Import upstream version 4.9.2
Debian Janitor
2 years ago
0 | environment: | |
1 | matrix: | |
2 | - job_name: java-tool-and-runtime | |
3 | - job_name: csharp-runtime | |
4 | job_depends_on: java-tool-and-runtime | |
5 | - job_name: dart-runtime | |
6 | job_depends_on: java-tool-and-runtime | |
7 | - job_name: go-runtime | |
8 | job_depends_on: java-tool-and-runtime | |
9 | - job_name: javascript-runtime | |
10 | job_depends_on: java-tool-and-runtime | |
11 | - job_name: php-runtime | |
12 | job_depends_on: java-tool-and-runtime | |
13 | - job_name: python2-runtime | |
14 | job_depends_on: java-tool-and-runtime | |
15 | - job_name: python3-runtime | |
16 | job_depends_on: java-tool-and-runtime | |
17 | ||
18 | matrix: | |
19 | fast_finish: false | |
20 | ||
21 | version: '4.9.1-SNAPSHOT+AppVeyor.{build}' | |
22 | cache: | |
23 | - '%USERPROFILE%\.m2' | |
24 | - '%USERPROFILE%\.nuget\packages -> **\project.json' | |
25 | image: Visual Studio 2019 | |
26 | # not using MSBuild | |
27 | build: off | |
28 | ||
29 | for: | |
30 | - matrix: | |
31 | only: | |
32 | - job_name: java-tool-and-runtime | |
33 | build_script: | |
34 | - mvn -q -DskipTests install --batch-mode | |
35 | test_script: | |
36 | - cd tool-testsuite | |
37 | - mvn -q test | |
38 | - cd ..\runtime-testsuite | |
39 | - mvn -q -Dtest=java.* test | |
40 | ||
41 | - matrix: | |
42 | only: | |
43 | - job_name: csharp-runtime | |
44 | build_script: | |
45 | - mvn -q -DskipTests install --batch-mode | |
46 | - dotnet build runtime/CSharp/src/Antlr4.csproj -c Release | |
47 | after_build: | |
48 | - dotnet pack runtime/CSharp/src/Antlr4.csproj -c Release | |
49 | test_script: | |
50 | - cd runtime-testsuite | |
51 | - mvn -q -Dtest=csharp.* test | |
52 | artifacts: | |
53 | - path: 'runtime\**\*.nupkg' | |
54 | name: NuGet | |
55 | ||
56 | - matrix: | |
57 | only: | |
58 | - job_name: dart-runtime | |
59 | install: | |
60 | - cinst -y dart-sdk --version=2.8.4 | |
61 | build_script: | |
62 | - mvn -q -DskipTests install --batch-mode | |
63 | test_script: | |
64 | - cd runtime-testsuite | |
65 | - mvn -q -Dtest=dart.* test -Dantlr-dart-dart="C:\tools\dart-sdk\bin\dart.exe" -Dantlr-dart-pub="C:\tools\dart-sdk\bin\pub.bat" -Dantlr-dart-dart2native="C:\tools\dart-sdk\bin\dart2native.bat" | |
66 | ||
67 | - matrix: | |
68 | only: | |
69 | - job_name: go-runtime | |
70 | build_script: | |
71 | - mvn -q -DskipTests install --batch-mode | |
72 | test_script: | |
73 | - cd runtime-testsuite | |
74 | - mvn -q -Dtest=go.* test | |
75 | ||
76 | - matrix: | |
77 | only: | |
78 | - job_name: javascript-runtime | |
79 | install: | |
80 | - cinst nodejs.install | |
81 | - node --version | |
82 | - npm --version | |
83 | - npm install -g yarn@v1.22.10 | |
84 | build_script: | |
85 | - cd runtime\JavaScript\ | |
86 | - npm install | |
87 | - npm link | |
88 | - cd ..\.. | |
89 | - mvn -q -DskipTests install --batch-mode | |
90 | test_script: | |
91 | - cd runtime\JavaScript\ | |
92 | - yarn test | |
93 | - cd ..\.. | |
94 | - cd runtime-testsuite | |
95 | - mvn -q -Dtest=javascript.* test -Dantlr-javascript-npm="C:\Program Files\nodejs\npm.cmd" -Dantlr-javascript-nodejs="C:\Program Files\nodejs\node.exe" | |
96 | ||
97 | - matrix: | |
98 | only: | |
99 | - job_name: php-runtime | |
100 | install: | |
101 | - git clone https://github.com/antlr/antlr-php-runtime.git | |
102 | - mv antlr-php-runtime runtime/PHP | |
103 | - cinst -y php --params "/InstallDir:C:\tools\php" | |
104 | - cinst -y composer | |
105 | build_script: | |
106 | - mvn -q -DskipTests install --batch-mode | |
107 | test_script: | |
108 | - cd runtime-testsuite | |
109 | - mvn -q -Dtest=php.* test -Dantlr-php-php="C:\tools\php\php.exe" | |
110 | ||
111 | - matrix: | |
112 | only: | |
113 | - job_name: python2-runtime | |
114 | build_script: | |
115 | - mvn -q -DskipTests install --batch-mode | |
116 | test_script: | |
117 | - cd runtime-testsuite | |
118 | - mvn -q -Dtest=python2.* test -Dantlr-python2-python="C:\Python27\python.exe" | |
119 | ||
120 | - matrix: | |
121 | only: | |
122 | - job_name: python3-runtime | |
123 | build_script: | |
124 | - mvn -q -DskipTests install --batch-mode | |
125 | test_script: | |
126 | - cd runtime-testsuite | |
127 | - mvn -q -Dtest=python3.* test -Dantlr-python3-python="C:\Python35\python.exe" |
0 | version: 2.1 | |
1 | ||
2 | jobs: | |
3 | test_tool_and_runtime_java: | |
4 | docker: | |
5 | - image: cimg/openjdk:8.0 | |
6 | steps: | |
7 | - checkout | |
8 | - run: | |
9 | name: build tool | |
10 | command: mvn -B -V -DskipTests=true -Dmaven.javadoc.skip=true install | |
11 | - run: | |
12 | name: test runtime | |
13 | command: | | |
14 | cd runtime-testsuite | |
15 | mvn -q -Dparallel=methods -DthreadCount=4 -Dtest=java.* test | |
16 | cd .. | |
17 | - run: | |
18 | name: test tool | |
19 | command: | | |
20 | cd tool-testsuite | |
21 | mvn -q -Dparallel=methods -DthreadCount=4 test | |
22 | cd .. | |
23 | test_runtime: | |
24 | parameters: | |
25 | test-group: | |
26 | description: The section | |
27 | type: string | |
28 | default: ALL | |
29 | target: | |
30 | description: The target | |
31 | type: string | |
32 | default: java | |
33 | docker: | |
34 | - image: cimg/openjdk:8.0 | |
35 | environment: | |
36 | TARGET: << parameters.target >> | |
37 | GROUP: << parameters.test-group >> | |
38 | steps: | |
39 | - checkout | |
40 | - run: | |
41 | name: Install << parameters.target >> pre-requisites | |
42 | command: | | |
43 | f=".circleci/scripts/install-linux-<< parameters.target >>.sh"; ! [ -x "$f" ] || "$f" | |
44 | - run: | |
45 | name: Build ANTLR4 tool | |
46 | command: mvn -B -V -DskipTests=true -Dmaven.javadoc.skip=true install | |
47 | - run: | |
48 | name: Test << parameters.target >> runtime | |
49 | command: | | |
50 | .circleci/scripts/run-tests-<< parameters.target >>.sh | |
51 | ||
52 | workflows: | |
53 | build: | |
54 | jobs: | |
55 | - test_tool_and_runtime_java | |
56 | - test_runtime: | |
57 | matrix: | |
58 | parameters: | |
59 | target: [ dart, go, python2, python3, javascript, php ] | |
60 | - test_runtime: | |
61 | matrix: | |
62 | parameters: | |
63 | # target: [ cpp, dotnet, swift ] | |
64 | target: [ cpp, dotnet ] | |
65 | test-group: [ LEXER, PARSER, RECURSION ] |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | echo "installing cpp SDK..." | |
5 | ||
6 | sudo apt-get update -y | |
7 | sudo apt-get install -y clang | |
8 | sudo apt-get install -y cmake | |
9 | sudo apt-get install -y pkg-config | |
10 | sudo apt-get install -y uuid-dev | |
11 | ||
12 | echo "done installing cpp SDK" | |
13 | ||
14 | clang++ --version | |
15 | cmake --version | |
16 | ||
17 | echo "building cpp runtime..." | |
18 | ||
19 | pushd "runtime/Cpp/" | |
20 | echo $PWD | |
21 | rc=0 | |
22 | if [ $rc == 0 ]; then | |
23 | cmake . -DCMAKE_BUILD_TYPE=release | |
24 | rc=$? | |
25 | fi | |
26 | if [ $rc == 0 ]; then | |
27 | make -j 8 | |
28 | rc=$? | |
29 | fi | |
30 | popd | |
31 | ||
32 | ||
33 | echo "done building cpp runtime" | |
34 |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | echo "installing dart SDK..." | |
5 | sudo apt-get update | |
6 | sudo apt-get install apt-transport-https | |
7 | sudo sh -c 'wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -' | |
8 | sudo sh -c 'wget -qO- https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list' | |
9 | sudo apt-get update | |
10 | sudo apt-get install dart=2.8.4-1 | |
11 | export PATH="$PATH:/usr/lib/dart/bin" | |
12 | echo "done installing dart SDK" | |
13 | sudo apt-get install -f |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | echo "installing .Net SDK..." | |
5 | wget https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb | |
6 | sudo dpkg -i packages-microsoft-prod.deb | |
7 | sudo apt-get update; \ | |
8 | sudo apt-get install -y apt-transport-https && \ | |
9 | sudo apt-get update && \ | |
10 | sudo apt-get install -y dotnet-sdk-3.1 | |
11 | export PATH=$PATH:~/.dotnet | |
12 | echo "done installing .Net SDK" | |
13 | ||
14 | # we need to build the runtime before test run, since we used "--no-dependencies" | |
15 | # when we call dotnet cli for restore and build, in order to speed up | |
16 | echo "building runtime..." | |
17 | dotnet build -c Release -f netstandard2.0 runtime/CSharp/src/Antlr4.csproj | |
18 | echo "done building runtime" |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | echo "installing go SDK..." | |
5 | sudo apt update | |
6 | sudo apt install golang-go | |
7 | go version | |
8 | echo "done installing go SDK"⏎ |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | # use v14 and check | |
5 | echo "installing nodejs..." | |
6 | curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - | |
7 | sudo apt-get install -y nodejs | |
8 | echo node version: $(node --version) | |
9 | echo "done installing nodejs" | |
10 | ||
11 | echo "installing yarn..." | |
12 | sudo npm install -g yarn@v1.22.10 | |
13 | echo "done installing yarn" | |
14 | ||
15 | echo "packaging javascript runtime..." | |
16 | pushd runtime/JavaScript | |
17 | sudo npm install | |
18 | sudo npm link | |
19 | popd | |
20 | echo "done packaging javascript runtime" |
0 | #!/bin/bash | |
1 | ||
2 | echo "before patching" | |
3 | ls -all /lib/x86_64-linux-gnu/ | grep libcurl | |
4 | ||
5 | # This would fix missing CURL_OPENSSL_3 | |
6 | # use a dedicated temp dir in the user space | |
7 | mkdir ~/libcurl3 | |
8 | cd ~/libcurl3 | |
9 | # fetch latest libcurl3 | |
10 | wget http://archive.ubuntu.com/ubuntu/pool/main/c/curl/libcurl3_7.47.0-1ubuntu2_amd64.deb | |
11 | # extract data.tar.xz | |
12 | ar x libcurl3* data.tar.xz | |
13 | # extract all from data.tar.xz | |
14 | tar xf data.tar.xz | |
15 | # copy libcurl.so.3 where required | |
16 | sudo cp -L ~/libcurl3/usr/lib/x86_64-linux-gnu/libcurl.so.4.4.0 /lib/x86_64-linux-gnu/libcurl.so.4.4.0 | |
17 | sudo ln -sf libcurl.so.4.4.0 /lib/x86_64-linux-gnu/libcurl.so.4 | |
18 | cd .. | |
19 | # drop dedicated temp dir | |
20 | sudo rm -rf ~/libcurl3 | |
21 | ||
22 | echo "after patching" | |
23 | ls -all /lib/x86_64-linux-gnu/ | grep libcurl |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF | |
5 | sudo apt-get update -qq | |
6 | ||
7 | sudo apt update | |
8 | ||
9 | sudo apt install php-all-dev | |
10 | php -v | |
11 | ||
12 | sudo apt install composer | |
13 | ||
14 | git clone https://github.com/antlr/antlr-php-runtime.git runtime/PHP | |
15 | composer install -d runtime/PHP | |
16 | ||
17 | mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V⏎ |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | echo "installing python 2..." | |
5 | sudo apt-get update -y | |
6 | sudo apt-get install python2 | |
7 | echo "done installing python 2" |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | echo "installing python 3..." | |
5 | sudo apt-get update -y | |
6 | sudo apt-get install python3 | |
7 | echo "done installing python 3" |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | echo "installing swift SDK..." | |
5 | ||
6 | .circleci/scripts/install-linux-libcurl3.sh | |
7 | ||
8 | # see https://tecadmin.net/install-swift-ubuntu-1604-xenial/ | |
9 | sudo apt-get update -y | |
10 | sudo apt-get install clang libicu-dev | |
11 | sudo apt-get install libpython2.7 libpython2.7-dev | |
12 | ||
13 | export SWIFT_VERSION=swift-5.3.2 | |
14 | echo "installing gpg key..." | |
15 | wget -q -O - https://swift.org/keys/all-keys.asc | sudo gpg --import - | |
16 | echo "downloading SDK gpg key..." | |
17 | SWIFT_SDK=https://swift.org/builds/$SWIFT_VERSION-release/ubuntu1604/$SWIFT_VERSION-RELEASE/$SWIFT_VERSION-RELEASE-ubuntu16.04.tar.gz | |
18 | echo $SWIFT_SDK | |
19 | wget -q $SWIFT_SDK | |
20 | sudo tar xzf $SWIFT_VERSION-RELEASE-ubuntu16.04.tar.gz | |
21 | mv $SWIFT_VERSION-RELEASE-ubuntu16.04 $PWD/swift | |
22 | ||
23 | export SWIFT_HOME=$PWD/swift/$SWIFT_VERSION-RELEASE-ubuntu16.04/usr/bin/ | |
24 | export PATH=$PWD/swift/usr/bin:$PATH | |
25 | ||
26 | # This would fix a know linker issue mentioned in: # https://bugs.swift.org/browse/SR-2299 | |
27 | sudo ln -sf ld.gold /usr/bin/ld | |
28 | # This would fix missing libtinfo.so.5 | |
29 | sudo apt install libncurses5 | |
30 | ||
31 | echo "done installing swift SDK..." | |
32 | ||
33 | # check swift | |
34 | swift --version | |
35 | swift build --version |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | pushd runtime-testsuite | |
5 | echo "running maven tests..." | |
6 | if [ $GROUP == "LEXER" ]; then | |
7 | mvn -q -Dgroups="org.antlr.v4.test.runtime.category.LexerTests" -Dtest=cpp.* test | |
8 | elif [ $GROUP == "PARSER" ]; then | |
9 | mvn -q -Dgroups="org.antlr.v4.test.runtime.category.ParserTests" -Dtest=cpp.* test | |
10 | elif [ $GROUP == "RECURSION" ]; then | |
11 | mvn -q -Dgroups="org.antlr.v4.test.runtime.category.LeftRecursionTests" -Dtest=cpp.* test | |
12 | else | |
13 | mvn -q -Dtest=cpp.* test | |
14 | fi | |
15 | popd | |
16 |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | dart --version | |
5 | ||
6 | pushd runtime-testsuite | |
7 | echo "running maven tests..." | |
8 | # mvn -q -Dparallel=classes -DthreadCount=4 -Dtest=dart.* test | |
9 | mvn -q -Dtest=dart.* test | |
10 | popd |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | pushd runtime-testsuite/ | |
5 | echo "running maven tests..." | |
6 | if [ $GROUP == "LEXER" ]; then | |
7 | mvn -q -Dgroups="org.antlr.v4.test.runtime.category.LexerTests" -Dtest=csharp.* test | |
8 | elif [ $GROUP == "PARSER" ]; then | |
9 | mvn -q -Dgroups="org.antlr.v4.test.runtime.category.ParserTests" -Dtest=csharp.* test | |
10 | elif [ $GROUP == "RECURSION" ]; then | |
11 | mvn -q -Dgroups="org.antlr.v4.test.runtime.category.LeftRecursionTests" -Dtest=csharp.* test | |
12 | else | |
13 | mvn -q -Dtest=csharp.* test | |
14 | fi | |
15 | popd |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | go version | |
5 | ||
6 | pushd runtime-testsuite | |
7 | echo "running maven tests..." | |
8 | mvn -q -Dparallel=methods -DthreadCount=4 -Dtest=go.* test | |
9 | popd⏎ |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | declare -i RESULT=0 | |
5 | ||
6 | pushd runtime/JavaScript | |
7 | ||
8 | echo "running jest tests..." | |
9 | yarn test | |
10 | RESULT+=$? | |
11 | ||
12 | popd | |
13 | ||
14 | pushd runtime-testsuite | |
15 | ||
16 | echo "running maven tests..." | |
17 | mvn -q -Dtest=javascript.* test | |
18 | RESULT+=$? | |
19 | ||
20 | popd | |
21 | ||
22 | exit $RESULT⏎ |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | php -v | |
5 | ||
6 | php_path=$(which php) | |
7 | pushd runtime-testsuite | |
8 | echo "running maven tests..." | |
9 | mvn -q -DPHP_PATH="${php_path}" -Dparallel=methods -DthreadCount=4 -Dtest=php.* test | |
10 | popd |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | python2 --version | |
5 | ||
6 | pushd runtime/Python2/tests | |
7 | echo "running native tests..." | |
8 | python2 run.py | |
9 | rc=$? | |
10 | if [ $rc != 0 ]; then | |
11 | echo "failed running native tests" | |
12 | fi | |
13 | popd | |
14 | ||
15 | if [ $rc == 0 ]; then | |
16 | pushd runtime-testsuite | |
17 | echo "running maven tests..." | |
18 | mvn -q -Dtest=python2.* test | |
19 | rc=$? | |
20 | popd | |
21 | fi | |
22 | ||
23 | # return $rc⏎ |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | python3 --version | |
5 | ||
6 | pushd runtime/Python3/tests | |
7 | echo "running native tests..." | |
8 | python3 run.py | |
9 | rc=$? | |
10 | if [ $rc != 0 ]; then | |
11 | echo "failed running native tests" | |
12 | fi | |
13 | popd | |
14 | ||
15 | if [ $rc == 0 ]; then | |
16 | pushd runtime-testsuite | |
17 | echo "running maven tests..." | |
18 | mvn -q -Dtest=python3.* test | |
19 | rc=$? | |
20 | popd | |
21 | fi | |
22 | ||
23 | # return $rc⏎ |
0 | #!/bin/bash | |
1 | ||
2 | set -euo pipefail | |
3 | ||
4 | pushd runtime/Swift | |
5 | echo "running native tests..." | |
6 | ./boot.py --test | |
7 | rc=$? | |
8 | if [ $rc != 0 ]; then | |
9 | echo "failed running native tests" | |
10 | fi | |
11 | popd | |
12 | ||
13 | if [ $rc == 0 ]; then | |
14 | pushd runtime-testsuite | |
15 | echo "running maven tests..." | |
16 | if [ $GROUP == "LEXER" ]; then | |
17 | mvn -q -Dgroups="org.antlr.v4.test.runtime.category.LexerTests" -Dtest=swift.* test | |
18 | elif [ $GROUP == "PARSER" ]; then | |
19 | mvn -q -Dgroups="org.antlr.v4.test.runtime.category.ParserTests" -Dtest=swift.* test | |
20 | elif [ $GROUP == "RECURSION" ]; then | |
21 | mvn -q -Dgroups="org.antlr.v4.test.runtime.category.LeftRecursionTests" -Dtest=swift.* test | |
22 | else | |
23 | mvn -q -Dtest=swift.* test | |
24 | fi | |
25 | popd | |
26 | fi |
0 | 0 | # ANTLR v4 |
1 | 1 | |
2 | [![Build Travis-CI Status](https://travis-ci.org/antlr/antlr4.svg?branch=master)](https://travis-ci.org/antlr/antlr4) [![Build AppVeyor Status](https://ci.appveyor.com/api/projects/status/5acpbx1pg7bhgh8v/branch/master?svg=true)](https://ci.appveyor.com/project/parrt/antlr4) [![Java 7+](https://img.shields.io/badge/java-7+-4c7e9f.svg)](http://java.oracle.com) [![License](https://img.shields.io/badge/license-BSD-blue.svg)](https://raw.githubusercontent.com/antlr/antlr4/master/LICENSE.txt) | |
2 | [![Java 7+](https://img.shields.io/badge/java-7+-4c7e9f.svg)](http://java.oracle.com) | |
3 | [![License](https://img.shields.io/badge/license-BSD-blue.svg)](https://raw.githubusercontent.com/antlr/antlr4/master/LICENSE.txt) | |
4 | ||
5 | **Build status** | |
6 | ||
7 | [![Github CI Build Status (MacOSX)](https://img.shields.io/github/workflow/status/antlr/antlr4/MacOSX?label=MacOSX)](https://github.com/antlr/antlr4/actions) | |
8 | [![AppVeyor CI Build Status (Windows)](https://img.shields.io/appveyor/build/parrt/antlr4?label=Windows)](https://ci.appveyor.com/project/parrt/antlr4) | |
9 | [![Circle CI Build Status (Linux)](https://img.shields.io/circleci/build/gh/antlr/antlr4/master?label=Linux)](https://app.circleci.com/pipelines/github/antlr/antlr4) | |
10 | [![Travis-CI Build Status (Swift-Linux)](https://img.shields.io/travis/antlr/antlr4.svg?label=Linux-Swift&branch=master)](https://travis-ci.com/github/antlr/antlr4) | |
3 | 11 | |
4 | 12 | **ANTLR** (ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files. It's widely used to build languages, tools, and frameworks. From a grammar, ANTLR generates a parser that can build parse trees and also generates a listener interface (or visitor) that makes it easy to respond to the recognition of phrases of interest. |
5 | 13 | |
12 | 20 | * [Terence Parr](http://www.cs.usfca.edu/~parrt/), parrt@cs.usfca.edu |
13 | 21 | ANTLR project lead and supreme dictator for life |
14 | 22 | [University of San Francisco](http://www.usfca.edu/) |
15 | * [Sam Harwell](http://tunnelvisionlabs.com/) (Tool co-author, Java and C# target) | |
16 | * Eric Vergnaud (Javascript, Python2, Python3 targets and significant work on C# target) | |
23 | * [Sam Harwell](http://tunnelvisionlabs.com/) (Tool co-author, Java and original C# target) | |
24 | * [Eric Vergnaud](https://github.com/ericvergnaud) (Javascript, Python2, Python3 targets and maintenance of C# target) | |
17 | 25 | * [Peter Boyer](https://github.com/pboyer) (Go target) |
18 | 26 | * [Mike Lischke](http://www.soft-gems.net/) (C++ completed target) |
19 | 27 | * Dan McLaughlin (C++ initial target) |
21 | 29 | * [Janyou](https://github.com/janyou) (Swift target) |
22 | 30 | * [Ewan Mellor](https://github.com/ewanmellor), [Hanzhou Shi](https://github.com/hanjoes) (Swift target merging) |
23 | 31 | * [Ben Hamilton](https://github.com/bhamiltoncx) (Full Unicode support in serialized ATN and all languages' runtimes for code points > U+FFFF) |
32 | * [Marcos Passos](https://github.com/marcospassos) (PHP target) | |
33 | * [Lingyu Li](https://github.com/lingyv-li) (Dart target) | |
24 | 34 | |
25 | 35 | ## Useful information |
26 | 36 | |
29 | 39 | * [Official site](http://www.antlr.org/) |
30 | 40 | * [Documentation](https://github.com/antlr/antlr4/blob/master/doc/index.md) |
31 | 41 | * [FAQ](https://github.com/antlr/antlr4/blob/master/doc/faq/index.md) |
32 | * [ANTLR code generation targets](https://github.com/antlr/antlr4/blob/master/doc/targets.md)<br>(Currently: Java, C#, Python2|3, JavaScript, Go, C++, Swift) | |
42 | * [ANTLR code generation targets](https://github.com/antlr/antlr4/blob/master/doc/targets.md)<br>(Currently: Java, C#, Python2|3, JavaScript, Go, C++, Swift, Dart, PHP) | |
33 | 43 | * [Java API](http://www.antlr.org/api/Java/index.html) |
34 | 44 | * [ANTLR v3](http://www.antlr3.org/) |
35 | 45 | * [v3 to v4 Migration, differences](https://github.com/antlr/antlr4/blob/master/doc/faq/general.md) |
7 | 7 | <parent> |
8 | 8 | <groupId>org.antlr</groupId> |
9 | 9 | <artifactId>antlr4-master</artifactId> |
10 | <version>4.7.2</version> | |
10 | <version>4.9.2</version> | |
11 | 11 | </parent> |
12 | 12 | <artifactId>antlr4-maven-plugin</artifactId> |
13 | 13 | <packaging>maven-plugin</packaging> |
63 | 63 | <dependency> |
64 | 64 | <groupId>junit</groupId> |
65 | 65 | <artifactId>junit</artifactId> |
66 | <version>4.12</version> | |
66 | <version>4.13.1</version> | |
67 | 67 | <scope>test</scope> |
68 | 68 | </dependency> |
69 | 69 | <dependency> |
119 | 119 | <plugin> |
120 | 120 | <groupId>org.apache.maven.plugins</groupId> |
121 | 121 | <artifactId>maven-plugin-plugin</artifactId> |
122 | <version>3.3</version> | |
122 | <version>3.6.0</version> | |
123 | 123 | <configuration> |
124 | 124 | <!-- see http://jira.codehaus.org/browse/MNG-5346 --> |
125 | 125 | <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound> |
54 | 54 | name = "antlr4", |
55 | 55 | defaultPhase = LifecyclePhase.GENERATE_SOURCES, |
56 | 56 | requiresDependencyResolution = ResolutionScope.COMPILE, |
57 | requiresProject = true) | |
57 | requiresProject = true, threadSafe = true) | |
58 | 58 | public class Antlr4Mojo extends AbstractMojo { |
59 | 59 | |
60 | 60 | // First, let's deal with the options that the ANTLR tool itself |
16 | 16 | <dependency> |
17 | 17 | <groupId>junit</groupId> |
18 | 18 | <artifactId>junit</artifactId> |
19 | <version>4.11</version> | |
19 | <version>4.13.1</version> | |
20 | 20 | <scope>test</scope> |
21 | 21 | </dependency> |
22 | 22 | </dependencies> |
16 | 16 | <dependency> |
17 | 17 | <groupId>junit</groupId> |
18 | 18 | <artifactId>junit</artifactId> |
19 | <version>4.11</version> | |
19 | <version>4.13.1</version> | |
20 | 20 | <scope>test</scope> |
21 | 21 | </dependency> |
22 | 22 | </dependencies> |
16 | 16 | <dependency> |
17 | 17 | <groupId>junit</groupId> |
18 | 18 | <artifactId>junit</artifactId> |
19 | <version>4.11</version> | |
19 | <version>4.13.1</version> | |
20 | 20 | <scope>test</scope> |
21 | 21 | </dependency> |
22 | 22 | </dependencies> |
16 | 16 | <dependency> |
17 | 17 | <groupId>junit</groupId> |
18 | 18 | <artifactId>junit</artifactId> |
19 | <version>4.11</version> | |
19 | <version>4.13.1</version> | |
20 | 20 | <scope>test</scope> |
21 | 21 | </dependency> |
22 | 22 | </dependencies> |
0 | version: '4.7.1-SNAPSHOT+AppVeyor.{build}' | |
1 | cache: | |
2 | - '%USERPROFILE%\.m2' | |
3 | - '%USERPROFILE%\.nuget\packages -> **\project.json' | |
4 | image: Visual Studio 2017 | |
5 | build: off | |
6 | build_script: | |
7 | - mvn -DskipTests install --batch-mode | |
8 | - msbuild /target:restore /target:rebuild /property:Configuration=Release /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /verbosity:detailed runtime/CSharp/runtime/CSharp/Antlr4.dotnet.sln | |
9 | - msbuild ./runtime-testsuite/target/classes/CSharp/runtime/CSharp/Antlr4.vs2013.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /verbosity:detailed | |
10 | after_build: | |
11 | - msbuild /target:pack /property:Configuration=Release /verbosity:detailed runtime/CSharp/runtime/CSharp/Antlr4.dotnet.sln | |
12 | test_script: | |
13 | - mvn install -Dantlr-python2-python="C:\Python27\python.exe" -Dantlr-python3-python="C:\Python35\python.exe" -Dantlr-javascript-nodejs="C:\Program Files (x86)\nodejs\node.exe" --batch-mode | |
14 | artifacts: | |
15 | - path: 'runtime\**\*.nupkg' | |
16 | name: NuGet⏎ |
0 | 0 | ANTLR Project Contributors Certification of Origin and Rights |
1 | ||
2 | NOTE: This tool is mature and Terence is mostly occupied elsewhere. We | |
3 | can't accept any changes that could have widespread effects on thousands | |
4 | of existing projects. Sorry! | |
1 | 5 | |
2 | 6 | All contributors to ANTLR v4 must formally agree to abide by this |
3 | 7 | certificate of origin by signing on the bottom with their github |
202 | 206 | 2018/06/16, EternalPhane, Zongyuan Zuo, eternalphane@gmail.com |
203 | 207 | 2018/07/03, jgoppert, James Goppert, james.goppert@gmail.com |
204 | 208 | 2018/07/27, Maksim Novikov, mnovikov.work@gmail.com |
209 | 2018/08/03, ENDOH takanao, djmchl@gmail.com | |
210 | 2018/10/08, xsIceman, Andreas Skaar, andreas.skaar@gmail.com | |
211 | 2018/10/18, edirgarcia, Edir García Lazo, edirgl@hotmail.com | |
205 | 212 | 2018/07/31, Lucas Henrqiue, lucashenrique580@gmail.com |
206 | 213 | 2018/08/03, ENDOH takanao, djmchl@gmail.com |
207 | 214 | 2018/10/29, chrisaycock, Christopher Aycock, chris[at]chrisaycock[dot]com |
208 | 215 | 2018/11/12, vinoski, Steve Vinoski, vinoski@ieee.org |
209 | 216 | 2018/11/14, nxtstep, Adriaan (Arjan) Duz, codewithadriaan[et]gmail[dot]com |
210 | 217 | 2018/11/15, amykyta3, Alex Mykyta, amykyta3@users.noreply.github.com |
211 | 2018/11/29, hannemann-tamas, Ralf Hannemann-Tamas, ralf.ht@gmail.com⏎ | |
218 | 2018/11/29, hannemann-tamas, Ralf Hannemann-Tamas, ralf.ht@gmail.com | |
219 | 2018/12/20, WalterCouto, Walter Couto, WalterCouto@users.noreply.github.com | |
220 | 2018/12/23, youkaichao, Kaichao You, youkaichao@gmail.com | |
221 | 2019/01/01, khoroshilov, Alexey Khoroshilov, khoroshilov@ispras.ru | |
222 | 2019/01/02, wkhemir, Wail Khemir, khemirwail@gmail.com | |
223 | 2019/01/16, kuegi, Markus Zancolo, markus.zancolo@roomle.com | |
224 | 2019/02/06, ralucado, Cristina Raluca Vijulie, ralucris.v[at]gmail[dot]com | |
225 | 2019/02/23, gedimitr, Gerasimos Dimitriadis, gedimitr@gmail.com | |
226 | 2019/03/13, base698, Justin Thomas, justin.thomas1@gmail.com | |
227 | 2019/03/18, carlodri, Carlo Dri, carlo.dri@gmail.com | |
228 | 2019/05/02, askingalot, Andy Collins, askingalot@gmail.com | |
229 | 2019/05/13, mapio, Massimo Santini, massimo.santini@gmail.com | |
230 | 2019/07/11, olowo726, Olof Wolgast, olof@baah.se | |
231 | 2019/07/16, abhijithneilabraham, Abhijith Neil Abraham, abhijithneilabrahampk@gmail.com | |
232 | 2019/07/26, Braavos96, Eric Hettiaratchi, erichettiaratchi@gmail.com | |
233 | 2019/08/02, thron7, Thomas Herchenroeder, thron7[at]users[dot]sourceforge[dot]net | |
234 | 2019/08/12, easonlin404, Eason Lin, easonlin404@gmail.com | |
235 | 2019/08/23, akaJes, Oleksandr Mamchyts, akaJes@gmail.com | |
236 | 2019/08/27, wurzelpeter, Markus Franke, markus[hyphen]franke[at]web[dot]de | |
237 | 2019/09/10, ImanHosseini, Iman Hosseini, hosseini.iman@yahoo.com | |
238 | 2019/09/03, João Henrique, johnnyonflame@hotmail.com | |
239 | 2019/09/10, neko1235, Ihar Mokharau, igor.mohorev@gmail.com | |
240 | 2019/09/10, yar3333, Yaroslav Sivakov, yar3333@gmail.com | |
241 | 2019/09/10, marcospassos, Marcos Passos, marcospassos.com@gmail.com | |
242 | 2019/09/10, amorimjuliana, Juliana Amorim, juu.amorim@gmail.com | |
243 | 2019/09/15, sullis, Sean Sullivan, github@seansullivan.com | |
244 | 2019/09/17, kaz, Kazuki Sawada, kazuki@6715.jp | |
245 | 2019/09/28, lmy269, Mingyang Liu, lmy040758@gmail.com | |
246 | 2019/10/29, tehbone, Tabari Alexander, tehbone@gmail.com | |
247 | 2019/10/31, a-square, Alexei Averchenko, lex.aver@gmail.com | |
248 | 2019/11/05, listba, Ben List, ben.list89@gmail.com | |
249 | 2019/11/11, foxeverl, Liu Xinfeng, liuxf1986[at]gmail[dot]com | |
250 | 2019/11/17, felixn, Felix Nieuwenhuizhen, felix@tdlrali.com | |
251 | 2019/11/18, mlilback, Mark Lilback, mark@lilback.com | |
252 | 2020/01/19, lingyv-li, Lingyu Li, lingyv.li@gmail.com | |
253 | 2020/02/02, carocad, Camilo Roca, carocad@unal.edu.co | |
254 | 2020/02/10, julibert, Julián Bermúdez Ortega, julibert.dev@gmail.com | |
255 | 2020/02/17, quantumsheep, Nathanael Demacon, nathanael.dmc@outlook.fr | |
256 | 2020/02/21, StochasticTinkr, Daniel Pitts, github@coloraura.com | |
257 | 2020/03/17, XsongyangX, Song Yang, songyang1218@gmail.com | |
258 | 2020/04/07, deniskyashif, Denis Kyashif, denis.kyashif@gmail.com | |
259 | 2020/04/08, lwehmeier, Leon Wehmeier, wehmeier@st.ovgu.de | |
260 | 2020/04/10, agrabski, Adam Grabski, adam.gr@outlook.com | |
261 | 2020/04/23, martinvw, Martin van Wingerden, martin@martinvw.nl | |
262 | 2020/04/30, TristonianJones, Tristan Swadell, tswadell@google.com | |
263 | 2020/05/06, iammosespaulr, Moses Paul R, iammosespaulr@gmail.com | |
264 | 2020/05/10, gomerser, Erik Gomersbach, gomerser@gomersba.ch | |
265 | 2020/05/22, keywan-ghadami-oxid, Keywan Ghadami, keywan.ghadami@oxid-esales.com | |
266 | 2020/05/25, graknol, Sindre van der Linden, graknol@gmail.com | |
267 | 2020/05/31, d-markey, David Markey, dmarkey@free.fr | |
268 | 2020/06/02, cohomology, Kilian Kilger, kkilger AT gmail.com | |
269 | 2020/06/04, IohannRabeson, Iohann Rabeson, iotaka6@gmail.com | |
270 | 2020/06/04, sigmasoldi3r, Pablo Blanco, pablobc.1995@gmail.com | |
271 | 2020/07/01, sha-N, Shan M Mathews, admin@bluestarqatar.com | |
272 | 2020/08/22, stevenjohnstone, Steven Johnstone, steven.james.johnstone@gmail.com | |
273 | 2020/09/06, ArthurSonzogni, Sonzogni Arthur, arthursonzogni@gmail.com | |
274 | 2020/09/10, Khailian, Arunav Sanyal, arunav.sanyal91@gmail.com | |
275 | 2020/09/12, Clcanny, Charles Ruan, a837940593@gmail.com | |
276 | 2020/09/15, rmcgregor1990, Robert McGregor, rmcgregor1990@gmail.com | |
277 | 2020/09/16, trenki2, Markus Trenkwalder, trenki2[at]gmx[dot]net | |
278 | 2020/10/08, Marti2203, Martin Mirchev, mirchevmartin2203@gmail.com | |
279 | 2020/10/16, adarshbhat, Adarsh Bhat, adarshbhat@users.noreply.github.com | |
280 | 2020/10/20, adamwojs, Adam Wójs, adam[at]wojs.pl | |
281 | 2020/10/24, cliid, Jiwu Jang, jiwujang@naver.com | |
282 | 2020/11/05, MichelHartmann, Michel Hartmann, MichelHartmann@users.noreply.github.com | |
283 | 2020/11/26, mr-c, Michael R. Crusoe, 1330696+mr-c@users.noreply.github.com | |
284 | 2020/12/01, maxence-lefebvre, Maxence Lefebvre, maxence-lefebvre@users.noreply.github.com | |
285 | 2020/12/03, electrum, David Phillips, david@acz.org | |
286 | 2021/01/25, l215884529, Qiheng Liu, 13607681+l215884529@users.noreply.github.com | |
287 | 2021/02/02, tsotnikov, Taras Sotnikov, taras.sotnikov@gmail.com | |
288 | 2021/02/21, namasikanam, Xingyu Xie, namasikanam@gmail.com | |
289 | 2021/02/27, khmarbaise, Karl Heinz Marbaise, github@soebes.com | |
290 | 2021/03/02, hackeris | |
291 | 2021/03/03, xTachyon, Damian Andrei, xTachyon@users.noreply.github.com |
83 | 83 | returnStat : 'return' e=expr {System.out.println("matched "+e.text);} ; |
84 | 84 | ``` |
85 | 85 | |
86 | You can also use `$ followed by the name of the attribute to access the value associated with the currently executing rule. For example, `$start` is the starting token of the current rule. | |
86 | You can also use `$` followed by the name of the attribute to access the value associated with the currently executing rule. For example, `$start` is the starting token of the current rule. | |
87 | 87 | |
88 | 88 | ``` |
89 | 89 | returnStat : 'return' expr {System.out.println("first token "+$start.getText());} ; |
56 | 56 | Now, make sure C# runtime is built and installed locally. |
57 | 57 | |
58 | 58 | ```bash |
59 | cd ~/antlr/code/antlr4/runtime/CSharp/runtime/CSharp | |
60 | # kill previous ones manually as "xbuild /t:Clean" didn't seem to do it | |
61 | find . -name '*.dll' -exec rm {} \; | |
62 | # build | |
63 | xbuild /p:Configuration=Release Antlr4.Runtime/Antlr4.Runtime.mono.csproj | |
59 | cd ~/antlr/code/antlr4/runtime/CSharp/src | |
60 | rm -rf `find . -name '{obj,bin}'` | |
61 | dotnet build -c Release runtime/CSharp/src/Antlr4.csproj | |
64 | 62 | ``` |
65 | 63 | |
66 | 64 | C++ test rig automatically builds C++ runtime during tests. Others don't need a prebuilt lib. |
22 | 22 | Resolving deltas: 100% (32970/32970), done. |
23 | 23 | Checking connectivity... done. |
24 | 24 | Checking out files: 100% (1427/1427), done. |
25 | ``` | |
26 | ||
27 | # Check your environment | |
28 | ||
29 | If you are starting from a clean, minimum Ubuntu OS, check your environment. | |
30 | ||
31 | ||
32 | ```bash | |
33 | $ sudo apt-get update | |
34 | $ # Get Java | |
35 | $ java > /dev/null 2>&1 | |
36 | $ if [[ "$?" != "0" ]]; then sudo apt install -y openjdk-11-jre-headless; fi | |
37 | $ # Get Mvn | |
38 | $ mvn > /dev/null 2>&1 | |
39 | $ if [[ "$?" != "0" ]]; then sudo apt install -y maven; fi | |
40 | ||
25 | 41 | ``` |
26 | 42 | |
27 | 43 | # Compile |
13 | 13 | |
14 | 14 | ## Case-insensitive grammars |
15 | 15 | |
16 | As a prime example of a grammar that specifically describes case insensitive keywords, see the | |
16 | As a prime example of a grammar that specifically describes case insensitive keywords, see the | |
17 | 17 | [SQLite grammar](https://github.com/antlr/grammars-v4/blob/master/sqlite/SQLite.g4). To match a case insensitive keyword, there are rules such as |
18 | 18 | |
19 | 19 | ``` |
71 | 71 | |
72 | 72 | Here are implementations of `CaseChangingCharStream` in various target languages: |
73 | 73 | |
74 | * [Java](https://github.com/parrt/antlr4/blob/case-insensitivity-doc/doc/resources/CaseChangingCharStream.java) | |
75 | * [JavaScript](https://github.com/parrt/antlr4/blob/case-insensitivity-doc/doc/resources/CaseInsensitiveInputStream.js) | |
76 | * [Go](https://github.com/parrt/antlr4/blob/case-insensitivity-doc/doc/resources/case_changing_stream.go) | |
77 | * [C#](https://github.com/parrt/antlr4/blob/case-insensitivity-doc/doc/resources/CaseChangingCharStream.cs)⏎ | |
74 | * [C#](https://github.com/antlr/antlr4/blob/master/doc/resources/CaseChangingCharStream.cs) | |
75 | * [Go](https://github.com/antlr/antlr4/blob/master/doc/resources/case_changing_stream.go) | |
76 | * [Java](https://github.com/antlr/antlr4/blob/master/doc/resources/CaseChangingCharStream.java) | |
77 | * [JavaScript](https://github.com/antlr/antlr4/blob/master/doc/resources/CaseChangingStream.js) | |
78 | * [Python2/3](https://github.com/antlr/antlr4/blob/master/doc/resources/CaseChangingStream.py) |
0 | 0 | # C++ |
1 | 1 | |
2 | The C++ target supports all platforms that can either run MS Visual Studio 2013 (or newer), XCode 7 (or newer) or CMake (C++11 required). All build tools can either create static or dynamic libraries, both as 64bit or 32bit arch. Additionally, XCode can create an iOS library. Also see [Antlr4 for C++ with CMake: A practical example](http://blorente.me//Antlr-,-C++-and-CMake-Wait-what.html). | |
2 | The C++ target supports all platforms that can either run MS Visual Studio 2013 (or newer), XCode 7 (or newer) or CMake (C++11 required). All build tools can either create static or dynamic libraries, both as 64bit or 32bit arch. Additionally, XCode can create an iOS library. Also see [Antlr4 for C++ with CMake: A practical example](http://blorente.me/beyond-the-loop/Antlr-cpp-cmake/). | |
3 | 3 | |
4 | 4 | ## How to create a C++ lexer or parser? |
5 | 5 | This is pretty much the same as creating a Java lexer or parser, except you need to specify the language target, for example: |
44 | 44 | #include "MyGrammarParser.h" |
45 | 45 | #include "MyGrammarBaseListener.h" |
46 | 46 | |
47 | using namespace org::antlr::v4::runtime; | |
47 | using namespace antlr4; | |
48 | 48 | |
49 | 49 | class TreeShapeListener : public MyGrammarBaseListener { |
50 | 50 | public: |
64 | 64 | |
65 | 65 | tree::ParseTree *tree = parser.key(); |
66 | 66 | TreeShapeListener listener; |
67 | tree::ParseTreeWalker::DEFAULT->walk(&listener, tree); | |
67 | tree::ParseTreeWalker::DEFAULT.walk(&listener, tree); | |
68 | 68 | |
69 | 69 | return 0; |
70 | 70 | } |
73 | 73 | |
74 | 74 | This example assumes your grammar contains a parser rule named `key` for which the enterKey function was generated. |
75 | 75 | |
76 | ## Specialities of this ANTLR target | |
76 | ## Special cases for this ANTLR target | |
77 | 77 | |
78 | 78 | There are a couple of things that only the C++ ANTLR target has to deal with. They are described here. |
79 | 79 |
9 | 9 | 1. Create *X*.stg in directory tool/resources/org/antlr/v4/tool/templates/codegen/*X*/*X*.stg. This is a [StringTemplate](http://www.stringtemplate.org/) group file (`.stg`) that tells ANTLR how to express all of the parsing elements needed to generate code. You will see templates called `ParserFile`, `Parser`, `Lexer`, `CodeBlockForAlt`, `AltBlock`, etc... Each of these must be described how to build the indicated chunk of code. Your best bet is to find the closest existing target, copy that template file, and tweak to suit. |
10 | 10 | 1. Create a runtime library to support the parsers generated by ANTLR. Under directory runtime/*X*, you are in complete control of the directory structure as dictated by common usage of that target language. For example, Java has: `runtime/Java/lib` and `runtime/Java/src` directories. Under `src`, you will find a directory structure for package `org.antlr.v4.runtime` and below. |
11 | 11 | 1. Create a template file for runtime tests. All you have to do is provide a few templates that indicate how to print values and declare variables. Our runtime test mechanism in dir `runtime-testsuite` will automatically generate code using these templates for each target and check the test results. It needs to know how to define various class fields, compare members and so on. You must create a *X*.test.stg file underneath [runtime-testsuite/resources/org/antlr/v4/test/runtime](https://github.com/antlr/antlr4/tree/master/runtime-testsuite/resources/org/antlr/v4/test/runtime). Again, your best bet is to copy the templates from the closest language to your target and tweak it to suit. |
12 | 1. Create test files under [/runtime-testsuite/test/org/antlr/v4/test/runtime](https://github.com/antlr/antlr4/tree/master/runtime-testsuite/test/org/antlr/v4/test/runtime). They will load defined test cases in each test descriptor. Also add the `/runtime-testsuite/test/org/antlr/v4/test/runtime/X/BaseXTest.java` which defines how test cases will execute and output. | |
13 | 1. Create/edit shell scripts in [/.travis](https://github.com/antlr/antlr4/blob/master/.travis) and [/appveyor.yml](https://github.com/antlr/antlr4/blob/master/appveyor.yml) to run tests in CI pipelines. | |
12 | 14 | |
13 | 15 | ## Getting started |
14 | 16 |
29 | 29 | |
30 | 30 | Now a fully functioning code might look like the following for start rule `StartRule`: |
31 | 31 | |
32 | ``` | |
32 | ```csharp | |
33 | 33 | using Antlr4.Runtime; |
34 | 34 | using Antlr4.Runtime.Tree; |
35 | 35 | |
36 | 36 | public void MyParseMethod() { |
37 | 37 | String input = "your text to parse here"; |
38 | ICharStream stream = CharStreams.fromstring(input); | |
38 | ICharStream stream = CharStreams.fromString(input); | |
39 | 39 | ITokenSource lexer = new MyGrammarLexer(stream); |
40 | 40 | ITokenStream tokens = new CommonTokenStream(lexer); |
41 | 41 | MyGrammarParser parser = new MyGrammarParser(tokens); |
58 | 58 | |
59 | 59 | The antlr4 tool will have generated the following listener (only partial code shown here): |
60 | 60 | |
61 | ``` | |
61 | ```csharp | |
62 | 62 | interface IMyGrammarParserListener : IParseTreeListener { |
63 | 63 | void EnterKey (MyGrammarParser.KeyContext context); |
64 | 64 | void ExitKey (MyGrammarParser.KeyContext context); |
69 | 69 | |
70 | 70 | In order to provide custom behavior, you might want to create the following class: |
71 | 71 | |
72 | ``` | |
72 | ```csharp | |
73 | 73 | class KeyPrinter : MyGrammarBaseListener { |
74 | 74 | // override default listener behavior |
75 | 75 | void ExitKey (MyGrammarParser.KeyContext context) { |
81 | 81 | In order to execute this listener, you would simply add the following lines to the above code: |
82 | 82 | |
83 | 83 | |
84 | ``` | |
84 | ```csharp | |
85 | 85 | ... |
86 | 86 | IParseTree tree = parser.StartRule() - only repeated here for reference |
87 | 87 | KeyPrinter printer = new KeyPrinter(); |
88 | ParseTreeWalker.DEFAULT.walk(printer, tree); | |
88 | ParseTreeWalker.Default.Walk(printer, tree); | |
89 | 89 | ``` |
90 | 90 | |
91 | 91 | Further information can be found from The Definitive ANTLR Reference book. |
0 | # ANTLR4 Runtime for Dart | |
1 | ||
2 | Notice: Dart target may generate code incompatible with Dart 2.9 sound null safety. Please set the minimum SDK constraint to 2.8.4 or lower if such violation is found. Contributions are welcomed. | |
3 | ||
4 | ### First steps | |
5 | ||
6 | #### 1. Install ANTLR4 | |
7 | ||
8 | [The getting started guide](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md) | |
9 | should get you started. | |
10 | ||
11 | #### 2. Install the Dart ANTLR runtime | |
12 | ||
13 | Each target language for ANTLR has a runtime package for running parser | |
14 | generated by ANTLR4. The runtime provides a common set of tools for using your parser. | |
15 | ||
16 | Install the runtime with the same version as the main ANTLR tool: | |
17 | ||
18 | Add this to your package's pubspec.yaml file: | |
19 | ```yaml | |
20 | ... | |
21 | dependencies: | |
22 | antlr4: <ANTLR version> | |
23 | ... | |
24 | ``` | |
25 | ||
26 | #### 3. Generate your parser | |
27 | ||
28 | You use the ANTLR4 "tool" to generate a parser. These will reference the ANTLR | |
29 | runtime, installed above. | |
30 | ||
31 | Suppose you're using a UNIX system and have set up an alias for the ANTLR4 tool | |
32 | as described in [the getting started guide](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md). | |
33 | To generate your Dart parser, run the following command: | |
34 | ||
35 | ```shell script | |
36 | antlr4 -Dlanguage=Dart MyGrammar.g4 | |
37 | ``` | |
38 | ||
39 | For a full list of antlr4 tool options, please visit the | |
40 | [tool documentation page](https://github.com/antlr/antlr4/blob/master/doc/tool-options.md). | |
41 | ||
42 | ### Complete example | |
43 | ||
44 | Suppose you're using the JSON grammar from https://github.com/antlr/grammars-v4/tree/master/json. | |
45 | ||
46 | Then, invoke `antlr4 -Dlanguage=Dart JSON.g4`. The result of this is a | |
47 | collection of `.dart` including: | |
48 | ||
49 | * JsonLexer.dart | |
50 | * JsonParser.dart | |
51 | * JsonBaseListener.dart | |
52 | * JsonListener.dart (if you have not activated the -no-listener option) | |
53 | * JsonVisitor.dart (if you have activated the -visitor option) | |
54 | ||
55 | We'll write a small main func to call the generated parser/lexer | |
56 | (assuming they are separate). This one writes out the encountered | |
57 | `ParseTreeContext`'s: | |
58 | ||
59 | ```dart | |
60 | import 'package:antlr4/antlr4.dart'; | |
61 | import 'package:my_project/JSONParser.dart'; | |
62 | import 'package:my_project/JSONLexer.dart'; | |
63 | ||
64 | class TreeShapeListener implements ParseTreeListener { | |
65 | @override | |
66 | void enterEveryRule(ParserRuleContext ctx) { | |
67 | print(ctx.text); | |
68 | } | |
69 | ||
70 | @override | |
71 | void exitEveryRule(ParserRuleContext node) { | |
72 | } | |
73 | ||
74 | @override | |
75 | void visitErrorNode(ErrorNode node) { | |
76 | } | |
77 | ||
78 | @override | |
79 | void visitTerminal(TerminalNode node) { | |
80 | } | |
81 | } | |
82 | ||
83 | void main(List<String> args) async { | |
84 | JSONLexer.checkVersion(); | |
85 | JSONParser.checkVersion(); | |
86 | final input = await InputStream.fromPath(args[0]); | |
87 | final lexer = JSONLexer(input); | |
88 | final tokens = CommonTokenStream(lexer); | |
89 | final parser = JSONParser(tokens); | |
90 | parser.addErrorListener(DiagnosticErrorListener()); | |
91 | parser.buildParseTree = true; | |
92 | final tree = parser.json(); | |
93 | ParseTreeWalker.DEFAULT.walk(TreeShapeListener(), tree); | |
94 | } | |
95 | ``` | |
96 | ||
97 | Create a `example.json` file: | |
98 | ```json | |
99 | {"a":1} | |
100 | ``` | |
101 | ||
102 | Parse the input file: | |
103 | ||
104 | ```shell script | |
105 | dart bin/main.dart example.json | |
106 | ``` | |
107 | ||
108 | The expected output is: | |
109 | ||
110 | ``` | |
111 | {"a":1} | |
112 | {"a":1} | |
113 | {"a":1} | |
114 | "a":1 | |
115 | 1 | |
116 | ```⏎ |
37 | 37 | |
38 | 38 | ## Translation |
39 | 39 | |
40 | * [ASTs vs parse trees](parse-trees.md) | |
41 | * [Decoupling input walking from output generation](parse-trees.md) | |
40 | * [ASTs vs parse trees](translation.md) | |
41 | * [Decoupling input walking from output generation](translation.md) | |
42 | 42 | |
43 | 43 | ## Actions and semantic predicates |
44 | 44 |
49 | 49 | |
50 | 50 | ### XPath |
51 | 51 | |
52 | XPath works great when you need to find specific nodes, possibly in certain contexts. The context is limited to the parents on the way to the root of the tree. For example, if you want to find all ID nodes, use path `//ID`. If you want all variable declarations, you might use path `//vardecl`. If you only want fields declarations, then you can use some context information via path `/classdef/vardecl`, which would only find vardecls that our children of class definitions. You can merge the results of multiple XPath `findAll()`s simulating a set union for XPath. The only caveat is that the order from the original tree is not preserved when you union multiple `findAll()` sets. | |
52 | XPath works great when you need to find specific nodes, possibly in certain contexts. The context is limited to the parents on the way to the root of the tree. For example, if you want to find all ID nodes, use path `//ID`. If you want all variable declarations, you might use path `//vardecl`. If you only want fields declarations, then you can use some context information via path `/classdef/vardecl`, which would only find vardecls that are children of class definitions. You can merge the results of multiple XPath `findAll()`s simulating a set union for XPath. The only caveat is that the order from the original tree is not preserved when you union multiple `findAll()` sets. | |
53 | 53 | |
54 | 54 | ### Tree pattern matching |
55 | 55 | |
69 | 69 | |
70 | 70 | That way each listener function does not have to compute its appropriate scope. |
71 | 71 | |
72 | Examples: [DefScopesAndSymbols.java](https://github.com/mantra/compiler/blob/master/src/java/mantra/semantics/DefScopesAndSymbols.java) and [SetScopeListener.java](https://github.com/mantra/compiler/blob/master/src/java/mantra/semantics/SetScopeListener.java) and [VerifyListener.java](https://github.com/mantra/compiler/blob/master/src/java/mantra/semantics/VerifyListener.java)⏎ | |
72 | Examples: [DefScopesAndSymbols.java](https://github.com/mantra/compiler/blob/master/src/java/mantra/semantics/DefScopesAndSymbols.java) and [SetScopeListener.java](https://github.com/mantra/compiler/blob/master/src/java/mantra/semantics/SetScopeListener.java) and [VerifyListener.java](https://github.com/mantra/compiler/blob/master/src/java/mantra/semantics/VerifyListener.java) |
5 | 5 | |
6 | 6 | ANTLR is really two things: a tool that translates your grammar to a parser/lexer in Java (or other target language) and the runtime needed by the generated parsers/lexers. Even if you are using the ANTLR Intellij plug-in or ANTLRWorks to run the ANTLR tool, the generated code will still need the runtime library. |
7 | 7 | |
8 | The first thing you should do is probably download and install a development tool plug-in. Even if you only use such tools for editing, they are great. Then, follow the instructions below to get the runtime environment available to your system to run generated parsers/lexers. In what follows, I talk about antlr-4.7.1-complete.jar, which has the tool and the runtime and any other support libraries (e.g., ANTLR v4 is written in v3). | |
8 | The first thing you should do is probably download and install a development tool plug-in. Even if you only use such tools for editing, they are great. Then, follow the instructions below to get the runtime environment available to your system to run generated parsers/lexers. In what follows, I talk about antlr-4.9-complete.jar, which has the tool and the runtime and any other support libraries (e.g., ANTLR v4 is written in v3). | |
9 | 9 | |
10 | If you are going to integrate ANTLR into your existing build system using mvn, ant, or want to get ANTLR into your IDE such as eclipse or intellij, see Integrating ANTLR into Development Systems. | |
10 | If you are going to integrate ANTLR into your existing build system using mvn, ant, or want to get ANTLR into your IDE such as eclipse or intellij, see [Integrating ANTLR into Development Systems](https://github.com/antlr/antlr4/blob/master/doc/IDEs.md). | |
11 | 11 | |
12 | 12 | ### UNIX |
13 | 13 | |
14 | 0. Install Java (version 1.6 or higher) | |
14 | 0. Install Java (version 1.7 or higher) | |
15 | 15 | 1. Download |
16 | 16 | ``` |
17 | 17 | $ cd /usr/local/lib |
18 | $ curl -O https://www.antlr.org/download/antlr-4.7.1-complete.jar | |
18 | $ curl -O https://www.antlr.org/download/antlr-4.9-complete.jar | |
19 | 19 | ``` |
20 | 20 | Or just download in browser from website: |
21 | 21 | [https://www.antlr.org/download.html](https://www.antlr.org/download.html) |
22 | 22 | and put it somewhere rational like `/usr/local/lib`. |
23 | 23 | |
24 | 2. Add `antlr-4.7.1-complete.jar` to your `CLASSPATH`: | |
24 | 2. Add `antlr-4.9-complete.jar` to your `CLASSPATH`: | |
25 | 25 | ``` |
26 | $ export CLASSPATH=".:/usr/local/lib/antlr-4.7.1-complete.jar:$CLASSPATH" | |
26 | $ export CLASSPATH=".:/usr/local/lib/antlr-4.9-complete.jar:$CLASSPATH" | |
27 | 27 | ``` |
28 | 28 | It's also a good idea to put this in your `.bash_profile` or whatever your startup script is. |
29 | 29 | |
30 | 30 | 3. Create aliases for the ANTLR Tool, and `TestRig`. |
31 | 31 | ``` |
32 | $ alias antlr4='java -Xmx500M -cp "/usr/local/lib/antlr-4.7.1-complete.jar:$CLASSPATH" org.antlr.v4.Tool' | |
33 | $ alias grun='java -Xmx500M -cp "/usr/local/lib/antlr-4.7.1-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig' | |
32 | $ alias antlr4='java -Xmx500M -cp "/usr/local/lib/antlr-4.9-complete.jar:$CLASSPATH" org.antlr.v4.Tool' | |
33 | $ alias grun='java -Xmx500M -cp "/usr/local/lib/antlr-4.9-complete.jar:$CLASSPATH" org.antlr.v4.gui.TestRig' | |
34 | 34 | ``` |
35 | 35 | |
36 | 36 | ### WINDOWS |
37 | 37 | |
38 | 38 | (*Thanks to Graham Wideman*) |
39 | 39 | |
40 | 0. Install Java (version 1.6 or higher) | |
41 | 1. Download antlr-4.7.1-complete.jar (or whatever version) from [https://www.antlr.org/download/](https://www.antlr.org/download/) | |
40 | 0. Install Java (version 1.7 or higher) | |
41 | 1. Download antlr-4.9-complete.jar (or whatever version) from [https://www.antlr.org/download/](https://www.antlr.org/download/) | |
42 | 42 | Save to your directory for 3rd party Java libraries, say `C:\Javalib` |
43 | 2. Add `antlr-4.7.1-complete.jar` to CLASSPATH, either: | |
43 | 2. Add `antlr-4.9-complete.jar` to CLASSPATH, either: | |
44 | 44 | * Permanently: Using System Properties dialog > Environment variables > Create or append to `CLASSPATH` variable |
45 | 45 | * Temporarily, at command line: |
46 | 46 | ``` |
47 | SET CLASSPATH=.;C:\Javalib\antlr-4.7.1-complete.jar;%CLASSPATH% | |
47 | SET CLASSPATH=.;C:\Javalib\antlr-4.9-complete.jar;%CLASSPATH% | |
48 | 48 | ``` |
49 | 49 | 3. Create short convenient commands for the ANTLR Tool, and TestRig, using batch files or doskey commands: |
50 | 50 | * Batch files (in directory in system PATH) antlr4.bat and grun.bat |
70 | 70 | |
71 | 71 | ``` |
72 | 72 | $ java org.antlr.v4.Tool |
73 | ANTLR Parser Generator Version 4.7.1 | |
73 | ANTLR Parser Generator Version 4.9 | |
74 | 74 | -o ___ specify output directory where all output is generated |
75 | 75 | -lib ___ specify location of .tokens files |
76 | 76 | ... |
79 | 79 | or use -jar option on java: |
80 | 80 | |
81 | 81 | ``` |
82 | $ java -jar /usr/local/lib/antlr-4.7.1-complete.jar | |
83 | ANTLR Parser Generator Version 4.7.1 | |
82 | $ java -jar /usr/local/lib/antlr-4.9-complete.jar | |
83 | ANTLR Parser Generator Version 4.9 | |
84 | 84 | -o ___ specify output directory where all output is generated |
85 | 85 | -lib ___ specify location of .tokens files |
86 | 86 | ... |
111 | 111 | |
112 | 112 | ``` |
113 | 113 | $ grun Hello r -tree |
114 | (Now enter something like the string below) | |
114 | 115 | hello parrt |
116 | (now,do:) | |
115 | 117 | ^D |
118 | (The output:) | |
116 | 119 | (r hello parrt) |
117 | 120 | (That ^D means EOF on unix; it's ^Z in Windows.) The -tree option prints the parse tree in LISP notation. |
118 | 121 | It's nicer to look at parse trees visually. |
134 | 137 | Also, there is a large collection of grammars for v4 at github: |
135 | 138 | |
136 | 139 | [https://github.com/antlr/grammars-v4](https://github.com/antlr/grammars-v4) |
140 | /⏎ |
64 | 64 | |
65 | 65 | We'll write a small main func to call the generated parser/lexer (assuming they are separate). This one writes out the encountered `ParseTreeContext`'s. Suppose the gen'ed parser code is in the `parser` directory relative to this code: |
66 | 66 | |
67 | ``` | |
67 | ```golang | |
68 | 68 | package main |
69 | 69 | |
70 | 70 | import ( |
19 | 19 | This documentation is a reference and summarizes grammar syntax and the key semantics of ANTLR grammars. The source code for all examples in the book, not just this chapter, are free at the publisher's website. The following video is a general tour of ANTLR 4 and includes a description of how to use parse tree listeners to process Java files easily: |
20 | 20 | |
21 | 21 | <a href="https://vimeo.com/59285751"><img src=images/tertalk.png width=200></a> |
22 | ||
23 | For those using Java, here's a great [set of ANTLR in Intellij notes](https://docs.google.com/document/d/1gQ2lsidvN2cDUUsHEkT05L-wGbX5mROB7d70Aaj3R64/edit#heading=h.xr0jj8vcdsgc) by Andreas Stefik. | |
22 | 24 | |
23 | 25 | ## Sections |
24 | 26 |
138 | 138 | <dependency> |
139 | 139 | <groupId>junit</groupId> |
140 | 140 | <artifactId>junit</artifactId> |
141 | <version>3.8.1</version> | |
141 | <version>4.13.1</version> | |
142 | 142 | </dependency> |
143 | 143 | </dependencies> |
144 | 144 | <build> |
10 | 10 | * Chrome 39.0.2171 |
11 | 11 | * Explorer 11.0.3 |
12 | 12 | |
13 | The tests were conducted using Selenium. No issue was found, so you should find that the runtime works pretty much against any recent JavaScript engine. | |
13 | The above tests were conducted using Selenium. No issue was found, so you should find that the runtime works pretty much against any recent JavaScript engine. | |
14 | 14 | |
15 | 15 | ## Is NodeJS supported? |
16 | 16 | |
17 | The runtime has also been extensively tested against Node.js 0.12.7. No issue was found. | |
17 | The runtime has also been extensively tested against Node.js 14 LTS. No issue was found. | |
18 | NodeJS together with a packaging tool is now the preferred development path, developers are encouraged to follow it. | |
19 | ||
20 | ## What about modules? | |
21 | ||
22 | Starting with version 8.1, Antlr4 JavaScript runtime follows esm semantics (see https://tc39.es/ecma262/#sec-modules for details) | |
23 | Generated lexers, parsers, listeners and visitors also follow this new standard. | |
24 | If you have used previous versions of the runtime, you will need to migrate and make your parser a module. | |
18 | 25 | |
19 | 26 | ## How to create a JavaScript lexer or parser? |
20 | 27 | |
54 | 61 | |
55 | 62 | The steps to create your parsing code are the following: |
56 | 63 | - generate your lexer, parser, listener and visitor using the antlr tool |
57 | - write your parse tree handling code by providig your custom listener or visitor, and associated code, using 'require' to load antlr. | |
64 | - write your parse tree handling code by providing your custom listener or visitor, and associated code, using 'require' to load antlr. | |
58 | 65 | - create an index.js file with the entry point to your parsing code (or several if required). |
59 | 66 | - test your parsing logic thoroughly using node.js |
60 | 67 | |
61 | 68 | You are now ready to bundle your parsing code as follows: |
62 | 69 | - following webpack specs, create a webpack.config file |
63 | - in the webpack.config file, exclude node.js only modules using: node: { module: "empty", net: "empty", fs: "empty" } | |
70 | - For Webpack version 5, | |
71 | - in the `webpack.config` file, exclude node.js only modules using: `resolve: { fallback: { fs: false } }` | |
72 | - For older versions of Webpack, | |
73 | - in the `webpack.config` file, exclude node.js only modules using: `node: { module: "empty", net: "empty", fs: "empty" }` | |
64 | 74 | - from the cmd line, navigate to the directory containing webpack.config and type: webpack |
65 | 75 | |
66 | 76 | This will produce a single js file containing all your parsing code. Easy to include in your web pages! |
67 | ||
68 | If you can't use webpack, you can use the lib/require.js script which implements the Node.js 'require' function in brwsers. | |
69 | ||
70 | This script is provided by Torben Haase, and is NOT part of ANTLR JavaScript runtime. | |
71 | ||
72 | Assuming you have, at the root of your web site, both the 'antlr4' directory and a 'lib' directory with 'require.js' inside it, all you need to put in your HTML header is the following: | |
73 | ||
74 | ```xml | |
75 | <script src='lib/require.js'> | |
76 | <script> | |
77 | var antlr4 = require('antlr4/index'); | |
78 | </script> | |
79 | ``` | |
80 | ||
81 | This will load the runtime asynchronously. | |
82 | 77 | |
83 | 78 | ## How do I run the generated lexer and/or parser? |
84 | 79 | |
94 | 89 | Now a fully functioning script might look like the following: |
95 | 90 | |
96 | 91 | ```javascript |
97 | var antlr4 = require('antlr4'); | |
98 | var MyGrammarLexer = require('./MyGrammarLexer').MyGrammarLexer; | |
99 | var MyGrammarParser = require('./MyGrammarParser').MyGrammarParser; | |
100 | var MyGrammarListener = require('./MyGrammarListener').MyGrammarListener; | |
101 | ||
102 | var input = "your text to parse here" | |
103 | var chars = new antlr4.InputStream(input); | |
104 | var lexer = new MyGrammarLexer(chars); | |
105 | var tokens = new antlr4.CommonTokenStream(lexer); | |
106 | var parser = new MyGrammarParser(tokens); | |
92 | import antlr4 from 'antlr4'; | |
93 | import MyGrammarLexer from './MyGrammarLexer.js'; | |
94 | import MyGrammarParser from './MyGrammarParser.js'; | |
95 | import MyGrammarListener from './MyGrammarListener.js'; | |
96 | ||
97 | const input = "your text to parse here" | |
98 | const chars = new antlr4.InputStream(input); | |
99 | const lexer = new MyGrammarLexer(chars); | |
100 | const tokens = new antlr4.CommonTokenStream(lexer); | |
101 | const parser = new MyGrammarParser(tokens); | |
107 | 102 | parser.buildParseTrees = true; |
108 | var tree = parser.MyStartRule(); | |
103 | const tree = parser.MyStartRule(); | |
109 | 104 | ``` |
110 | 105 | |
111 | 106 | This program will work. But it won't be useful unless you do one of the following: |
116 | 111 | |
117 | 112 | (please note that production code is target specific, so you can't have multi target grammars that include production code) |
118 | 113 | |
114 | ## How do I create and run a visitor? | |
115 | ```javascript | |
116 | // test.js | |
117 | import antlr4 from 'antlr4'; | |
118 | import MyGrammarLexer from './QueryLexer.js'; | |
119 | import MyGrammarParser from './QueryParser.js'; | |
120 | import MyGrammarListener from './QueryListener.js'; | |
121 | ||
122 | ||
123 | const input = "field = 123 AND items in (1,2,3)" | |
124 | const chars = new antlr4.InputStream(input); | |
125 | const lexer = new MyGrammarLexer(chars); | |
126 | const tokens = new antlr4.CommonTokenStream(lexer); | |
127 | const parser = new MyGrammarParser(tokens); | |
128 | parser.buildParseTrees = true; | |
129 | const tree = parser.query(); | |
130 | ||
131 | class Visitor { | |
132 | visitChildren(ctx) { | |
133 | if (!ctx) { | |
134 | return; | |
135 | } | |
136 | ||
137 | if (ctx.children) { | |
138 | return ctx.children.map(child => { | |
139 | if (child.children && child.children.length != 0) { | |
140 | return child.accept(this); | |
141 | } else { | |
142 | return child.getText(); | |
143 | } | |
144 | }); | |
145 | } | |
146 | } | |
147 | } | |
148 | ||
149 | tree.accept(new Visitor()); | |
150 | ```` | |
151 | ||
119 | 152 | ## How do I create and run a custom listener? |
120 | 153 | |
121 | 154 | Let's suppose your MyGrammar grammar comprises 2 rules: "key" and "value". The antlr4 tool will have generated the following listener: |
122 | 155 | |
123 | 156 | ```javascript |
124 | MyGrammarListener = function(ParseTreeListener) { | |
125 | // some code here | |
126 | } | |
127 | // some code here | |
128 | MyGrammarListener.prototype.enterKey = function(ctx) {}; | |
129 | MyGrammarListener.prototype.exitKey = function(ctx) {}; | |
130 | MyGrammarListener.prototype.enterValue = function(ctx) {}; | |
131 | MyGrammarListener.prototype.exitValue = function(ctx) {}; | |
157 | class MyGrammarListener extends ParseTreeListener { | |
158 | ||
159 | constructor() { | |
160 | super(); | |
161 | } | |
162 | ||
163 | enterKey(ctx) {} | |
164 | exitKey(ctx) {} | |
165 | enterValue(ctx) {} | |
166 | exitValue(ctx) {} | |
167 | } | |
132 | 168 | ``` |
133 | 169 | |
134 | 170 | In order to provide custom behavior, you might want to create the following class: |
135 | 171 | |
136 | 172 | ```javascript |
137 | var KeyPrinter = function() { | |
138 | MyGrammarListener.call(this); // inherit default listener | |
139 | return this; | |
140 | }; | |
141 | ||
142 | // continue inheriting default listener | |
143 | KeyPrinter.prototype = Object.create(MyGrammarListener.prototype); | |
144 | KeyPrinter.prototype.constructor = KeyPrinter; | |
145 | ||
146 | // override default listener behavior | |
147 | KeyPrinter.prototype.exitKey = function(ctx) { | |
148 | console.log("Oh, a key!"); | |
149 | }; | |
173 | class KeyPrinter extends MyGrammarListener { | |
174 | ||
175 | // override default listener behavior | |
176 | exitKey(ctx) { | |
177 | console.log("Oh, a key!"); | |
178 | } | |
179 | } | |
150 | 180 | ``` |
151 | 181 | |
152 | 182 | In order to execute this listener, you would simply add the following lines to the above code: |
153 | 183 | |
154 | 184 | ```javascript |
155 | ... | |
156 | tree = parser.StartRule() // only repeated here for reference | |
157 | var printer = new KeyPrinter(); | |
185 | ... | |
186 | tree = parser.StartRule() // only repeated here for reference | |
187 | const printer = new KeyPrinter(); | |
158 | 188 | antlr4.tree.ParseTreeWalker.DEFAULT.walk(printer, tree); |
159 | 189 | ``` |
160 | 190 |
24 | 24 | |
25 | 25 | ## Lexical Modes |
26 | 26 | |
27 | Modes allow you to group lexical rules by context, such as inside and outside of XML tags. It’s like having multiple sublexers, one for context. The lexer can only return tokens matched by entering a rule in the current mode. Lexers start out in the so-called default mode. All rules are considered to be within the default mode unless you specify a mode command. Modes are not allowed within combined grammars, just lexer grammars. (See grammar `XMLLexer` from [Tokenizing XML](http://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference).) | |
27 | Modes allow you to group lexical rules by context, such as inside and outside of XML tags. It’s like having multiple sublexers, one for each context. The lexer can only return tokens matched by entering a rule in the current mode. Lexers start out in the so-called default mode. All rules are considered to be within the default mode unless you specify a mode command. Modes are not allowed within combined grammars, just lexer grammars. (See grammar `XMLLexer` from [Tokenizing XML](http://pragprog.com/book/tpantlr2/the-definitive-antlr-4-reference).) | |
28 | 28 | |
29 | 29 | ``` |
30 | 30 | rules in default mode |
57 | 57 | |
58 | 58 | <tr> |
59 | 59 | <td>[char set]</td><td> |
60 | <p>Match one of the characters specified in the character set. Interpret <tt>x-y</tt> as the set of characters between range <tt>x</tt> and <tt>y</tt>, inclusively. The following escaped characters are interpreted as single special characters: <tt>\n</tt>, <tt>\r</tt>, <tt>\b</tt>, <tt>\t</tt>, <tt>\f</tt>, <tt>\uXXXX</tt>, and <tt>\u{XXXXXX}</tt>. To get <tt>]</tt>, <tt>\</tt>, or <tt>-</tt> you must escape them with <tt>\</tt>.</p> | |
60 | <p>Match one of the characters specified in the character set. Interpret <tt>x-y</tt> as the set of characters between range <tt>x</tt> and <tt>y</tt>, inclusively. The following escaped characters are interpreted as single special characters: <tt>\n</tt>, <tt>\r</tt>, <tt>\b</tt>, <tt>\t</tt>, <tt>\f</tt>, <tt>\uXXXX</tt>, and <tt>\u{XXXXXX}</tt>. To get <tt>]</tt> or <tt>\</tt> you must escape them with <tt>\</tt>. To get <tt>-</tt> you must escape it with <tt>\</tt> too, except for the case when <tt>-</tt> is the first or last character in the set.</p> | |
61 | 61 | |
62 | 62 | <p>You can also include all characters matching Unicode properties (general category, boolean, or enumerated including scripts and blocks) with <tt>\p{PropertyName}</tt> or <tt>\p{EnumProperty=Value}</tt>. (You can invert the test with <tt>\P{PropertyName}</tt> or <tt>\P{EnumProperty=Value}</tt>).</p> |
63 | 63 | |
89 | 89 | EMOJI : [\u{1F4A9}\u{1F926}] ; // note Unicode code points > U+FFFF |
90 | 90 | |
91 | 91 | DASHBRACK : [\-\]]+ ; // match - or ] one or more times |
92 | ||
93 | DASH : [---] ; // match a single -, i.e., "any character" between - and - (note first and last - not escaped) | |
92 | 94 | </pre> |
93 | 95 | </td> |
94 | 96 | </tr> |
122 | 124 | |
123 | 125 | <tr> |
124 | 126 | <td>{«action»}</td><td> |
125 | Lexer actions can appear anywhere as of 4.2, not just at the end of the outermost alternative. The lexer executes the actions at the appropriate input position, according to the placement of the action within the rule. To execute a single action for a role that has multiple alternatives, you can enclose the alts in parentheses and put the action afterwards: | |
127 | Lexer actions can appear anywhere as of 4.2, not just at the end of the outermost alternative. The lexer executes the actions at the appropriate input position, according to the placement of the action within the rule. To execute a single action for a rule that has multiple alternatives, you can enclose the alts in parentheses and put the action afterwards: | |
126 | 128 | |
127 | 129 | <pre> |
128 | 130 | END : ('endif'|'end') {System.out.println("found an end");} ; |
243 | 245 | ``` |
244 | 246 | // Default "mode": Everything OUTSIDE of a tag |
245 | 247 | COMMENT : '<!--' .*? '-->' ; |
246 | CDATA : '<![CDATA[' .*? ']]>' ;OPEN : '<' -> pushMode(INSIDE) ; | |
248 | CDATA : '<![CDATA[' .*? ']]>' ; | |
249 | OPEN : '<' -> pushMode(INSIDE) ; | |
247 | 250 | ... |
248 | 251 | XMLDeclOpen : '<?xml' S -> pushMode(INSIDE) ; |
249 | 252 | SPECIAL_OPEN: '<?' Name -> more, pushMode(PROC_INSTR) ; |
25 | 25 | Token names always start with a capital letter and so do lexer rules as defined by Java’s `Character.isUpperCase` method. Parser rule names always start with a lowercase letter (those that fail `Character.isUpperCase`). The initial character can be followed by uppercase and lowercase letters, digits, and underscores. Here are some sample names: |
26 | 26 | |
27 | 27 | ``` |
28 | ID, LPAREN, RIGHT_CURLY // token names/rules | |
29 | expr, simpleDeclarator, d2, header_file // rule names | |
28 | ID, LPAREN, RIGHT_CURLY // token names/lexer rules | |
29 | expr, simpleDeclarator, d2, header_file // parser rule names | |
30 | 30 | ``` |
31 | 31 | |
32 | 32 | Like Java, ANTLR accepts Unicode characters in ANTLR names: |
78 | 78 | |
79 | 79 | ## Literals |
80 | 80 | |
81 | ANTLR does not distinguish between character and string literals as most languages do. All literal strings one or more characters in length are enclosed in single quotes such as `’;’`, `’if’`, `’>=’`, and `’\’` (refers to the one-character string containing the single quote character). Literals never contain regular expressions. | |
81 | ANTLR does not distinguish between character and string literals as most languages do. All literal strings one or more characters in length are enclosed in single quotes such as `’;’`, `’if’`, `’>=’`, and `’\’’` (refers to the one-character string containing the single quote character). Literals never contain regular expressions. | |
82 | 82 | |
83 | 83 | Literals can contain Unicode escape sequences of the form `’\uXXXX’` (for Unicode code points up to `’U+FFFF’`) or `’\u{XXXXXX}’` (for all Unicode code points), where `’XXXX’` is the hexadecimal Unicode code point value. |
84 | 84 | |
95 | 95 | |
96 | 96 | ## Actions |
97 | 97 | |
98 | Actions are code blocks written in the target language. You can use actions in a number of places within a grammar, but the syntax is always the same: arbitrary text surrounded by curly braces. You don’t need to escape a closing curly character if it’s in a string or comment: `"}"` or `/*}*/`. If the curlies are balanced, you also don’t need to escape }: `{...}`. Otherwise, escape extra curlies with a backslash: `\{` or `\}`. The action text should conform to the target language as specified with thelanguage option. | |
98 | Actions are code blocks written in the target language. You can use actions in a number of places within a grammar, but the syntax is always the same: arbitrary text surrounded by curly braces. You don’t need to escape a closing curly character if it’s in a string or comment: `"}"` or `/*}*/`. If the curlies are balanced, you also don’t need to escape }: `{...}`. Otherwise, escape extra curlies with a backslash: `\{` or `\}`. The action text should conform to the target language as specified with the language option. | |
99 | 99 | |
100 | 100 | Embedded code can appear in: `@header` and `@members` named actions, parser and lexer rules, exception catching specifications, attribute sections for parser rules (return values, arguments, and locals), and some rule element options (currently predicates). |
101 | 101 |
0 | # ANTLR4 Runtime for PHP | |
1 | ||
2 | ### First steps | |
3 | ||
4 | #### 1. Install ANTLR4 | |
5 | ||
6 | [The getting started guide](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md) | |
7 | should get you started. | |
8 | ||
9 | #### 2. Install the PHP ANTLR runtime | |
10 | ||
11 | Each target language for ANTLR has a runtime package for running parser | |
12 | generated by ANTLR4. The runtime provides a common set of tools for using your parser. | |
13 | ||
14 | Install the runtime with Composer: | |
15 | ||
16 | ```bash | |
17 | composer require antlr/antlr4-php-runtime | |
18 | ``` | |
19 | ||
20 | #### 3. Generate your parser | |
21 | ||
22 | You use the ANTLR4 "tool" to generate a parser. These will reference the ANTLR | |
23 | runtime, installed above. | |
24 | ||
25 | Suppose you're using a UNIX system and have set up an alias for the ANTLR4 tool | |
26 | as described in [the getting started guide](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md). | |
27 | To generate your PHP parser, run the following command: | |
28 | ||
29 | ```bash | |
30 | antlr4 -Dlanguage=PHP MyGrammar.g4 | |
31 | ``` | |
32 | ||
33 | For a full list of antlr4 tool options, please visit the | |
34 | [tool documentation page](https://github.com/antlr/antlr4/blob/master/doc/tool-options.md). | |
35 | ||
36 | ### Complete example | |
37 | ||
38 | Suppose you're using the JSON grammar from https://github.com/antlr/grammars-v4/tree/master/json. | |
39 | ||
40 | Then, invoke `antlr4 -Dlanguage=PHP JSON.g4`. The result of this is a | |
41 | collection of `.php` files in the `parser` directory including: | |
42 | ``` | |
43 | JsonParser.php | |
44 | JsonBaseListener.php | |
45 | JsonLexer.php | |
46 | JsonListener.php | |
47 | ``` | |
48 | ||
49 | Another common option to the ANTLR tool is `-visitor`, which generates a parse | |
50 | tree visitor, but we won't be doing that here. For a full list of antlr4 tool | |
51 | options, please visit the [tool documentation page](tool-options.md). | |
52 | ||
53 | We'll write a small main func to call the generated parser/lexer | |
54 | (assuming they are separate). This one writes out the encountered | |
55 | `ParseTreeContext`'s: | |
56 | ||
57 | ```php | |
58 | <?php | |
59 | ||
60 | namespace JsonParser; | |
61 | ||
62 | use Antlr\Antlr4\Runtime\CommonTokenStream; | |
63 | use Antlr\Antlr4\Runtime\Error\Listeners\DiagnosticErrorListener; | |
64 | use Antlr\Antlr4\Runtime\InputStream; | |
65 | use Antlr\Antlr4\Runtime\ParserRuleContext; | |
66 | use Antlr\Antlr4\Runtime\Tree\ErrorNode; | |
67 | use Antlr\Antlr4\Runtime\Tree\ParseTreeListener; | |
68 | use Antlr\Antlr4\Runtime\Tree\ParseTreeWalker; | |
69 | use Antlr\Antlr4\Runtime\Tree\TerminalNode; | |
70 | ||
71 | final class TreeShapeListener implements ParseTreeListener { | |
72 | public function visitTerminal(TerminalNode $node) : void {} | |
73 | public function visitErrorNode(ErrorNode $node) : void {} | |
74 | public function exitEveryRule(ParserRuleContext $ctx) : void {} | |
75 | ||
76 | public function enterEveryRule(ParserRuleContext $ctx) : void { | |
77 | echo $ctx->getText(); | |
78 | } | |
79 | } | |
80 | ||
81 | $input = InputStream::fromPath($argv[1]); | |
82 | $lexer = new JSONLexer($input); | |
83 | $tokens = new CommonTokenStream($lexer); | |
84 | $parser = new JSONParser($tokens); | |
85 | $parser->addErrorListener(new DiagnosticErrorListener()); | |
86 | $parser->setBuildParseTree(true); | |
87 | $tree = $parser->json(); | |
88 | ||
89 | ParseTreeWalker::default()->walk(new TreeShapeListener(), $tree); | |
90 | ``` | |
91 | ||
92 | Create a `example.json` file: | |
93 | ```json | |
94 | {"a":1} | |
95 | ``` | |
96 | ||
97 | Parse the input file: | |
98 | ||
99 | ``` | |
100 | php json.php example.json | |
101 | ``` | |
102 | ||
103 | The expected output is: | |
104 | ||
105 | ``` | |
106 | {"a":1} | |
107 | {"a":1} | |
108 | "a":1 | |
109 | 1 | |
110 | ``` |
49 | 49 | from MyGrammarParser import MyGrammarParser |
50 | 50 | |
51 | 51 | def main(argv): |
52 | input = FileStream(argv[1]) | |
53 | lexer = MyGrammarLexer(input) | |
52 | input_stream = FileStream(argv[1]) | |
53 | lexer = MyGrammarLexer(input_stream) | |
54 | 54 | stream = CommonTokenStream(lexer) |
55 | 55 | parser = MyGrammarParser(stream) |
56 | 56 | tree = parser.startRule() |
8 | 8 | Wack any existing tag as mvn will create one and it fails if already there. |
9 | 9 | |
10 | 10 | ``` |
11 | $ git tag -d 4.7 | |
12 | $ git push origin :refs/tags/4.7 | |
13 | $ git push upstream :refs/tags/4.7 | |
11 | $ git tag -d 4.9 | |
12 | $ git push origin :refs/tags/4.9 | |
13 | $ git push upstream :refs/tags/4.9 | |
14 | 14 | ``` |
15 | 15 | |
16 | 16 | ### Create release candidate tag |
17 | 17 | |
18 | 18 | ```bash |
19 | $ git tag -a 4.7-rc1 -m 'heading towards 4.7' | |
20 | $ git push origin 4.7-rc1 | |
21 | $ git push upstream 4.7-rc1 | |
19 | $ git tag -a 4.9-rc1 -m 'heading towards 4.9' | |
20 | $ git push origin 4.9-rc1 | |
21 | $ git push upstream 4.9-rc1 | |
22 | ``` | |
23 | ||
24 | ## Copy PHP runtime over | |
25 | ||
26 | Bump version to 4.9 in `~/antlr/code/antlr-php-runtime/src/RuntimeMetaData.php` in separate repository and commit plus push. | |
27 | ||
28 | ``` | |
29 | cd ~/antlr/code/antlr-php-runtime/src | |
30 | ... vi RuntimeMetaData.php ... | |
31 | git commit -a -m "Update PHP Runtime to latest version" | |
32 | ``` | |
33 | ||
34 | them back over in the ANTLR repo: | |
35 | ||
36 | ``` | |
37 | cd runtime | |
38 | rm -rf PHP | |
39 | mkdir PHP | |
40 | cp ~/antlr/code/antlr-php-runtime/LICENSE PHP | |
41 | cp ~/antlr/code/antlr-php-runtime/README.md PHP | |
42 | cp ~/antlr/code/antlr-php-runtime/composer.json PHP | |
43 | cp ~/antlr/code/antlr-php-runtime/phpcs.xml.dist PHP | |
44 | cp ~/antlr/code/antlr-php-runtime/phpstan.neon.dist PHP | |
45 | cp -r ~/antlr/code/antlr-php-runtime/src PHP | |
22 | 46 | ``` |
23 | 47 | |
24 | 48 | ## Bump version |
30 | 54 | * runtime/Python2/src/antlr4/Recognizer.py |
31 | 55 | * runtime/Python3/setup.py |
32 | 56 | * runtime/Python3/src/antlr4/Recognizer.py |
33 | * runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Properties/AssemblyInfo.cs | |
34 | * runtime/CSharp/runtime/CSharp/Antlr4.Runtime/Antlr4.Runtime.dotnet.csproj | |
35 | * runtime/JavaScript/src/antlr4/package.json | |
57 | * runtime/CSharp/src/Antlr4.csproj | |
58 | * runtime/PHP/src/RuntimeMetaData.php | |
59 | * runtime/JavaScript/package.json | |
36 | 60 | * runtime/JavaScript/src/antlr4/Recognizer.js |
61 | * runtime/JavaScript/package-lock.json | |
37 | 62 | * runtime/Cpp/VERSION |
38 | 63 | * runtime/Cpp/runtime/src/RuntimeMetaData.cpp |
39 | 64 | * runtime/Cpp/cmake/ExternalAntlr4Cpp.cmake |
40 | 65 | * runtime/Cpp/demo/generate.cmd |
41 | 66 | * runtime/Go/antlr/recognizer.go |
42 | 67 | * runtime/Swift/Antlr4/org/antlr/v4/runtime/RuntimeMetaData.swift |
68 | * runtime/Dart/lib/src/runtime_meta_data.dart | |
69 | * runtime/Dart/pubspec.yaml | |
70 | * runtime/Swift/Tests/Antlr4Tests/RuntimeMetaDataTests.swift | |
71 | * runtime/Swift/Sources/Antlr4/RuntimeMetaData.swift | |
72 | * runtime/CSharp/src/Tree/Xpath/XPathLexer.cs | |
73 | * runtime/CSharp/src/README.md | |
74 | * runtime/CSharp/src/Properties/AssemblyInfo.cs | |
43 | 75 | * tool/src/org/antlr/v4/codegen/target/GoTarget.java |
44 | 76 | * tool/src/org/antlr/v4/codegen/target/CppTarget.java |
45 | 77 | * tool/src/org/antlr/v4/codegen/target/CSharpTarget.java |
47 | 79 | * tool/src/org/antlr/v4/codegen/target/Python2Target.java |
48 | 80 | * tool/src/org/antlr/v4/codegen/target/Python3Target.java |
49 | 81 | * tool/src/org/antlr/v4/codegen/target/SwiftTarget.java |
82 | * tool/src/org/antlr/v4/codegen/target/PHPTarget.java | |
50 | 83 | * tool/src/org/antlr/v4/codegen/Target.java |
51 | 84 | * tool/resources/org/antlr/v4/tool/templates/codegen/Swift/Swift.stg |
52 | 85 | |
53 | Here is a simple script to display any line from the critical files with, say, `4.5` in it: | |
54 | ||
55 | ```bash | |
56 | find tool runtime -type f -exec grep -l '4\.6' {} \; | |
86 | Here is a simple script to display any line from the critical files with, say, `4.9` in it: | |
87 | ||
88 | ```bash | |
89 | mvn clean | |
90 | rm -rf runtime/CSharp/src/bin | |
91 | rm -rf runtime/CSharp/src/obj | |
92 | rm -rf runtime/Cpp/runtime/build | |
93 | rm -rf runtime/gen | |
94 | rm -rf runtime/JavaScript/dist | |
95 | find tool runtime -type f -exec grep -l '4\.9' {} \; | |
57 | 96 | ``` |
58 | 97 | |
59 | 98 | Commit to repository. |
99 | ||
100 | ## Building | |
101 | ||
102 | ugh. apparently you have to `mvn install` and then `mvn compile` or some such or subdir pom.xml's won't see the latest runtime build. | |
60 | 103 | |
61 | 104 | ## Maven Repository Settings |
62 | 105 | |
105 | 148 | |
106 | 149 | ## Maven deploy snapshot |
107 | 150 | |
108 | The goal is to get a snapshot, such as `4.7-SNAPSHOT`, to the staging server: [antlr4 tool](https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4) and [antlr4 java runtime](https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-runtime). | |
151 | The goal is to get a snapshot, such as `4.9-SNAPSHOT`, to the staging server: [antlr4 tool](https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4) and [antlr4 java runtime](https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-runtime). | |
109 | 152 | |
110 | 153 | Do this: |
111 | 154 | |
112 | 155 | ```bash |
156 | $ mvn install -DskipTests # seems required to get the jar files visible to maven | |
113 | 157 | $ mvn deploy -DskipTests |
114 | 158 | ... |
115 | 159 | [INFO] --- maven-deploy-plugin:2.7:deploy (default-deploy) @ antlr4-tool-testsuite --- |
116 | Downloading: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.7-SNAPSHOT/maven-metadata.xml | |
117 | Uploading: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.7-SNAPSHOT/antlr4-tool-testsuite-4.7-20161211.173752-1.jar | |
118 | Uploaded: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.7-SNAPSHOT/antlr4-tool-testsuite-4.7-20161211.173752-1.jar (3 KB at 3.4 KB/sec) | |
119 | Uploading: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.7-SNAPSHOT/antlr4-tool-testsuite-4.7-20161211.173752-1.pom | |
120 | Uploaded: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.7-SNAPSHOT/antlr4-tool-testsuite-4.7-20161211.173752-1.pom (3 KB at 6.5 KB/sec) | |
160 | Downloading: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.9-SNAPSHOT/maven-metadata.xml | |
161 | Uploading: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.9-SNAPSHOT/antlr4-tool-testsuite-4.9-20161211.173752-1.jar | |
162 | Uploaded: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.9-SNAPSHOT/antlr4-tool-testsuite-4.9-20161211.173752-1.jar (3 KB at 3.4 KB/sec) | |
163 | Uploading: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.9-SNAPSHOT/antlr4-tool-testsuite-4.9-20161211.173752-1.pom | |
164 | Uploaded: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.9-SNAPSHOT/antlr4-tool-testsuite-4.9-20161211.173752-1.pom (3 KB at 6.5 KB/sec) | |
121 | 165 | Downloading: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/maven-metadata.xml |
122 | 166 | Downloaded: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/maven-metadata.xml (371 B at 1.4 KB/sec) |
123 | Uploading: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.7-SNAPSHOT/maven-metadata.xml | |
124 | Uploaded: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.7-SNAPSHOT/maven-metadata.xml (774 B at 1.8 KB/sec) | |
167 | Uploading: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.9-SNAPSHOT/maven-metadata.xml | |
168 | Uploaded: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/4.9-SNAPSHOT/maven-metadata.xml (774 B at 1.8 KB/sec) | |
125 | 169 | Uploading: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/maven-metadata.xml |
126 | 170 | Uploaded: https://oss.sonatype.org/content/repositories/snapshots/org/antlr/antlr4-tool-testsuite/maven-metadata.xml (388 B at 0.9 KB/sec) |
127 | 171 | [INFO] ------------------------------------------------------------------------ |
167 | 211 | Side note to set jdk 1.7 on os x: |
168 | 212 | |
169 | 213 | ```bash |
170 | alias java='/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/bin/java' | |
171 | alias javac='/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/bin/javac' | |
172 | alias javadoc='/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/bin/javadoc' | |
173 | alias jar='/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/bin/jar' | |
214 | alias java="`/usr/libexec/java_home -v 1.7`/bin/java" | |
215 | alias javac="`/usr/libexec/java_home -v 1.7`/bin/javac" | |
216 | alias javadoc="`/usr/libexec/java_home -v 1.7`/bin/javadoc" | |
217 | alias jar="`/usr/libexec/java_home -v 1.7`/bin/jar" | |
174 | 218 | export JAVA_HOME=`/usr/libexec/java_home -v 1.7` |
175 | 219 | ``` |
176 | 220 | |
191 | 235 | |
192 | 236 | ``` |
193 | 237 | ... |
194 | What is the release version for "ANTLR 4"? (org.antlr:antlr4-master) 4.7: : 4.7 | |
195 | What is the release version for "ANTLR 4 Runtime"? (org.antlr:antlr4-runtime) 4.7: : | |
196 | What is the release version for "ANTLR 4 Tool"? (org.antlr:antlr4) 4.7: : | |
197 | What is the release version for "ANTLR 4 Maven plugin"? (org.antlr:antlr4-maven-plugin) 4.7: : | |
198 | What is the release version for "ANTLR 4 Runtime Test Generator"? (org.antlr:antlr4-runtime-testsuite) 4.7: : | |
199 | What is the release version for "ANTLR 4 Tool Tests"? (org.antlr:antlr4-tool-testsuite) 4.7: : | |
200 | What is SCM release tag or label for "ANTLR 4"? (org.antlr:antlr4-master) antlr4-master-4.7: : 4.7 | |
201 | What is the new development version for "ANTLR 4"? (org.antlr:antlr4-master) 4.7.1-SNAPSHOT: | |
238 | What is the release version for "ANTLR 4"? (org.antlr:antlr4-master) 4.9: : 4.9 | |
239 | What is the release version for "ANTLR 4 Runtime"? (org.antlr:antlr4-runtime) 4.9: : | |
240 | What is the release version for "ANTLR 4 Tool"? (org.antlr:antlr4) 4.9: : | |
241 | What is the release version for "ANTLR 4 Maven plugin"? (org.antlr:antlr4-maven-plugin) 4.9: : | |
242 | What is the release version for "ANTLR 4 Runtime Test Generator"? (org.antlr:antlr4-runtime-testsuite) 4.9: : | |
243 | What is the release version for "ANTLR 4 Tool Tests"? (org.antlr:antlr4-tool-testsuite) 4.9: : | |
244 | What is SCM release tag or label for "ANTLR 4"? (org.antlr:antlr4-master) antlr4-master-4.9: : 4.9 | |
245 | What is the new development version for "ANTLR 4"? (org.antlr:antlr4-master) 4.9.1-SNAPSHOT: | |
202 | 246 | ... |
203 | 247 | ``` |
204 | 248 | |
205 | Maven will go through your pom.xml files to update versions from 4.7-SNAPSHOT to 4.7 for release and then to 4.7.1-SNAPSHOT after release, which is done with: | |
249 | Maven will go through your pom.xml files to update versions from 4.9-SNAPSHOT to 4.9 for release and then to 4.9.1-SNAPSHOT after release, which is done with: | |
206 | 250 | |
207 | 251 | ```bash |
208 | 252 | mvn release:perform -Darguments="-DskipTests" |
216 | 260 | |
217 | 261 | and on the left click "Staging Repositories". You click the staging repo and close it, then you refresh, click it and release it. It's done when you see it here: |
218 | 262 | |
219 | [http://repo1.maven.org/maven2/org/antlr/antlr4-runtime/](http://repo1.maven.org/maven2/org/antlr/antlr4-runtime/) | |
263 | [https://oss.sonatype.org/service/local/repositories/releases/content/org/antlr/antlr4-runtime/4.9-1/antlr4-runtime-4.9-1.jar](https://oss.sonatype.org/service/local/repositories/releases/content/org/antlr/antlr4-runtime/4.9-1/antlr4-runtime-4.9-1.jar) | |
264 | ||
265 | All releases should be here: https://repo1.maven.org/maven2/org/antlr/antlr4-runtime/ | |
220 | 266 | |
221 | 267 | Copy the jars to antlr.org site and update download/index.html |
222 | 268 | |
223 | 269 | ```bash |
224 | cp ~/.m2/repository/org/antlr/antlr4-runtime/4.7/antlr4-runtime-4.7.jar ~/antlr/sites/website-antlr4/download/antlr-runtime-4.7.jar | |
225 | cp ~/.m2/repository/org/antlr/antlr4/4.7/antlr4-4.7-complete.jar ~/antlr/sites/website-antlr4/download/antlr-4.7-complete.jar | |
270 | cp ~/.m2/repository/org/antlr/antlr4-runtime/4.9/antlr4-runtime-4.9.jar ~/antlr/sites/website-antlr4/download/antlr-runtime-4.9.jar | |
271 | cp ~/.m2/repository/org/antlr/antlr4/4.9/antlr4-4.9-complete.jar ~/antlr/sites/website-antlr4/download/antlr-4.9-complete.jar | |
226 | 272 | cd ~/antlr/sites/website-antlr4/download |
227 | git add antlr-4.7-complete.jar | |
228 | git add antlr-runtime-4.7.jar | |
273 | git add antlr-4.9-complete.jar | |
274 | git add antlr-runtime-4.9.jar | |
229 | 275 | ``` |
230 | 276 | |
231 | 277 | Update on site: |
237 | 283 | * scripts/topnav.js |
238 | 284 | |
239 | 285 | ``` |
240 | git commit -a -m 'add 4.7 jars' | |
286 | git commit -a -m 'add 4.9 jars' | |
241 | 287 | git push origin gh-pages |
242 | 288 | ``` |
243 | 289 | |
246 | 292 | ### JavaScript |
247 | 293 | |
248 | 294 | ```bash |
249 | cd runtime/JavaScript/src | |
250 | zip -r /tmp/antlr-javascript-runtime-4.7.zip antlr4 | |
251 | cp /tmp/antlr-javascript-runtime-4.7.zip ~/antlr/sites/website-antlr4/download | |
295 | cd runtime/JavaScript | |
252 | 296 | # git add, commit, push |
253 | 297 | ``` |
254 | 298 | |
255 | 299 | **Push to npm** |
256 | 300 | |
257 | 301 | ```bash |
258 | cd runtime/JavaScript/src | |
302 | cd runtime/JavaScript | |
303 | npm update | |
304 | npm install | |
305 | npm run build | |
259 | 306 | npm login |
260 | npm publish antlr4 | |
261 | ``` | |
262 | ||
263 | Move target to website | |
264 | ||
265 | ```bash | |
266 | pushd ~/antlr/sites/website-antlr4/download | |
267 | git add antlr-javascript-runtime-4.7.zip | |
268 | git commit -a -m 'update JS runtime' | |
269 | git push origin gh-pages | |
270 | popd | |
307 | npm publish # don't put antlr4 on there or it will try to push the old version for some reason | |
308 | ``` | |
309 | ||
310 | Move (and zip) target to website: | |
311 | ||
312 | ```bash | |
313 | cd src | |
314 | zip -r ~/antlr/sites/website-antlr4/download/antlr-javascript-runtime-4.9.zip . | |
271 | 315 | ``` |
272 | 316 | |
273 | 317 | ### CSharp |
280 | 324 | |
281 | 325 | Of course you need Mono and `nuget` to be installed. On mac: |
282 | 326 | |
283 | - .NET build tools - can be loaded from [here](https://www.visualstudio.com/downloads/) | |
327 | - .NET build tools - can be loaded from [here](https://www.visualstudio.com/downloads/) (I need dotnet 5 and 3.1 versions) | |
284 | 328 | - nuget - download [nuget.exe](https://www.nuget.org/downloads) |
285 | 329 | - dotnet - follow [the instructions here](https://www.microsoft.com/net/core) |
330 | ||
331 | From @kvanTTT: Install `dotnet` on any platform (see https://dotnet.microsoft.com/download) and run the following command on any OS (Win, Linux, macOS): | |
332 | ||
333 | * building: `dotnet build runtime/CSharp/src/Antlr4.csproj -c Release` | |
334 | Output `.dll` will be in `runtime/CSharp/src/bin/Release/netstandard2.0` or in `runtime/CSharp/src/bin/Release/netstandard2.1` | |
335 | * packing: `dotnet pack runtime/CSharp/src/Antlr4.csproj -c Release` | |
336 | Output `.nupkg` will be in `runtime/CSharp/src/bin/Release/Antlr4.Runtime.Standard.4.9.1.nupkg` | |
286 | 337 | |
287 | 338 | Alternatively, you can install Visual Studio 2017 and make sure to check boxes with .NET Core SDK. |
288 | 339 | |
308 | 359 | Restore completed in 427.62 ms for C:\Code\antlr4-fork\runtime\CSharp\runtime\CSharp\Antlr4.Runtime\Antlr4.Runtime.dotnet.csproj. |
309 | 360 | Antlr4.Runtime.dotnet -> C:\Code\antlr4-fork\runtime\CSharp\runtime\CSharp\Antlr4.Runtime\lib\Release\netstandard1.3\Antlr4.Runtime.Standard.dll |
310 | 361 | Antlr4.Runtime.dotnet -> C:\Code\antlr4-fork\runtime\CSharp\runtime\CSharp\Antlr4.Runtime\lib\Release\net35\Antlr4.Runtime.Standard.dll |
311 | Successfully created package 'C:\Code\antlr4-fork\runtime\CSharp\runtime\CSharp\Antlr4.Runtime\lib\Release\Antlr4.Runtime.Standard.4.7.2.nupkg'. | |
362 | Successfully created package 'C:\Code\antlr4-fork\runtime\CSharp\runtime\CSharp\Antlr4.Runtime\lib\Release\Antlr4.Runtime.Standard.4.9.2.nupkg'. | |
312 | 363 | ``` |
313 | 364 | |
314 | 365 | **Publishing to NuGet** |
370 | 421 | |
371 | 422 | The C++ target is the most complex one, because it addresses multiple platforms, which require individual handling. We have 4 scenarios to cover: |
372 | 423 | |
373 | * **Windows**: static and dynamic libraries for the VC++ runtime 2013 or 2015 (corresponding to Visual Studio 2013 or 2015) + header files. All that in 32 and 64bit, debug + release. | |
424 | * **Windows**: static and dynamic libraries for the VC++ runtime 2017 or 2019 (corresponding to Visual Studio 2017 or 2019) + header files. All that in 32 and 64bit, debug + release. | |
374 | 425 | * **MacOS**: static and dynamic release libraries + header files. |
375 | 426 | * **iOS**: no prebuilt binaries, but just a zip of the source, including the XCode project to build everything from source. |
376 | 427 | * **Linux**: no prebuilt binaries, but just a zip of the source code, including the cmake file to build everything from source there. |
384 | 435 | ```bash |
385 | 436 | cd runtime/Cpp |
386 | 437 | ./deploy-macos.sh |
387 | cp antlr4-cpp-runtime-macos.zip ~/antlr/sites/website-antlr4/download/antlr4-cpp-runtime-4.7-macos.zip | |
438 | cp antlr4-cpp-runtime-macos.zip ~/antlr/sites/website-antlr4/download/antlr4-cpp-runtime-4.9-macos.zip | |
388 | 439 | ``` |
389 | 440 | |
390 | 441 | On any Mac or Linux machine: |
392 | 443 | ```bash |
393 | 444 | cd runtime/Cpp |
394 | 445 | ./deploy-source.sh |
395 | cp antlr4-cpp-runtime-source.zip ~/antlr/sites/website-antlr4/download/antlr4-cpp-runtime-4.7-source.zip | |
396 | ``` | |
397 | ||
398 | On a Windows machine the build scripts checks if VS 2013 and/or VS 2015 are installed and builds binaries for each, if found. This script requires 7z to be installed (http://7-zip.org then do `set PATH=%PATH%;C:\Program Files\7-Zip\` from DOS not powershell). | |
446 | cp antlr4-cpp-runtime-source.zip ~/antlr/sites/website-antlr4/download/antlr4-cpp-runtime-4.9-source.zip | |
447 | ``` | |
448 | ||
449 | On a Windows machine the build scripts checks if VS 2017 and/or VS 2019 are installed and builds binaries for each, if found. This script requires 7z to be installed (http://7-zip.org then do `set PATH=%PATH%;C:\Program Files\7-Zip\` from DOS not powershell). | |
399 | 450 | |
400 | 451 | ```bash |
401 | 452 | cd runtime/Cpp |
402 | deploy-windows.cmd | |
403 | cp runtime\bin\vs-2015\x64\Release DLL\antlr4-cpp-runtime-vs2015.zip ~/antlr/sites/website-antlr4/download/antlr4-cpp-runtime-4.7-vs2015.zip | |
453 | deploy-windows.cmd Community | |
454 | cp antlr4-cpp-runtime-vs2019.zip ~/antlr/sites/website-antlr4/download/antlr4-cpp-runtime-4.9-vs2019.zip | |
404 | 455 | ``` |
405 | 456 | |
406 | 457 | Move target to website (**_rename to a specific ANTLR version first if needed_**): |
408 | 459 | ```bash |
409 | 460 | pushd ~/antlr/sites/website-antlr4/download |
410 | 461 | # vi index.html |
411 | git add antlr4cpp-runtime-4.7-macos.zip | |
412 | git add antlr4cpp-runtime-4.7-windows.zip | |
413 | git add antlr4cpp-runtime-4.7-source.zip | |
462 | git add antlr4-cpp-runtime-4.9-macos.zip | |
463 | git add antlr4-cpp-runtime-4.9-windows.zip | |
464 | git add antlr4-cpp-runtime-4.9-source.zip | |
414 | 465 | git commit -a -m 'update C++ runtime' |
415 | 466 | git push origin gh-pages |
416 | 467 | popd |
417 | 468 | ``` |
469 | ||
470 | ### Dart | |
471 | ||
472 | Install Dart SDK from https://dart.dev/get-dart | |
473 | ||
474 | Push to pub.dev | |
475 | ||
476 | ```bash | |
477 | cd runtime/Dart | |
478 | pub publish | |
479 | ``` | |
480 | ||
481 | It will warn that no change log found for the new version. | |
482 | If there are changes relevant to dart in this release, edit [CHANGELOG.md](https://github.com/antlr/antlr4/blob/master/runtime/Dart/CHANGELOG.md) to describe the changes. | |
483 | Otherwise enter `N` to ignore the warning. | |
418 | 484 | |
419 | 485 | ## Update javadoc for runtime and tool |
420 | 486 | |
432 | 498 | git checkout gh-pages |
433 | 499 | git pull origin gh-pages |
434 | 500 | cd Java |
435 | jar xvf ~/.m2/repository/org/antlr/antlr4-runtime/4.7/antlr4-runtime-4.7-javadoc.jar | |
501 | jar xvf ~/.m2/repository/org/antlr/antlr4-runtime/4.9/antlr4-runtime-4.9-javadoc.jar | |
436 | 502 | cd ../JavaTool |
437 | jar xvf ~/.m2/repository/org/antlr/antlr4/4.7/antlr4-4.7-javadoc.jar | |
503 | jar xvf ~/.m2/repository/org/antlr/antlr4/4.9/antlr4-4.9-javadoc.jar | |
438 | 504 | git commit -a -m 'freshen api doc' |
439 | 505 | git push origin gh-pages |
440 | 506 | ``` |
0 | // | |
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. | |
2 | * Use of this file is governed by the BSD 3-clause license that | |
3 | * can be found in the LICENSE.txt file in the project root. | |
4 | */ | |
5 | // | |
6 | ||
7 | function CaseChangingStream(stream, upper) { | |
8 | this._stream = stream; | |
9 | this._upper = upper; | |
10 | } | |
11 | ||
12 | CaseChangingStream.prototype.LA = function(offset) { | |
13 | var c = this._stream.LA(offset); | |
14 | if (c <= 0) { | |
15 | return c; | |
16 | } | |
17 | return String.fromCodePoint(c)[this._upper ? "toUpperCase" : "toLowerCase"]().codePointAt(0); | |
18 | }; | |
19 | ||
20 | CaseChangingStream.prototype.reset = function() { | |
21 | return this._stream.reset(); | |
22 | }; | |
23 | ||
24 | CaseChangingStream.prototype.consume = function() { | |
25 | return this._stream.consume(); | |
26 | }; | |
27 | ||
28 | CaseChangingStream.prototype.LT = function(offset) { | |
29 | return this._stream.LT(offset); | |
30 | }; | |
31 | ||
32 | CaseChangingStream.prototype.mark = function() { | |
33 | return this._stream.mark(); | |
34 | }; | |
35 | ||
36 | CaseChangingStream.prototype.release = function(marker) { | |
37 | return this._stream.release(marker); | |
38 | }; | |
39 | ||
40 | CaseChangingStream.prototype.seek = function(_index) { | |
41 | return this._stream.seek(_index); | |
42 | }; | |
43 | ||
44 | CaseChangingStream.prototype.getText = function(start, stop) { | |
45 | return this._stream.getText(start, stop); | |
46 | }; | |
47 | ||
48 | CaseChangingStream.prototype.toString = function() { | |
49 | return this._stream.toString(); | |
50 | }; | |
51 | ||
52 | Object.defineProperty(CaseChangingStream.prototype, "index", { | |
53 | get: function() { | |
54 | return this._stream.index; | |
55 | } | |
56 | }); | |
57 | ||
58 | Object.defineProperty(CaseChangingStream.prototype, "size", { | |
59 | get: function() { | |
60 | return this._stream.size; | |
61 | } | |
62 | }); | |
63 | ||
64 | exports.CaseChangingStream = CaseChangingStream; |
0 | class CaseChangingStream(): | |
1 | def __init__(self, stream, upper): | |
2 | self._stream = stream | |
3 | self._upper = upper | |
4 | ||
5 | def __getattr__(self, name): | |
6 | return self._stream.__getattribute__(name) | |
7 | ||
8 | def LA(self, offset): | |
9 | c = self._stream.LA(offset) | |
10 | if c <= 0: | |
11 | return c | |
12 | return ord(chr(c).upper() if self._upper else chr(c).lower()) |
0 | // | |
1 | /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. | |
2 | * Use of this file is governed by the BSD 3-clause license that | |
3 | * can be found in the LICENSE.txt file in the project root. | |
4 | */ | |
5 | // | |
6 | ||
7 | function CaseInsensitiveInputStream(stream, upper) { | |
8 | this._stream = stream; | |
9 | this._case = upper ? String.toUpperCase : String.toLowerCase; | |
10 | return this; | |
11 | } | |
12 | ||
13 | CaseInsensitiveInputStream.prototype.LA = function (offset) { | |
14 | c = this._stream.LA(i); | |
15 | if (c <= 0) { | |
16 | return c; | |
17 | } | |
18 | return this._case.call(String.fromCodePoint(c)) | |
19 | }; | |
20 | ||
21 | CaseInsensitiveInputStream.prototype.reset = function() { | |
22 | return this._stream.reset(); | |
23 | }; | |
24 | ||
25 | CaseInsensitiveInputStream.prototype.consume = function() { | |
26 | return this._stream.consume(); | |
27 | }; | |
28 | ||
29 | CaseInsensitiveInputStream.prototype.LT = function(offset) { | |
30 | return this._stream.LT(offset); | |
31 | }; | |
32 | ||
33 | CaseInsensitiveInputStream.prototype.mark = function() { | |
34 | return this._stream.mark(); | |
35 | }; | |
36 | ||
37 | CaseInsensitiveInputStream.prototype.release = function(marker) { | |
38 | return this._stream.release(marker); | |
39 | }; | |
40 | ||
41 | CaseInsensitiveInputStream.prototype.seek = function(_index) { | |
42 | return this._stream.getText(start, stop); | |
43 | }; | |
44 | ||
45 | CaseInsensitiveInputStream.prototype.getText = function(start, stop) { | |
46 | return this._stream.getText(start, stop); | |
47 | }; | |
48 | ||
49 | CaseInsensitiveInputStream.prototype.toString = function() { | |
50 | return this._stream.toString(); | |
51 | }; | |
52 | ||
53 | exports.CaseInsensitiveInputStream = CaseInsensitiveInputStream; |
0 | package antlr | |
0 | package antlr_resource | |
1 | 1 | |
2 | 2 | import ( |
3 | 3 | "unicode" |
4 | ||
5 | "github.com/antlr/antlr4/runtime/Go/antlr" | |
4 | 6 | ) |
5 | 7 | |
6 | 8 | // CaseChangingStream wraps an existing CharStream, but upper cases, or |
7 | 9 | // lower cases the input before it is tokenized. |
8 | 10 | type CaseChangingStream struct { |
9 | CharStream | |
11 | antlr.CharStream | |
10 | 12 | |
11 | 13 | upper bool |
12 | 14 | } |
14 | 16 | // NewCaseChangingStream returns a new CaseChangingStream that forces |
15 | 17 | // all tokens read from the underlying stream to be either upper case |
16 | 18 | // or lower case based on the upper argument. |
17 | func NewCaseChangingStream(in CharStream, upper bool) *CaseChangingStream { | |
18 | return &CaseChangingStream{ | |
19 | in, upper, | |
20 | } | |
19 | func NewCaseChangingStream(in antlr.CharStream, upper bool) *CaseChangingStream { | |
20 | return &CaseChangingStream{in, upper} | |
21 | 21 | } |
22 | 22 | |
23 | 23 | // LA gets the value of the symbol at offset from the current position |
8 | 8 | * [Go](go-target.md) |
9 | 9 | * [C++](cpp-target.md) |
10 | 10 | * [Swift](swift-target.md) |
11 | * [PHP](php-target.md) | |
12 | * [Dart](dart-target.md) | |
11 | 13 | |
12 | 14 | ## Target feature parity |
13 | 15 | |
14 | 16 | New features generally appear in the Java target and then migrate to the other targets, but these other targets don't always get updated in the same overall tool release. This section tries to identify features added to Java that have not been added to the other targets. |
15 | 17 | |
16 | |Feature|Java|C♯|Python2|Python3|JavaScript|Go|C++|Swift| | |
17 | |---|---|---|---|---|---|---|---|---| | |
18 | |Ambiguous tree construction|4.5.1|-|-|-|-|-|-|-| | |
18 | |Feature|Java|C♯|Python2|Python3|JavaScript|Go|C++|Swift|PHP|Dart | |
19 | |---|---|---|---|---|---|---|---|---|---|---| | |
20 | |Ambiguous tree construction|4.5.1|-|-|-|-|-|-|-|-|-| | |
19 | 21 |
50 | 50 | ``` |
51 | 51 | |
52 | 52 | This would allow pattern `<<ID>> = <<expr>> ;$<< ick $>>` to be interpreted as elements: `ID`, ` = `, `expr`, and ` ;<< ick >>`. |
53 | ||
54 | ```java | |
55 | String xpath = "//blockStatement/*"; | |
56 | String treePattern = "int <Identifier> = <expression>;"; | |
57 | ParseTreePattern p = | |
58 | parser.compileParseTreePattern(treePattern, | |
59 | JavaParser.RULE_localVariableDeclarationStatement); | |
60 | List<ParseTreeMatch> matches = p.findAll(tree, xpath); | |
61 | ``` | |
62 | 53 | |
63 | 54 | ### Pattern labels |
64 | 55 |
12 | 12 | </parent> |
13 | 13 | <groupId>org.antlr</groupId> |
14 | 14 | <artifactId>antlr4-master</artifactId> |
15 | <version>4.7.2</version> | |
15 | <version>4.9.2</version> | |
16 | 16 | <packaging>pom</packaging> |
17 | 17 | |
18 | 18 | <name>ANTLR 4</name> |
150 | 150 | <plugin> |
151 | 151 | <groupId>org.apache.maven.plugins</groupId> |
152 | 152 | <artifactId>maven-compiler-plugin</artifactId> |
153 | <version>3.6.0</version> | |
153 | <version>3.8.1</version> | |
154 | 154 | <configuration> |
155 | 155 | <source>${maven.compiler.source}</source> |
156 | 156 | <target>${maven.compiler.target}</target> |
8 | 8 | <parent> |
9 | 9 | <groupId>org.antlr</groupId> |
10 | 10 | <artifactId>antlr4-master</artifactId> |
11 | <version>4.7.2</version> | |
11 | <version>4.9.2</version> | |
12 | 12 | <relativePath>../../pom.xml</relativePath> |
13 | 13 | </parent> |
14 | 14 | <artifactId>antlr4-runtime</artifactId> |
66 | 66 | * omitted.</li> |
67 | 67 | * </ul> |
68 | 68 | */ |
69 | public static final String VERSION = "4.7.2"; | |
69 | public static final String VERSION = "4.9.2"; | |
70 | 70 | |
71 | 71 | /** |
72 | 72 | * Gets the currently executing version of the ANTLR 4 runtime library. |
156 | 156 | !getMajorMinorVersion(runtimeVersion).equals(getMajorMinorVersion(compileTimeVersion)); |
157 | 157 | |
158 | 158 | if ( runtimeConflictsWithGeneratingTool ) { |
159 | System.err.printf("ANTLR Tool version %s used for code generation does not match the current runtime version %s", | |
159 | System.err.printf("ANTLR Tool version %s used for code generation does not match the current runtime version %s%n", | |
160 | 160 | generatingToolVersion, runtimeVersion); |
161 | 161 | } |
162 | 162 | if ( runtimeConflictsWithCompileTimeTool ) { |
163 | System.err.printf("ANTLR Runtime version %s used for parser compilation does not match the current runtime version %s", | |
163 | System.err.printf("ANTLR Runtime version %s used for parser compilation does not match the current runtime version %s%n", | |
164 | 164 | compileTimeVersion, runtimeVersion); |
165 | 165 | } |
166 | 166 | } |
77 | 77 | |
78 | 78 | protected final SimState prevAccept = new SimState(); |
79 | 79 | |
80 | public static int match_calls = 0; | |
81 | ||
82 | 80 | public LexerATNSimulator(ATN atn, DFA[] decisionToDFA, |
83 | 81 | PredictionContextCache sharedContextCache) |
84 | 82 | { |
102 | 100 | } |
103 | 101 | |
104 | 102 | public int match(CharStream input, int mode) { |
105 | match_calls++; | |
106 | 103 | this.mode = mode; |
107 | 104 | int mark = input.mark(); |
108 | 105 | try { |
6 | 6 | package org.antlr.v4.runtime.tree; |
7 | 7 | |
8 | 8 | import org.antlr.v4.runtime.ParserRuleContext; |
9 | import org.antlr.v4.runtime.RuleContext; | |
10 | 9 | |
11 | 10 | public class ParseTreeWalker { |
12 | 11 | public static final ParseTreeWalker DEFAULT = new ParseTreeWalker(); |
13 | 12 | |
14 | public void walk(ParseTreeListener listener, ParseTree t) { | |
13 | ||
14 | /** | |
15 | * Performs a walk on the given parse tree starting at the root and going down recursively | |
16 | * with depth-first search. On each node, {@link ParseTreeWalker#enterRule} is called before | |
17 | * recursively walking down into child nodes, then | |
18 | * {@link ParseTreeWalker#exitRule} is called after the recursive call to wind up. | |
19 | * @param listener The listener used by the walker to process grammar rules | |
20 | * @param t The parse tree to be walked on | |
21 | */ | |
22 | public void walk(ParseTreeListener listener, ParseTree t) { | |
15 | 23 | if ( t instanceof ErrorNode) { |
16 | 24 | listener.visitErrorNode((ErrorNode)t); |
17 | 25 | return; |
30 | 38 | } |
31 | 39 | |
32 | 40 | /** |
33 | * The discovery of a rule node, involves sending two events: the generic | |
34 | * {@link ParseTreeListener#enterEveryRule} and a | |
35 | * {@link RuleContext}-specific event. First we trigger the generic and then | |
36 | * the rule specific. We to them in reverse order upon finishing the node. | |
41 | * Enters a grammar rule by first triggering the generic event {@link ParseTreeListener#enterEveryRule} | |
42 | * then by triggering the event specific to the given parse tree node | |
43 | * @param listener The listener responding to the trigger events | |
44 | * @param r The grammar rule containing the rule context | |
37 | 45 | */ |
38 | 46 | protected void enterRule(ParseTreeListener listener, RuleNode r) { |
39 | 47 | ParserRuleContext ctx = (ParserRuleContext)r.getRuleContext(); |
41 | 49 | ctx.enterRule(listener); |
42 | 50 | } |
43 | 51 | |
44 | protected void exitRule(ParseTreeListener listener, RuleNode r) { | |
52 | ||
53 | /** | |
54 | * Exits a grammar rule by first triggering the event specific to the given parse tree node | |
55 | * then by triggering the generic event {@link ParseTreeListener#exitEveryRule} | |
56 | * @param listener The listener responding to the trigger events | |
57 | * @param r The grammar rule containing the rule context | |
58 | */ | |
59 | protected void exitRule(ParseTreeListener listener, RuleNode r) { | |
45 | 60 | ParserRuleContext ctx = (ParserRuleContext)r.getRuleContext(); |
46 | 61 | ctx.exitRule(listener); |
47 | 62 | listener.exitEveryRule(ctx); |
18 | 18 | Tree getParent(); |
19 | 19 | |
20 | 20 | /** |
21 | * This method returns whatever object represents the data at this note. For | |
21 | * This method returns whatever object represents the data at this node. For | |
22 | 22 | * example, for parse trees, the payload can be a {@link Token} representing |
23 | 23 | * a leaf node or a {@link RuleContext} object representing a rule |
24 | 24 | * invocation. For abstract syntax trees (ASTs), this is a {@link Token} |
8 | 8 | <parent> |
9 | 9 | <groupId>org.antlr</groupId> |
10 | 10 | <artifactId>antlr4-master</artifactId> |
11 | <version>4.7.2</version> | |
11 | <version>4.9.2</version> | |
12 | 12 | <relativePath>../../pom.xml</relativePath> |
13 | 13 | </parent> |
14 | 14 | <artifactId>antlr4-runtime-test-annotations</artifactId> |
9 | 9 | <parent> |
10 | 10 | <groupId>org.antlr</groupId> |
11 | 11 | <artifactId>antlr4-master</artifactId> |
12 | <version>4.7.2</version> | |
12 | <version>4.9.2</version> | |
13 | 13 | </parent> |
14 | 14 | <artifactId>antlr4-runtime-testsuite</artifactId> |
15 | 15 | <name>ANTLR 4 Runtime Tests (2nd generation)</name> |
25 | 25 | <dependency> |
26 | 26 | <groupId>org.antlr</groupId> |
27 | 27 | <artifactId>ST4</artifactId> |
28 | <version>4.1</version> | |
28 | <version>4.3</version> | |
29 | 29 | <scope>test</scope> |
30 | 30 | </dependency> |
31 | 31 | <dependency> |
55 | 55 | <dependency> |
56 | 56 | <groupId>junit</groupId> |
57 | 57 | <artifactId>junit</artifactId> |
58 | <version>4.12</version> | |
58 | <version>4.13.1</version> | |
59 | 59 | <scope>test</scope> |
60 | </dependency> | |
61 | <dependency> | |
62 | <groupId>org.seleniumhq.selenium</groupId> | |
63 | <artifactId>selenium-java</artifactId> | |
64 | <version>2.46.0</version> | |
65 | <scope>test</scope> | |
66 | </dependency> | |
67 | <dependency> | |
68 | <groupId>org.eclipse.jetty</groupId> | |
69 | <artifactId>jetty-server</artifactId> | |
70 | <version>[9.3.24.v20180605,)</version> | |
71 | <scope>test</scope> | |
72 | 60 | </dependency> |
73 | 61 | <dependency> |
74 | 62 | <groupId>org.glassfish</groupId> |
107 | 95 | <!-- SUREFIRE-951: file.encoding cannot be set via systemPropertyVariables --> |
108 | 96 | <argLine>-Dfile.encoding=UTF-8</argLine> |
109 | 97 | <includes> |
110 | <include>**/csharp/Test*.java</include> | |
111 | <include>**/java/Test*.java</include> | |
112 | <include>**/go/Test*.java</include> | |
113 | <include>**/javascript/node/Test*.java</include> | |
114 | <include>**/python2/Test*.java</include> | |
115 | <include>**/python3/Test*.java</include> | |
116 | <include>${antlr.tests.swift}</include> | |
117 | </includes> | |
98 | <include>**/csharp/Test*.java</include> | |
99 | <include>**/java/Test*.java</include> | |
100 | <include>**/go/Test*.java</include> | |
101 | <include>**/javascript/Test*.java</include> | |
102 | <include>**/python2/Test*.java</include> | |
103 | <include>**/python3/Test*.java</include> | |
104 | <include>**/php/Test*.java</include> | |
105 | <include>**/dart/Test*.java</include> | |
106 | <include>${antlr.tests.swift}</include> | |
107 | </includes> | |
118 | 108 | </configuration> |
119 | 109 | </plugin> |
120 | 110 | <plugin> |
8 | 8 | <parent> |
9 | 9 | <groupId>org.antlr</groupId> |
10 | 10 | <artifactId>antlr4-master</artifactId> |
11 | <version>4.7.2</version> | |
11 | <version>4.9.2</version> | |
12 | 12 | <relativePath>../../pom.xml</relativePath> |
13 | 13 | </parent> |
14 | 14 | <artifactId>antlr4-runtime-test-annotation-processors</artifactId> |
+20
-6
5 | 5 | |
6 | 6 | package org.antlr.v4.test.runtime; |
7 | 7 | |
8 | import com.sun.tools.javac.main.JavaCompiler; | |
8 | 9 | import com.sun.tools.javac.model.JavacElements; |
9 | import com.sun.tools.javac.processing.JavacProcessingEnvironment; | |
10 | 10 | import com.sun.tools.javac.tree.JCTree; |
11 | 11 | import com.sun.tools.javac.tree.TreeMaker; |
12 | import com.sun.tools.javac.util.Context; | |
12 | 13 | import com.sun.tools.javac.util.List; |
13 | 14 | |
14 | 15 | import javax.annotation.processing.AbstractProcessor; |
19 | 20 | import javax.lang.model.SourceVersion; |
20 | 21 | import javax.lang.model.element.Element; |
21 | 22 | import javax.lang.model.element.TypeElement; |
23 | import java.lang.reflect.Field; | |
22 | 24 | import java.util.Set; |
23 | 25 | |
24 | 26 | /** |
37 | 39 | @SupportedAnnotationTypes({"org.antlr.v4.test.runtime.CommentHasStringValue"}) |
38 | 40 | @SupportedSourceVersion(SourceVersion.RELEASE_7) |
39 | 41 | public class CommentHasStringValueProcessor extends AbstractProcessor { |
42 | ||
40 | 43 | protected JavacElements utilities; |
41 | 44 | protected TreeMaker treeMaker; |
42 | 45 | |
45 | 48 | super.init(processingEnv); |
46 | 49 | // Messager messager = processingEnv.getMessager(); |
47 | 50 | // messager.printMessage(Diagnostic.Kind.NOTE, "WOW INIT--------------------"); |
48 | JavacProcessingEnvironment javacProcessingEnv = (JavacProcessingEnvironment) processingEnv; | |
49 | utilities = javacProcessingEnv.getElementUtils(); | |
50 | treeMaker = TreeMaker.instance(javacProcessingEnv.getContext()); | |
51 | utilities = (JavacElements)processingEnv.getElementUtils(); | |
52 | treeMaker = TreeMaker.instance(extractContext(utilities)); | |
53 | } | |
54 | ||
55 | private static Context extractContext(JavacElements utilities) { | |
56 | try { | |
57 | Field compilerField = JavacElements.class.getDeclaredField("javaCompiler"); | |
58 | compilerField.setAccessible(true); | |
59 | JavaCompiler compiler = (JavaCompiler)compilerField.get(utilities); | |
60 | Field contextField = JavaCompiler.class.getDeclaredField("context"); | |
61 | contextField.setAccessible(true); | |
62 | return (Context)contextField.get(compiler); | |
63 | } catch (NoSuchFieldException | IllegalAccessException e) { | |
64 | throw new IllegalStateException(e); | |
65 | } | |
51 | 66 | } |
52 | 67 | |
53 | 68 | @Override |
65 | 80 | else if ( elementTree instanceof JCTree.JCMethodDecl ) { |
66 | 81 | JCTree.JCStatement[] statements = new JCTree.JCStatement[1]; |
67 | 82 | statements[0] = treeMaker.Return(literal); |
68 | JCTree.JCBlock body = treeMaker.Block(0, List.from(statements)); | |
69 | ((JCTree.JCMethodDecl)elementTree).body = body; | |
83 | ((JCTree.JCMethodDecl)elementTree).body = treeMaker.Block(0, List.from(statements)); | |
70 | 84 | } |
71 | 85 | } |
72 | 86 | return true; |
4 | 4 | from collections import Counter |
5 | 5 | import sys |
6 | 6 | |
7 | TARGETS = ['csharp', 'cpp', 'go', 'java', 'javascript', 'python2', 'python3', 'swift'] | |
7 | TARGETS = ['csharp', 'cpp', 'go', 'java', 'javascript', 'python2', 'python3', 'swift', 'php', 'dart'] | |
8 | 8 | |
9 | 9 | TOKEN=sys.argv[1] |
10 | 10 | MILESTONE=sys.argv[2] |
8 | 8 | <parent> |
9 | 9 | <groupId>org.antlr</groupId> |
10 | 10 | <artifactId>antlr4-master</artifactId> |
11 | <version>4.7.2</version> | |
11 | <version>4.9.2</version> | |
12 | 12 | </parent> |
13 | 13 | <artifactId>antlr4</artifactId> |
14 | 14 | <name>ANTLR 4 Tool</name> |
28 | 28 | <dependency> |
29 | 29 | <groupId>org.antlr</groupId> |
30 | 30 | <artifactId>ST4</artifactId> |
31 | <version>4.1</version> | |
31 | <version>4.3</version> | |
32 | 32 | </dependency> |
33 | 33 | <dependency> |
34 | 34 | <groupId>org.abego.treelayout</groupId> |
115 | 115 | /// of the available methods. |
116 | 116 | /// \</summary> |
117 | 117 | [System.CodeDom.Compiler.GeneratedCode("ANTLR", "<file.ANTLRVersion>")] |
118 | [System.Diagnostics.DebuggerNonUserCode] | |
118 | 119 | [System.CLSCompliant(false)] |
119 | 120 | public partial class <file.grammarName>BaseListener : I<file.grammarName>Listener { |
120 | 121 | <file.listenerNames:{lname | |
213 | 214 | /// \</summary> |
214 | 215 | /// \<typeparam name="Result">The return type of the visit operation.\</typeparam> |
215 | 216 | [System.CodeDom.Compiler.GeneratedCode("ANTLR", "<file.ANTLRVersion>")] |
217 | [System.Diagnostics.DebuggerNonUserCode] | |
216 | 218 | [System.CLSCompliant(false)] |
217 | 219 | public partial class <file.grammarName>BaseVisitor\<Result> : AbstractParseTreeVisitor\<Result>, I<file.grammarName>Visitor\<Result> { |
218 | 220 | <file.visitorNames:{lname | |
275 | 277 | public const int |
276 | 278 | <parser.tokens:{k | <k>=<parser.tokens.(k)>}; separator=", ", wrap, anchor>; |
277 | 279 | <endif> |
280 | <if(parser.rules)> | |
278 | 281 | public const int |
279 | 282 | <parser.rules:{r | RULE_<r.name> = <r.index>}; separator=", ", wrap, anchor>; |
283 | <endif> | |
280 | 284 | public static readonly string[] ruleNames = { |
281 | 285 | <parser.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> |
282 | 286 | }; |
703 | 707 | >> |
704 | 708 | |
705 | 709 | InvokeRule(r, argExprsChunks) ::= << |
706 | State = <r.stateNumber>; <if(r.labels)><r.labels:{l | <labelref(l)> = }><endif><csIdentifier.(r.name)>(<if(r.ast.options.p)><r.ast.options.p><if(argExprsChunks)>,<endif><endif><argExprsChunks>); | |
710 | State = <r.stateNumber>; | |
711 | <if(r.labels)><r.labels:{l | <labelref(l)> = }><endif><csIdentifier.(r.name)>(<if(r.ast.options.p)><r.ast.options.p><if(argExprsChunks)>,<endif><endif><argExprsChunks>); | |
707 | 712 | >> |
708 | 713 | |
709 | 714 | MatchToken(m) ::= << |
710 | State = <m.stateNumber>; <if(m.labels)><m.labels:{l | <labelref(l)> = }><endif>Match(<tokenType.(m.name)>); | |
715 | State = <m.stateNumber>; | |
716 | <if(m.labels)><m.labels:{l | <labelref(l)> = }><endif>Match(<tokenType.(m.name)>); | |
711 | 717 | >> |
712 | 718 | |
713 | 719 | MatchSet(m, expr, capture) ::= "<CommonSetStuff(m, expr, capture, false)>" |
812 | 818 | %> |
813 | 819 | |
814 | 820 | ContextTokenGetterDecl(t) ::= |
815 | "public ITerminalNode <csIdentifier.(tokenType.(t.name))>() { return GetToken(<csIdentifier.(parser.name)>.<csIdentifier.(tokenType.(t.name))>, 0); }" | |
821 | "[System.Diagnostics.DebuggerNonUserCode] public ITerminalNode <csIdentifier.(tokenType.(t.name))>() { return GetToken(<csIdentifier.(parser.name)>.<csIdentifier.(tokenType.(t.name))>, 0); }" | |
816 | 822 | ContextTokenListGetterDecl(t) ::= << |
817 | public <contextGetterCollection("ITerminalNode")> <csIdentifier.(tokenType.(t.name))>() { return GetTokens(<csIdentifier.(parser.name)>.<csIdentifier.(tokenType.(t.name))>); } | |
823 | [System.Diagnostics.DebuggerNonUserCode] public <contextGetterCollection("ITerminalNode")> <csIdentifier.(tokenType.(t.name))>() { return GetTokens(<csIdentifier.(parser.name)>.<csIdentifier.(tokenType.(t.name))>); } | |
818 | 824 | >> |
819 | 825 | ContextTokenListIndexedGetterDecl(t) ::= << |
820 | public ITerminalNode <csIdentifier.(tokenType.(t.name))>(int i) { | |
826 | [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode <csIdentifier.(tokenType.(t.name))>(int i) { | |
821 | 827 | return GetToken(<csIdentifier.(parser.name)>.<csIdentifier.(tokenType.(t.name))>, i); |
822 | 828 | } |
823 | 829 | >> |
824 | 830 | ContextRuleGetterDecl(r) ::= << |
825 | public <r.ctxName> <csIdentifier.(r.name)>() { | |
831 | [System.Diagnostics.DebuggerNonUserCode] public <r.ctxName> <csIdentifier.(r.name)>() { | |
826 | 832 | return GetRuleContext\<<r.ctxName>\>(0); |
827 | 833 | } |
828 | 834 | >> |
829 | 835 | ContextRuleListGetterDecl(r) ::= << |
830 | public <contextGetterCollection({<r.ctxName>})> <csIdentifier.(r.name)>() { | |
836 | [System.Diagnostics.DebuggerNonUserCode] public <contextGetterCollection({<r.ctxName>})> <csIdentifier.(r.name)>() { | |
831 | 837 | return GetRuleContexts\<<r.ctxName>\>(); |
832 | 838 | } |
833 | 839 | >> |
834 | 840 | ContextRuleListIndexedGetterDecl(r) ::= << |
835 | public <r.ctxName> <csIdentifier.(r.name)>(int i) { | |
841 | [System.Diagnostics.DebuggerNonUserCode] public <r.ctxName> <csIdentifier.(r.name)>(int i) { | |
836 | 842 | return GetRuleContext\<<r.ctxName>\>(i); |
837 | 843 | } |
838 | 844 | >> |
886 | 892 | >> |
887 | 893 | |
888 | 894 | ListenerDispatchMethod(method) ::= << |
895 | [System.Diagnostics.DebuggerNonUserCode] | |
889 | 896 | public override void <if(method.isEnter)>Enter<else>Exit<endif>Rule(IParseTreeListener listener) { |
890 | 897 | I<parser.grammarName>Listener typedListener = listener as I<parser.grammarName>Listener; |
891 | 898 | if (typedListener != null) typedListener.<if(method.isEnter)>Enter<else>Exit<endif><struct.derivedFromName; format="cap">(this); |
893 | 900 | >> |
894 | 901 | |
895 | 902 | VisitorDispatchMethod(method) ::= << |
903 | [System.Diagnostics.DebuggerNonUserCode] | |
896 | 904 | public override TResult Accept\<TResult>(IParseTreeVisitor\<TResult> visitor) { |
897 | 905 | I<parser.grammarName>Visitor\<TResult> typedVisitor = visitor as I<parser.grammarName>Visitor\<TResult>; |
898 | 906 | if (typedVisitor != null) return typedVisitor.Visit<struct.derivedFromName; format="cap">(this); |
979 | 987 | public partial class <csIdentifier.(lexer.name)> : <superClass; null="Lexer"> { |
980 | 988 | protected static DFA[] decisionToDFA; |
981 | 989 | protected static PredictionContextCache sharedContextCache = new PredictionContextCache(); |
990 | <if(lexer.tokens)> | |
982 | 991 | public const int |
983 | 992 | <lexer.tokens:{k | <tokenType.(k)>=<lexer.tokens.(k)>}; separator=", ", wrap, anchor>; |
993 | <endif> | |
984 | 994 | <if(lexer.channels)> |
985 | 995 | public const int |
986 | 996 | <lexer.channels:{k | <csIdentifier.(k)>=<lexer.channels.(k)>}; separator=", ", wrap, anchor>; |
62 | 62 | }; |
63 | 63 | <endif> |
64 | 64 | |
65 | <lexer.name>(antlr4::CharStream *input); | |
65 | explicit <lexer.name>(antlr4::CharStream *input); | |
66 | 66 | ~<lexer.name>(); |
67 | 67 | |
68 | 68 | <namedActions.members> |
191 | 191 | std::vector\<uint16_t> <lexer.name>::_serializedATN; |
192 | 192 | |
193 | 193 | std::vector\<std::string> <lexer.name>::_ruleNames = { |
194 | <lexer.ruleNames: {r | u8"<r>"}; separator = ", ", wrap, anchor> | |
194 | <lexer.ruleNames: {r | "<r>"}; separator = ", ", wrap, anchor> | |
195 | 195 | }; |
196 | 196 | |
197 | 197 | std::vector\<std::string> <lexer.name>::_channelNames = { |
198 | "DEFAULT_TOKEN_CHANNEL", "HIDDEN"<if (lexer.channels)>, <lexer.channels: {c | u8"<c>"}; separator = ", ", wrap, anchor><endif> | |
198 | "DEFAULT_TOKEN_CHANNEL", "HIDDEN"<if (lexer.channels)>, <lexer.channels: {c | "<c>"}; separator = ", ", wrap, anchor><endif> | |
199 | 199 | }; |
200 | 200 | |
201 | 201 | std::vector\<std::string> <lexer.name>::_modeNames = { |
202 | <lexer.modes: {m | u8"<m>"}; separator = ", ", wrap, anchor> | |
202 | <lexer.modes: {m | "<m>"}; separator = ", ", wrap, anchor> | |
203 | 203 | }; |
204 | 204 | |
205 | 205 | std::vector\<std::string> <lexer.name>::_literalNames = { |
206 | <lexer.literalNames: {t | u8<t>}; null = "\"\"", separator = ", ", wrap, anchor> | |
206 | <lexer.literalNames: {t | <t>}; null = "\"\"", separator = ", ", wrap, anchor> | |
207 | 207 | }; |
208 | 208 | |
209 | 209 | std::vector\<std::string> <lexer.name>::_symbolicNames = { |
210 | <lexer.symbolicNames: {t | u8<t>}; null = "\"\"", separator = ", ", wrap, anchor> | |
210 | <lexer.symbolicNames: {t | <t>}; null = "\"\"", separator = ", ", wrap, anchor> | |
211 | 211 | }; |
212 | 212 | |
213 | 213 | dfa::Vocabulary <lexer.name>::_vocabulary(_literalNames, _symbolicNames); |
283 | 283 | }; |
284 | 284 | <endif> |
285 | 285 | |
286 | <if (parser.tokens)> | |
286 | <if (parser.rules)> | |
287 | 287 | enum { |
288 | 288 | <parser.rules: {r | Rule<r.name; format="cap"> = <r.index>}; separator=", ", wrap, anchor> |
289 | 289 | }; |
290 | 290 | <endif> |
291 | 291 | |
292 | <parser.name>(antlr4::TokenStream *input); | |
292 | explicit <parser.name>(antlr4::TokenStream *input); | |
293 | 293 | ~<parser.name>(); |
294 | 294 | |
295 | 295 | virtual std::string getGrammarFileName() const override; |
421 | 421 | |
422 | 422 | // Constructs the serialized ATN and writes init code for static member vars. |
423 | 423 | SerializedATN(model) ::= << |
424 | <if (rest(model.segments))> | |
425 | <model.segments: {segment | static uint16_t serializedATNSegment<i0>[] = { | |
424 | <model.segments: {segment | static const uint16_t serializedATNSegment<i0>[] = { | |
426 | 425 | <segment; wrap={<\n> }> |
427 | 426 | \};}; separator="\n"> |
428 | 427 | |
429 | 428 | <model.segments: {segment | _serializedATN.insert(_serializedATN.end(), serializedATNSegment<i0>, |
430 | 429 | serializedATNSegment<i0> + sizeof(serializedATNSegment<i0>) / sizeof(serializedATNSegment<i0>[0])); |
431 | 430 | }> |
432 | ||
433 | <else> | |
434 | <! only one segment, can be inlined !> | |
435 | _serializedATN = { | |
436 | <model.serialized; wrap = {<\n>}> | |
437 | }; | |
438 | <endif> | |
439 | 431 | |
440 | 432 | atn::ATNDeserializer deserializer; |
441 | 433 | _atn = deserializer.deserialize(_serializedATN); |
463 | 455 | <namedActions.init> |
464 | 456 | <locals; separator = "\n"> |
465 | 457 | |
458 | #if __cplusplus > 201703L | |
459 | auto onExit = finally([=, this] { | |
460 | #else | |
466 | 461 | auto onExit = finally([=] { |
462 | #endif | |
467 | 463 | <finallyAction> |
468 | 464 | exitRule(); |
469 | 465 | }); |
516 | 512 | <namedActions.init> |
517 | 513 | <! TODO: untested !> <locals; separator = "\n"> |
518 | 514 | |
515 | #if __cplusplus > 201703L | |
516 | auto onExit = finally([=, this] { | |
517 | #else | |
519 | 518 | auto onExit = finally([=] { |
519 | #endif | |
520 | 520 | <if (finallyAction)><finallyAction><endif> |
521 | 521 | unrollRecursionContexts(parentContext); |
522 | 522 | }); |
538 | 538 | StructDeclHeader(struct, ctorAttrs, attrs, getters, dispatchMethods, interfaces, extensionMembers) ::= << |
539 | 539 | class <file.exportMacro> <struct.name> : public <if (contextSuperClass)><contextSuperClass><else>antlr4::ParserRuleContext<endif><if(interfaces)>, <interfaces; separator=", "><endif> { |
540 | 540 | public: |
541 | <attrs: {a | <a>;}; separator="\n"> | |
541 | <attrs: {a | <a>;}; separator = "\n"> | |
542 | 542 | <if (ctorAttrs)><struct.name>(antlr4::ParserRuleContext *parent, size_t invokingState);<endif> |
543 | 543 | <struct.name>(antlr4::ParserRuleContext *parent, size_t invokingState<ctorAttrs: {a | , <a>}>); |
544 | 544 | <if (struct.provideCopyFrom)> <! don't need copy unless we have subclasses !> |
592 | 592 | public: |
593 | 593 | <struct.name>(<currentRule.name; format = "cap">Context *ctx); |
594 | 594 | |
595 | <if (attrs)><attrs: {a | <a>}; separator = "\n"><endif> | |
595 | <if (attrs)><attrs: {a | <a>;}; separator = "\n"><endif> | |
596 | 596 | <getters: {g | <g>}; separator = "\n"> |
597 | 597 | <dispatchMethods; separator = "\n"> |
598 | 598 | }; |
709 | 709 | break; |
710 | 710 | \} |
711 | 711 | }; separator="\n"> |
712 | default: | |
713 | break; | |
712 | 714 | } |
713 | 715 | >> |
714 | 716 | |
723 | 725 | break; |
724 | 726 | \} |
725 | 727 | }; separator = "\n"> |
728 | default: | |
729 | break; | |
726 | 730 | } |
727 | 731 | >> |
728 | 732 | |
960 | 964 | |
961 | 965 | TokenLabelType() ::= "<file.TokenLabelType; null = {Token}> *" |
962 | 966 | |
963 | TokenDeclHeader(t) ::= "antlr4::<TokenLabelType()><t.name> = nullptr;" | |
967 | TokenDeclHeader(t) ::= "antlr4::<TokenLabelType()><t.name> = nullptr" | |
964 | 968 | TokenDecl(t) ::= "<! Variable Declaration !>" |
965 | 969 | |
966 | 970 | TokenTypeDeclHeader(t) ::= "<! Local Variable !>" |
967 | 971 | TokenTypeDecl(t) ::= "size_t <t.name> = 0;" |
968 | 972 | |
969 | TokenListDeclHeader(t) ::= "std::vector\<antlr4::Token *> <t.name>;" | |
973 | TokenListDeclHeader(t) ::= "std::vector\<antlr4::Token *> <t.name>" | |
970 | 974 | TokenListDecl(t) ::= "<! Variable Declaration !>" |
971 | 975 | |
972 | RuleContextDeclHeader(r) ::= "<parser.name>::<r.ctxName> *<r.name> = nullptr;" | |
976 | RuleContextDeclHeader(r) ::= "<parser.name>::<r.ctxName> *<r.name> = nullptr" | |
973 | 977 | RuleContextDecl(r) ::= "<! Variable Declaration !>" |
974 | 978 | |
975 | RuleContextListDeclHeader(rdecl) ::= "std::vector\<<rdecl.ctxName> *> <rdecl.name>;" | |
979 | RuleContextListDeclHeader(rdecl) ::= "std::vector\<<rdecl.ctxName> *> <rdecl.name>" | |
976 | 980 | RuleContextListDecl(rdecl) ::= "<! Variable Declaration !>" |
977 | 981 | |
978 | 982 | ContextTokenGetterDeclHeader(t) ::= "antlr4::tree::TerminalNode *<t.name>();" |
0 | /* | |
1 | * [The "BSD license"] | |
2 | * Copyright (c) 2012 Terence Parr | |
3 | * Copyright (c) 2012 Sam Harwell | |
4 | * Copyright (c) 2014 Tiago Mazzutti | |
5 | * Copyright (c) 2017 Tobe Osakwe | |
6 | * Copyright (c) 2020 Larry Li | |
7 | * All rights reserved. | |
8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | |
12 | * | |
13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * 3. The name of the author may not be used to endorse or promote products | |
19 | * derived from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
22 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
23 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
24 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
26 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
30 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 | */ | |
32 | ||
33 | dartTypeInitMap ::= [ | |
34 | "int":"0", | |
35 | "double":"0.0", | |
36 | "bool":"false", | |
37 | default:"null" // anything other than a primitive type is an object | |
38 | ] | |
39 | ||
40 | // args must be <object-model-object>, <fields-resulting-in-STs> | |
41 | ||
42 | ParserFile(file, parser, namedActions, contextSuperClass) ::= << | |
43 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> | |
44 | <if(file.genPackage)> | |
45 | library <file.genPackage>; | |
46 | ||
47 | import 'package:antlr4/antlr4.dart'; | |
48 | import 'dart:io'; | |
49 | ||
50 | <if(file.genListener)> | |
51 | part '<file.grammarName>Listener.dart'; | |
52 | part '<file.grammarName>BaseListener.dart'; | |
53 | <endif> | |
54 | <if(file.genVisitor)> | |
55 | part '<file.grammarName>Visitor.dart'; | |
56 | part '<file.grammarName>BaseVisitor.dart'; | |
57 | <endif> | |
58 | part '<file.grammarName>Lexer.dart'; | |
59 | <else> | |
60 | import 'package:antlr4/antlr4.dart'; | |
61 | import 'dart:io'; | |
62 | ||
63 | <if(file.genListener)> | |
64 | import '<file.grammarName>Listener.dart'; | |
65 | import '<file.grammarName>BaseListener.dart'; | |
66 | <endif> | |
67 | <if(file.genVisitor)> | |
68 | import '<file.grammarName>Visitor.dart'; | |
69 | import '<file.grammarName>BaseVisitor.dart'; | |
70 | <endif> | |
71 | <endif> | |
72 | ||
73 | <namedActions.header> | |
74 | <parser> | |
75 | >> | |
76 | ||
77 | ListenerFile(file, header, namedActions) ::= << | |
78 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> | |
79 | <if(file.genPackage)> | |
80 | part of <file.genPackage>; | |
81 | <else> | |
82 | import 'package:antlr4/antlr4.dart'; | |
83 | ||
84 | import '<file.parserName>.dart'; | |
85 | <endif> | |
86 | <header> | |
87 | ||
88 | /// This abstract class defines a complete listener for a parse tree produced by | |
89 | /// [<file.parserName>]. | |
90 | abstract class <file.grammarName>Listener extends ParseTreeListener { | |
91 | <file.listenerNames:{lname | | |
92 | <if(file.listenerLabelRuleNames.(lname))> | |
93 | /// Enter a parse tree produced by the [<lname>] | |
94 | /// labeled alternative in [file.parserName>.<file.listenerLabelRuleNames.(lname)>]. | |
95 | <else> | |
96 | /// Enter a parse tree produced by [<file.parserName>.<lname>]. | |
97 | <endif> | |
98 | /// [ctx] the parse tree | |
99 | void enter<lname; format="cap">(<lname; format="cap">Context ctx); | |
100 | <if(file.listenerLabelRuleNames.(lname))> | |
101 | /// Exit a parse tree produced by the [<lname>] | |
102 | /// labeled alternative in [<file.parserName>.<file.listenerLabelRuleNames.(lname)>]. | |
103 | <else> | |
104 | /// Exit a parse tree produced by [<file.parserName>.<lname>]. | |
105 | <endif> | |
106 | /// [ctx] the parse tree | |
107 | void exit<lname; format="cap">(<lname; format="cap">Context ctx);}; separator="\n"> | |
108 | } | |
109 | >> | |
110 | ||
111 | BaseListenerFile(file, header, namedActions) ::= << | |
112 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> | |
113 | <if(file.genPackage)> | |
114 | part of <file.genPackage>; | |
115 | <else> | |
116 | import 'package:antlr4/antlr4.dart'; | |
117 | ||
118 | import '<file.parserName>.dart'; | |
119 | import '<file.grammarName>Listener.dart'; | |
120 | <endif> | |
121 | ||
122 | <header> | |
123 | ||
124 | /// This class provides an empty implementation of [<file.grammarName>Listener], | |
125 | /// which can be extended to create a listener which only needs to handle | |
126 | /// a subset of the available methods. | |
127 | class <file.grammarName>BaseListener implements <file.grammarName>Listener { | |
128 | <file.listenerNames:{lname | | |
129 | ||
130 | /// The default implementation does nothing. | |
131 | @override | |
132 | void enter<lname; format="cap">(<lname; format="cap">Context ctx) {\} | |
133 | ||
134 | /// The default implementation does nothing. | |
135 | @override | |
136 | void exit<lname; format="cap">(<lname; format="cap">Context ctx) {\}}; separator="\n"> | |
137 | ||
138 | /// The default implementation does nothing. | |
139 | @override | |
140 | void enterEveryRule(ParserRuleContext ctx) {} | |
141 | ||
142 | /// The default implementation does nothing. | |
143 | @override | |
144 | void exitEveryRule(ParserRuleContext ctx) {} | |
145 | ||
146 | /// The default implementation does nothing. | |
147 | @override | |
148 | void visitTerminal(TerminalNode node) {} | |
149 | ||
150 | /// The default implementation does nothing. | |
151 | @override | |
152 | void visitErrorNode(ErrorNode node) {} | |
153 | } | |
154 | ||
155 | >> | |
156 | ||
157 | VisitorFile(file, header, namedActions) ::= << | |
158 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> | |
159 | <if(file.genPackage)> | |
160 | part of <file.genPackage>; | |
161 | <else> | |
162 | import 'package:antlr4/antlr4.dart'; | |
163 | ||
164 | import '<file.parserName>.dart'; | |
165 | <endif> | |
166 | <header> | |
167 | ||
168 | /// This abstract class defines a complete generic visitor for a parse tree | |
169 | /// produced by [<file.parserName>]. | |
170 | /// | |
171 | /// [T] is the eturn type of the visit operation. Use `void` for | |
172 | /// operations with no return type. | |
173 | abstract class <file.grammarName>Visitor\<T> extends ParseTreeVisitor\<T> { | |
174 | <file.visitorNames:{lname | | |
175 | <if(file.visitorLabelRuleNames.(lname))> | |
176 | /// Visit a parse tree produced by the {@code <lname>\} | |
177 | /// labeled alternative in {@link <file.parserName>#<file.visitorLabelRuleNames.(lname)>\}. | |
178 | <else> | |
179 | /// Visit a parse tree produced by [<file.parserName>.<lname>]. | |
180 | <endif> | |
181 | /// [ctx] the parse tree. | |
182 | /// Return the visitor result. | |
183 | T visit<lname; format="cap">(<lname; format="cap">Context ctx);}; separator="\n"> | |
184 | } | |
185 | >> | |
186 | ||
187 | BaseVisitorFile(file, header, namedActions) ::= << | |
188 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> | |
189 | <if(file.genPackage)> | |
190 | part of <file.genPackage>; | |
191 | <else> | |
192 | import 'package:antlr4/antlr4.dart'; | |
193 | ||
194 | import '<file.parserName>.dart'; | |
195 | import '<file.grammarName>Visitor.dart'; | |
196 | <endif> | |
197 | <header> | |
198 | ||
199 | /// This class provides an empty implementation of [<file.grammarName>Visitor], | |
200 | /// which can be extended to create a visitor which only needs to handle | |
201 | /// a subset of the available methods. | |
202 | /// | |
203 | /// [T] is the return type of the visit operation. Use `void` for | |
204 | /// operations with no return type. | |
205 | class <file.grammarName>BaseVisitor\<T> extends ParseTreeVisitor\<T> implements <file.grammarName>Visitor\<T> { | |
206 | <file.visitorNames:{lname | | |
207 | /// The default implementation returns the result of calling | |
208 | /// [visitChildren] on [ctx]. | |
209 | @override | |
210 | T visit<lname; format="cap">(<lname; format="cap">Context ctx) => visitChildren(ctx);}; separator="\n"> | |
211 | } | |
212 | >> | |
213 | ||
214 | fileHeader(grammarFileName, ANTLRVersion) ::= << | |
215 | // Generated from <grammarFileName> by ANTLR <ANTLRVersion> | |
216 | // ignore_for_file: unused_import, unused_local_variable, prefer_single_quotes | |
217 | >> | |
218 | ||
219 | Parser(parser, funcs, atn, sempredFuncs, superClass) ::= << | |
220 | <Parser_(ctor="parser_ctor", ...)> | |
221 | >> | |
222 | ||
223 | Parser_(parser, funcs, atn, sempredFuncs, ctor, superClass) ::= << | |
224 | <if(namedActions.definitions)><namedActions.definitions><endif> | |
225 | <if(parser.rules)> | |
226 | const int <parser.rules:{r | RULE_<r.name> = <r.index>}; separator=", ", wrap, anchor>; | |
227 | <endif> | |
228 | class <parser.name> extends <superClass; null="Parser"> { | |
229 | static final checkVersion = () => RuntimeMetaData.checkVersion('<file.ANTLRVersion>', RuntimeMetaData.VERSION); | |
230 | static const int TOKEN_EOF = IntStream.EOF; | |
231 | ||
232 | static final List\<DFA> _decisionToDFA = List.generate( | |
233 | _ATN.numberOfDecisions, (i) => DFA(_ATN.getDecisionState(i), i)); | |
234 | static final PredictionContextCache _sharedContextCache = PredictionContextCache(); | |
235 | <if(parser.tokens)> | |
236 | static const int <parser.tokens:{k | TOKEN_<k> = <parser.tokens.(k)>}; separator=", ", wrap, anchor>; | |
237 | <endif> | |
238 | ||
239 | @override | |
240 | final List\<String> ruleNames = [ | |
241 | <parser.ruleNames:{r | '<r>'}; separator=", ", wrap, anchor> | |
242 | ]; | |
243 | ||
244 | <vocabulary(parser.literalNames, parser.symbolicNames)> | |
245 | ||
246 | @override | |
247 | String get grammarFileName => '<parser.grammarFileName>'; | |
248 | ||
249 | @override | |
250 | String get serializedATN => _serializedATN; | |
251 | ||
252 | @override | |
253 | ATN getATN() { | |
254 | return _ATN; | |
255 | } | |
256 | ||
257 | <namedActions.members> | |
258 | <parser:(ctor)()> | |
259 | <funcs; separator="\n"> | |
260 | ||
261 | <if(sempredFuncs)> | |
262 | @override | |
263 | bool sempred(RuleContext _localctx, int ruleIndex, int predIndex) { | |
264 | switch (ruleIndex) { | |
265 | <parser.sempredFuncs.values:{f| | |
266 | case <f.ruleIndex>: | |
267 | return _<f.name>_sempred(_localctx, predIndex);}; separator="\n"> | |
268 | } | |
269 | return true; | |
270 | } | |
271 | <sempredFuncs.values; separator="\n"> | |
272 | <endif> | |
273 | ||
274 | <atn> | |
275 | } | |
276 | <funcs:{func | <if(func.ruleCtx)><func.ruleCtx><endif>}; separator="\n\n"> | |
277 | ||
278 | <funcs:{func | <if(func.altLabelCtxs)><func.altLabelCtxs:{l | <func.altLabelCtxs.(l)>}; separator="\n\n"><endif>}> | |
279 | >> | |
280 | ||
281 | vocabulary(literalNames, symbolicNames) ::= << | |
282 | static final List\<String> _LITERAL_NAMES = [ | |
283 | <literalNames:{t | <t>}; null="null", separator=", ", wrap, anchor> | |
284 | ]; | |
285 | static final List\<String> _SYMBOLIC_NAMES = [ | |
286 | <symbolicNames:{t | <t>}; null="null", separator=", ", wrap, anchor> | |
287 | ]; | |
288 | static final Vocabulary VOCABULARY = VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); | |
289 | ||
290 | @override | |
291 | Vocabulary get vocabulary { | |
292 | return VOCABULARY; | |
293 | } | |
294 | >> | |
295 | ||
296 | dumpActions(recog, argFuncs, actionFuncs, sempredFuncs) ::= << | |
297 | <if(actionFuncs)> | |
298 | void action(RuleContext _localctx, int ruleIndex, int actionIndex) { | |
299 | switch (ruleIndex) { | |
300 | <recog.actionFuncs.values:{f| | |
301 | case <f.ruleIndex>: | |
302 | _<f.name>_action(_localctx, actionIndex); | |
303 | break;}; separator="\n"> | |
304 | } | |
305 | } | |
306 | <actionFuncs.values; separator="\n"> | |
307 | <endif> | |
308 | <if(sempredFuncs)> | |
309 | bool sempred(RuleContext _localctx, int ruleIndex, int predIndex) { | |
310 | switch (ruleIndex) { | |
311 | <recog.sempredFuncs.values:{f| | |
312 | case <f.ruleIndex>: | |
313 | return _<f.name>_sempred(_localctx, predIndex);}; separator="\n"> | |
314 | } | |
315 | return true; | |
316 | } | |
317 | <sempredFuncs.values; separator="\n"> | |
318 | <endif> | |
319 | >> | |
320 | ||
321 | parser_ctor(p) ::= << | |
322 | <p.name>(TokenStream input) : super(input) { | |
323 | interpreter = ParserATNSimulator(this, _ATN, _decisionToDFA, _sharedContextCache); | |
324 | } | |
325 | >> | |
326 | ||
327 | /// This generates a private method since the actionIndex is generated, making an | |
328 | /// overriding implementation impossible to maintain. | |
329 | RuleActionFunction(r, actions) ::= << | |
330 | void _<r.name>_action(<r.ctxType> _localctx, int actionIndex) { | |
331 | switch (actionIndex) { | |
332 | <actions:{index|case <index>: <actions.(index)> break;}; separator="\n"> | |
333 | } | |
334 | } | |
335 | >> | |
336 | ||
337 | /// This generates a private method since the predIndex is generated, making an | |
338 | /// overriding implementation impossible to maintain. | |
339 | RuleSempredFunction(r, actions) ::= << | |
340 | bool _<r.name>_sempred(<r.ctxType> _localctx, int predIndex) { | |
341 | switch (predIndex) { | |
342 | <actions:{index|case <index>: return <actions.(index)>;}; separator="\n"> | |
343 | } | |
344 | return true; | |
345 | } | |
346 | >> | |
347 | ||
348 | RuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,postamble,exceptions) ::= << | |
349 | ||
350 | <if(currentRule.modifiers)><currentRule.modifiers:{f | <f> }><else><endif><currentRule.ctxType> <currentRule.name>(<args; separator=", ">) { | |
351 | dynamic _localctx = <currentRule.ctxType>(context, state<currentRule.args:{a | , <a.name>}>); | |
352 | enterRule(_localctx, <currentRule.startState>, RULE_<currentRule.name>); | |
353 | <namedActions.init> | |
354 | <locals; separator="\n"> | |
355 | try { | |
356 | <if(currentRule.hasLookaheadBlock)> | |
357 | int _alt; | |
358 | <endif> | |
359 | <code> | |
360 | <postamble; separator="\n"> | |
361 | <namedActions.after> | |
362 | } <if(exceptions)> <exceptions; separator="\n"><else>on RecognitionException catch (re) { | |
363 | _localctx.exception = re; | |
364 | errorHandler.reportError(this, re); | |
365 | errorHandler.recover(this, re); | |
366 | }<endif> finally { | |
367 | <finallyAction> | |
368 | exitRule(); | |
369 | } | |
370 | return _localctx; | |
371 | } | |
372 | >> | |
373 | ||
374 | LeftRecursiveRuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs, | |
375 | namedActions,finallyAction,postamble) ::= | |
376 | << | |
377 | ||
378 | <currentRule.ctxType> <currentRule.name>([int _p = 0]<args:{a | , <a>}>) { | |
379 | final _parentctx = context; | |
380 | final _parentState = state; | |
381 | dynamic _localctx = <currentRule.ctxType>(context, _parentState<currentRule.args:{a | , <a.name>}>); | |
382 | var _prevctx = _localctx; | |
383 | var _startState = <currentRule.startState>; | |
384 | enterRecursionRule(_localctx, <currentRule.startState>, RULE_<currentRule.name>, _p); | |
385 | <namedActions.init> | |
386 | <locals; separator="\n"> | |
387 | try { | |
388 | <if(currentRule.hasLookaheadBlock)> | |
389 | int _alt; | |
390 | <endif> | |
391 | <code> | |
392 | <postamble; separator="\n"> | |
393 | <namedActions.after> | |
394 | } on RecognitionException catch (re) { | |
395 | _localctx.exception = re; | |
396 | errorHandler.reportError(this, re); | |
397 | errorHandler.recover(this, re); | |
398 | } finally { | |
399 | <finallyAction> | |
400 | unrollRecursionContexts(_parentctx); | |
401 | } | |
402 | return _localctx; | |
403 | } | |
404 | >> | |
405 | ||
406 | CodeBlockForOuterMostAlt(currentOuterMostAltCodeBlock, locals, preamble, ops) ::= << | |
407 | <if(currentOuterMostAltCodeBlock.altLabel)>_localctx = <currentOuterMostAltCodeBlock.altLabel; format="cap">Context(_localctx);<endif> | |
408 | enterOuterAlt(_localctx, <currentOuterMostAltCodeBlock.alt.altNum>); | |
409 | <CodeBlockForAlt(currentAltCodeBlock=currentOuterMostAltCodeBlock, ...)> | |
410 | >> | |
411 | ||
412 | CodeBlockForAlt(currentAltCodeBlock, locals, preamble, ops) ::= << | |
413 | <locals; separator="\n"> | |
414 | <preamble; separator="\n"> | |
415 | <ops; separator="\n"> | |
416 | >> | |
417 | ||
418 | LL1AltBlock(choice, preamble, alts, error) ::= << | |
419 | state = <choice.stateNumber>; | |
420 | errorHandler.sync(this); | |
421 | <if(choice.label)><labelref(choice.label)> = tokenStream.LT(1);<endif> | |
422 | <preamble; separator="\n"> | |
423 | switch (tokenStream.LA(1)) { | |
424 | <choice.altLook,alts:{look,alt| <cases(ttypes=look)> | |
425 | <alt> | |
426 | break;}; separator="\n"> | |
427 | default: | |
428 | <error> | |
429 | } | |
430 | >> | |
431 | ||
432 | LL1OptionalBlock(choice, alts, error) ::= << | |
433 | state = <choice.stateNumber>; | |
434 | errorHandler.sync(this); | |
435 | switch (tokenStream.LA(1)) { | |
436 | <choice.altLook,alts:{look,alt| <cases(ttypes=look)> | |
437 | <alt> | |
438 | break;}; separator="\n"> | |
439 | default: | |
440 | break; | |
441 | } | |
442 | >> | |
443 | ||
444 | LL1OptionalBlockSingleAlt(choice, expr, alts, preamble, error, followExpr) ::= << | |
445 | state = <choice.stateNumber>; | |
446 | errorHandler.sync(this); | |
447 | <preamble; separator="\n"> | |
448 | if (<expr>) { | |
449 | <alts; separator="\n"> | |
450 | } | |
451 | <!else if ( !(<followExpr>) ) <error>!> | |
452 | >> | |
453 | ||
454 | LL1StarBlockSingleAlt(choice, loopExpr, alts, preamble, iteration) ::= << | |
455 | state = <choice.stateNumber>; | |
456 | errorHandler.sync(this); | |
457 | <preamble; separator="\n"> | |
458 | while (<loopExpr>) { | |
459 | <alts; separator="\n"> | |
460 | state = <choice.loopBackStateNumber>; | |
461 | errorHandler.sync(this); | |
462 | <iteration> | |
463 | } | |
464 | >> | |
465 | ||
466 | LL1PlusBlockSingleAlt(choice, loopExpr, alts, preamble, iteration) ::= << | |
467 | state = <choice.blockStartStateNumber>; <! alt block decision !> | |
468 | errorHandler.sync(this); | |
469 | <preamble; separator="\n"> | |
470 | do { | |
471 | <alts; separator="\n"> | |
472 | state = <choice.stateNumber>; <! loopback/exit decision !> | |
473 | errorHandler.sync(this); | |
474 | <iteration> | |
475 | } while (<loopExpr>); | |
476 | >> | |
477 | ||
478 | // LL(*) stuff | |
479 | ||
480 | AltBlock(choice, preamble, alts, error) ::= << | |
481 | state = <choice.stateNumber>; | |
482 | errorHandler.sync(this); | |
483 | <if(choice.label)><labelref(choice.label)> = tokenStream.LT(1);<endif> | |
484 | <preamble; separator="\n"> | |
485 | switch (interpreter.adaptivePredict(tokenStream, <choice.decision>, context)) { | |
486 | <alts:{alt | | |
487 | case <i>: | |
488 | <alt> | |
489 | break;}; separator="\n"> | |
490 | } | |
491 | >> | |
492 | ||
493 | OptionalBlock(choice, alts, error) ::= << | |
494 | state = <choice.stateNumber>; | |
495 | errorHandler.sync(this); | |
496 | switch (interpreter.adaptivePredict(tokenStream, <choice.decision>, context)) { | |
497 | <alts:{alt | | |
498 | case <i><if(!choice.ast.greedy)>+1<endif>: | |
499 | <alt> | |
500 | break;}; separator="\n"> | |
501 | } | |
502 | >> | |
503 | ||
504 | StarBlock(choice, alts, sync, iteration) ::= << | |
505 | state = <choice.stateNumber>; | |
506 | errorHandler.sync(this); | |
507 | _alt = interpreter.adaptivePredict(tokenStream, <choice.decision>, context); | |
508 | while (_alt != <choice.exitAlt> && _alt != ATN.INVALID_ALT_NUMBER) { | |
509 | if (_alt == 1<if(!choice.ast.greedy)> + 1<endif>) { | |
510 | <iteration> | |
511 | <alts> <! should only be one !> | |
512 | } | |
513 | state = <choice.loopBackStateNumber>; | |
514 | errorHandler.sync(this); | |
515 | _alt = interpreter.adaptivePredict(tokenStream, <choice.decision>, context); | |
516 | } | |
517 | >> | |
518 | ||
519 | PlusBlock(choice, alts, error) ::= << | |
520 | state = <choice.blockStartStateNumber>; <! alt block decision !> | |
521 | errorHandler.sync(this); | |
522 | _alt = 1<if(!choice.ast.greedy)>+1<endif>; | |
523 | do { | |
524 | switch (_alt) { | |
525 | <alts:{alt| | |
526 | case <i><if(!choice.ast.greedy)> + 1<endif>: | |
527 | <alt> | |
528 | break;}; separator="\n"> | |
529 | default: | |
530 | <error> | |
531 | } | |
532 | state = <choice.loopBackStateNumber>; <! loopback/exit decision !> | |
533 | errorHandler.sync(this); | |
534 | _alt = interpreter.adaptivePredict(tokenStream, <choice.decision>, context); | |
535 | } while (_alt != <choice.exitAlt> && _alt != ATN.INVALID_ALT_NUMBER); | |
536 | >> | |
537 | ||
538 | Sync(s) ::= "sync(<s.expecting.name>);" | |
539 | ||
540 | ThrowNoViableAlt(t) ::= "throw NoViableAltException(this);" | |
541 | ||
542 | TestSetInline(s) ::= << | |
543 | <s.bitsets:{bits | <if(rest(rest(bits.ttypes)))><bitsetBitfieldComparison(s, bits)><else><bitsetInlineComparison(s, bits)><endif>}; separator=" || "> | |
544 | >> | |
545 | ||
546 | // Java language spec 15.19 - shift operators mask operands rather than overflow to 0... need range test | |
547 | testShiftInRange(shiftAmount) ::= << | |
548 | ((<shiftAmount>) & ~0x3f) == 0 | |
549 | >> | |
550 | ||
551 | // produces smaller bytecode only when bits.ttypes contains more than two items | |
552 | bitsetBitfieldComparison(s, bits) ::= <% | |
553 | (<testShiftInRange({<offsetShift(s.varName, bits.shift)>})> && ((BigInt.one \<\< <offsetShift(s.varName, bits.shift)>) & (<bits.ttypes:{ttype | (BigInt.one \<\< <offsetShift({TOKEN_<ttype>}, bits.shift)>)}; separator=" | ">)) != BigInt.zero) | |
554 | %> | |
555 | ||
556 | isZero ::= [ | |
557 | "0":true, | |
558 | default:false | |
559 | ] | |
560 | ||
561 | offsetShift(shiftAmount, offset) ::= <% | |
562 | <if(!isZero.(offset))>(<shiftAmount> - <offset>)<else><shiftAmount><endif> | |
563 | %> | |
564 | ||
565 | // produces more efficient bytecode when bits.ttypes contains at most two items | |
566 | bitsetInlineComparison(s, bits) ::= <% | |
567 | <bits.ttypes:{ttype | <s.varName> == TOKEN_<ttype>}; separator=" || "> | |
568 | %> | |
569 | ||
570 | cases(ttypes) ::= << | |
571 | <ttypes:{t | case TOKEN_<t>:}; separator="\n"> | |
572 | >> | |
573 | ||
574 | InvokeRule(r, argExprsChunks) ::=<< | |
575 | state = <r.stateNumber>; | |
576 | <if(r.labels)><r.labels:{l | <labelref(l)> = }><endif><r.name>(<if(r.ast.options.p)><r.ast.options.p><if(argExprsChunks)>,<endif><endif><argExprsChunks>); | |
577 | >> | |
578 | ||
579 | MatchToken(m) ::= << | |
580 | state = <m.stateNumber>; | |
581 | <if(m.labels)><m.labels:{l | <labelref(l)> = }><endif>match(TOKEN_<m.name>); | |
582 | >> | |
583 | ||
584 | MatchSet(m, expr, capture) ::= "<CommonSetStuff(m, expr, capture, false)>" | |
585 | ||
586 | MatchNotSet(m, expr, capture) ::= "<CommonSetStuff(m, expr, capture, true)>" | |
587 | ||
588 | CommonSetStuff(m, expr, capture, invert) ::= << | |
589 | state = <m.stateNumber>; | |
590 | <if(m.labels)><m.labels:{l | <labelref(l)> = }>tokenStream.LT(1);<endif> | |
591 | <capture> | |
592 | if (<if(invert)><m.varName> \<= 0 || <else>!<endif>(<expr>)) { | |
593 | <if(m.labels)><m.labels:{l | <labelref(l)> = }><endif>errorHandler.recoverInline(this); | |
594 | } else { | |
595 | if ( tokenStream.LA(1)==IntStream.EOF ) matchedEOF = true; | |
596 | errorHandler.reportMatch(this); | |
597 | consume(); | |
598 | } | |
599 | >> | |
600 | ||
601 | Wildcard(w) ::= << | |
602 | state = <w.stateNumber>; | |
603 | <if(w.labels)><w.labels:{l | <labelref(l)> = }><endif>matchWildcard(); | |
604 | >> | |
605 | ||
606 | // ACTION STUFF | |
607 | ||
608 | Action(a, foo, chunks) ::= "<chunks>" | |
609 | ||
610 | ArgAction(a, chunks) ::= "<chunks>" | |
611 | ||
612 | SemPred(p, chunks, failChunks) ::= << | |
613 | state = <p.stateNumber>; | |
614 | if (!(<chunks>)) { | |
615 | throw FailedPredicateException(this, <p.predicate><if(failChunks)>, <failChunks><elseif(p.msg)>, <p.msg><endif>); | |
616 | } | |
617 | >> | |
618 | ||
619 | ExceptionClause(e, catchArg, catchAction) ::= << | |
620 | catch (<catchArg>) { | |
621 | <catchAction> | |
622 | } | |
623 | >> | |
624 | ||
625 | // lexer actions are not associated with model objects | |
626 | ||
627 | LexerSkipCommand() ::= "skip();" | |
628 | LexerMoreCommand() ::= "more();" | |
629 | LexerPopModeCommand() ::= "popMode();" | |
630 | ||
631 | LexerTypeCommand(arg, grammar) ::= "type = <arg>;" | |
632 | LexerChannelCommand(arg, grammar) ::= "channel = <arg>;" | |
633 | LexerModeCommand(arg, grammar) ::= "mode_ = <arg>;" | |
634 | LexerPushModeCommand(arg, grammar) ::= "pushMode(<arg>);" | |
635 | ||
636 | ActionText(t) ::= "<t.text>" | |
637 | ActionTemplate(t) ::= "<t.st>" | |
638 | ArgRef(a) ::= "_localctx.<a.name>" | |
639 | LocalRef(a) ::= "_localctx.<a.name>" | |
640 | RetValueRef(a) ::= "_localctx.<a.name>" | |
641 | QRetValueRef(a) ::= "<ctx(a)>.<a.dict>.<a.name>" | |
642 | /** How to translate $tokenLabel */ | |
643 | TokenRef(t) ::= "<ctx(t)>.<t.name>" | |
644 | LabelRef(t) ::= "<ctx(t)>.<t.name>" | |
645 | ListLabelRef(t) ::= "<ctx(t)>.<ListLabelName(t.name)>" | |
646 | SetAttr(s,rhsChunks) ::= "<ctx(s)>.<s.name> = <rhsChunks>;" | |
647 | ||
648 | TokenLabelType() ::= "<file.TokenLabelType; null={Token}>" | |
649 | InputSymbolType() ::= "<file.InputSymbolType; null={Token}>" | |
650 | ||
651 | TokenPropertyRef_text(t) ::= "<ctx(t)>.<t.label>?.text" | |
652 | TokenPropertyRef_type(t) ::= "<ctx(t)>.<t.label> != null ? <ctx(t)>.<t.label>.type : 0" | |
653 | TokenPropertyRef_line(t) ::= "<ctx(t)>.<t.label> != null ? <ctx(t)>.<t.label>.line : 0" | |
654 | TokenPropertyRef_pos(t) ::= "<ctx(t)>.<t.label> != null ? <ctx(t)>.<t.label>.charPositionInLine : 0" | |
655 | TokenPropertyRef_channel(t) ::= "<ctx(t)>.<t.label> != null ? <ctx(t)>.<t.label>.channel : 0" | |
656 | TokenPropertyRef_index(t) ::= "<ctx(t)>.<t.label> != null ? <ctx(t)>.<t.label>.tokenIndex : 0" | |
657 | TokenPropertyRef_int(t) ::= "<ctx(t)>.<t.label> != null ? int.parse(<ctx(t)>.<t.label>.text) : 0" | |
658 | ||
659 | RulePropertyRef_start(r) ::= "<ctx(r)>.<r.label>?.start" | |
660 | RulePropertyRef_stop(r) ::= "<ctx(r)>.<r.label>?.stop" | |
661 | RulePropertyRef_text(r) ::= "(<ctx(r)>.<r.label> != null ? tokenStream.getTextRange(<ctx(r)>.<r.label>.start, <ctx(r)>.<r.label>.stop) : null)" | |
662 | RulePropertyRef_ctx(r) ::= "<ctx(r)>.<r.label>" | |
663 | RulePropertyRef_parser(r) ::= "this" | |
664 | ||
665 | ThisRulePropertyRef_start(r) ::= "_localctx.start" | |
666 | ThisRulePropertyRef_stop(r) ::= "_localctx.stop" | |
667 | ThisRulePropertyRef_text(r) ::= "tokenStream.getTextRange(_localctx.start, tokenStream.LT(-1))" | |
668 | ThisRulePropertyRef_ctx(r) ::= "_localctx" | |
669 | ThisRulePropertyRef_parser(r) ::= "this" | |
670 | ||
671 | NonLocalAttrRef(s) ::= "(getInvokingContext(<s.ruleIndex>) as <s.ruleName; format=\"cap\">Context).<s.name>" | |
672 | SetNonLocalAttr(s, rhsChunks) ::= | |
673 | "(getInvokingContext(<s.ruleIndex>) as <s.ruleName; format=\"cap\">Context).<s.name> = <rhsChunks>;" | |
674 | ||
675 | AddToLabelList(a) ::= "<ctx(a.label)>.<a.listName>.add(<labelref(a.label)>);" | |
676 | ||
677 | TokenDecl(t) ::= "<TokenLabelType()> <t.name>" | |
678 | TokenTypeDecl(t) ::= "int <t.name>;" | |
679 | TokenListDecl(t) ::= "List\<Token> <t.name> = List\<Token>()" | |
680 | RuleContextDecl(r) ::= "<r.ctxName> <r.name>" | |
681 | RuleContextListDecl(rdecl) ::= "List\<<rdecl.ctxName>> <rdecl.name> = List\<<rdecl.ctxName>>()" | |
682 | ||
683 | ContextTokenGetterDecl(t) ::= << | |
684 | TerminalNode <t.name>() => getToken(<parser.name>.TOKEN_<t.name>, 0); | |
685 | >> | |
686 | ContextTokenListGetterDecl(t) ::= << | |
687 | List\<TerminalNode> <t.name>s() => getTokens(<parser.name>.TOKEN_<t.name>); | |
688 | >> | |
689 | ContextTokenListIndexedGetterDecl(t) ::= << | |
690 | TerminalNode <t.name>(int i) => getToken(<parser.name>.TOKEN_<t.name>, i); | |
691 | >> | |
692 | ContextRuleGetterDecl(r) ::= << | |
693 | <r.ctxName> <r.name>() => getRuleContext\<<r.ctxName>\>(0); | |
694 | >> | |
695 | ContextRuleListGetterDecl(r) ::= << | |
696 | List\<<r.ctxName>\> <r.name>s() => getRuleContexts\<<r.ctxName>\>(); | |
697 | >> | |
698 | ContextRuleListIndexedGetterDecl(r) ::= << | |
699 | <r.ctxName> <r.name>(int i) => getRuleContext\<<r.ctxName>\>(i); | |
700 | >> | |
701 | ||
702 | LexerRuleContext() ::= "RuleContext" | |
703 | ||
704 | /// The rule context name is the rule followed by a suffix; e.g., | |
705 | /// r becomes rContext. | |
706 | RuleContextNameSuffix() ::= "Context" | |
707 | ||
708 | ImplicitTokenLabel(tokenName) ::= "_<tokenName>" | |
709 | ImplicitRuleLabel(ruleName) ::= "_<ruleName>" | |
710 | ImplicitSetLabel(id) ::= "_tset<id>" | |
711 | ListLabelName(label) ::= "<label>" | |
712 | ||
713 | CaptureNextToken(d) ::= "<d.varName> = tokenStream.LT(1);" | |
714 | CaptureNextTokenType(d) ::= "<d.varName> = tokenStream.LA(1);" | |
715 | ||
716 | StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers) | |
717 | ::= << | |
718 | class <struct.name> extends <if(contextSuperClass)><contextSuperClass><else>ParserRuleContext<endif><if(interfaces)> implements <interfaces; separator=", "><endif> { | |
719 | <attrs:{a | <a>;}; separator="\n"> | |
720 | <getters:{g | <g>}; separator="\n"> | |
721 | <struct.name>([ParserRuleContext parent, int invokingState<ctorAttrs:{a | , <a>}>]) : super(parent, invokingState)<if(struct.ctorAttrs)> { | |
722 | <struct.ctorAttrs:{a | this.<a.name> = <a.name>;}; separator="\n"> | |
723 | }<else>;<endif> | |
724 | ||
725 | @override | |
726 | int get ruleIndex => RULE_<struct.derivedFromName>; | |
727 | <if(struct.provideCopyFrom)> <! don't need copy unless we have subclasses !> | |
728 | @override | |
729 | void copyFrom(<if(contextSuperClass)><contextSuperClass><else>ParserRuleContext<endif> ctx) { | |
730 | super.copyFrom(ctx); | |
731 | <struct.attrs:{a | this.<a.name> = (ctx as <struct.name>).<a.name>;}; separator="\n"> | |
732 | } | |
733 | <endif> | |
734 | <dispatchMethods; separator="\n"> | |
735 | <extensionMembers; separator="\n"> | |
736 | } | |
737 | >> | |
738 | ||
739 | AltLabelStructDecl(struct,attrs,getters,dispatchMethods) ::= << | |
740 | class <struct.name> extends <struct.parentRule; format="cap">Context { | |
741 | <attrs:{a | <a>;}; separator="\n"> | |
742 | <getters:{g | <g>}; separator="\n"> | |
743 | <struct.name>(<struct.parentRule; format="cap">Context ctx) { copyFrom(ctx); } | |
744 | <dispatchMethods; separator="\n"> | |
745 | } | |
746 | >> | |
747 | ||
748 | ListenerDispatchMethod(method) ::= << | |
749 | @override | |
750 | void <if(method.isEnter)>enter<else>exit<endif>Rule(ParseTreeListener listener) { | |
751 | if (listener is <parser.grammarName>Listener) listener.<if(method.isEnter)>enter<else>exit<endif><struct.derivedFromName; format="cap">(this); | |
752 | } | |
753 | >> | |
754 | ||
755 | VisitorDispatchMethod(method) ::= << | |
756 | @override | |
757 | T accept\<T>(ParseTreeVisitor\<T> visitor) { | |
758 | if (visitor is <parser.grammarName>Visitor\<T>) { | |
759 | return visitor.visit<struct.derivedFromName; format="cap">(this); | |
760 | } else { | |
761 | return visitor.visitChildren(this); | |
762 | } | |
763 | } | |
764 | >> | |
765 | ||
766 | AttributeDecl(d) ::= "<d.type> <d.name><if(d.initValue)> = <d.initValue><endif>" | |
767 | ||
768 | // If we don't know location of label def x, use this template | |
769 | labelref(x) ::= "<if(!x.isLocal)>_localctx.<endif><x.name>" | |
770 | ||
771 | // For any action chunk, what is correctly-typed context struct ptr? | |
772 | ctx(actionChunk) ::= "_localctx" | |
773 | ||
774 | // used for left-recursive rules | |
775 | recRuleAltPredicate(ruleName,opPrec) ::= "precpred(context, <opPrec>)" | |
776 | recRuleSetReturnAction(src,name) ::= "$<name> = $<src>.<name>;" | |
777 | recRuleSetStopToken() ::= "context.stop = tokenStream.LT(-1);" | |
778 | ||
779 | recRuleAltStartAction(ruleName, ctxName, label, isListLabel) ::= << | |
780 | _localctx = <ctxName>Context(_parentctx, _parentState); | |
781 | <if(label)> | |
782 | <if(isListLabel)> | |
783 | _localctx.<label>.add(_prevctx); | |
784 | <else> | |
785 | _localctx.<label> = _prevctx; | |
786 | <endif> | |
787 | <endif> | |
788 | pushNewRecursionContext(_localctx, _startState, RULE_<ruleName>); | |
789 | >> | |
790 | ||
791 | recRuleLabeledAltStartAction(ruleName, currentAltLabel, label, isListLabel) ::= << | |
792 | _localctx = <currentAltLabel; format="cap">Context(new <ruleName; format="cap">Context(_parentctx, _parentState)); | |
793 | <if(label)> | |
794 | <if(isListLabel)> | |
795 | _localctx.<label>.add(_prevctx); | |
796 | <else> | |
797 | _localctx.<label> = _prevctx; | |
798 | <endif> | |
799 | <endif> | |
800 | pushNewRecursionContext(_localctx, _startState, RULE_<ruleName>); | |
801 | >> | |
802 | ||
803 | recRuleReplaceContext(ctxName) ::= << | |
804 | _localctx = <ctxName>Context(_localctx); | |
805 | context = _localctx; | |
806 | _prevctx = _localctx; | |
807 | >> | |
808 | ||
809 | recRuleSetPrevCtx() ::= << | |
810 | if (parseListeners != null) triggerExitRuleEvent(); | |
811 | _prevctx = _localctx; | |
812 | >> | |
813 | ||
814 | ||
815 | LexerFile(lexerFile, lexer, namedActions) ::= << | |
816 | <fileHeader(lexerFile.grammarFileName, lexerFile.ANTLRVersion)> | |
817 | <if(lexerFile.genPackage)> | |
818 | part of <lexerFile.genPackage>; | |
819 | <else> | |
820 | import 'package:antlr4/antlr4.dart'; | |
821 | <endif> | |
822 | <namedActions.header> | |
823 | ||
824 | <lexer> | |
825 | >> | |
826 | ||
827 | Lexer(lexer, atn, actionFuncs, sempredFuncs, superClass) ::= << | |
828 | <if(namedActions.definitions)><namedActions.definitions><endif> | |
829 | ||
830 | class <lexer.name> extends <superClass; null="Lexer"> { | |
831 | static final checkVersion = () => RuntimeMetaData.checkVersion('<lexerFile.ANTLRVersion>', RuntimeMetaData.VERSION); | |
832 | ||
833 | static final List\<DFA> _decisionToDFA = List.generate( | |
834 | _ATN.numberOfDecisions, (i) => DFA(_ATN.getDecisionState(i), i)); | |
835 | static final PredictionContextCache _sharedContextCache = PredictionContextCache(); | |
836 | <if(lexer.tokens)> | |
837 | static const int | |
838 | <lexer.tokens:{k | TOKEN_<k> = <lexer.tokens.(k)>}; separator=", ", wrap, anchor>; | |
839 | <endif> | |
840 | <if(lexer.channels)> | |
841 | static const int | |
842 | <lexer.channels:{c | <c> = <lexer.channels.(c)>}; separator=", ", wrap, anchor>; | |
843 | <endif> | |
844 | <if(rest(lexer.modes))> | |
845 | static const int | |
846 | <rest(lexer.modes):{m | <m> = <i>}; separator=", ", wrap, anchor>; | |
847 | <endif> | |
848 | ||
849 | @override | |
850 | final List\<String> channelNames = [ | |
851 | 'DEFAULT_TOKEN_CHANNEL', 'HIDDEN'<if (lexer.channels)>, <lexer.channels:{c| '<c>'}; separator=", ", wrap, anchor><endif> | |
852 | ]; | |
853 | ||
854 | @override | |
855 | final List\<String> modeNames = [ | |
856 | <lexer.modes:{m| '<m>'}; separator=", ", wrap, anchor> | |
857 | ]; | |
858 | ||
859 | @override | |
860 | final List\<String> ruleNames = [ | |
861 | <lexer.ruleNames:{r | '<r>'}; separator=", ", wrap, anchor> | |
862 | ]; | |
863 | ||
864 | <vocabulary(lexer.literalNames, lexer.symbolicNames)> | |
865 | ||
866 | <namedActions.members> | |
867 | ||
868 | <lexer.name>(CharStream input) : super(input) { | |
869 | interpreter = LexerATNSimulator(_ATN, _decisionToDFA, _sharedContextCache, recog: this); | |
870 | } | |
871 | ||
872 | @override | |
873 | String get serializedATN => _serializedATN; | |
874 | ||
875 | @override | |
876 | String get grammarFileName => '<lexer.grammarFileName>'; | |
877 | ||
878 | @override | |
879 | ATN getATN() { return _ATN; } | |
880 | ||
881 | <dumpActions(lexer, "", actionFuncs, sempredFuncs)> | |
882 | <atn> | |
883 | } | |
884 | >> | |
885 | ||
886 | SerializedATN(model) ::= << | |
887 | <if(rest(model.segments))> | |
888 | <! requires segmented representation !> | |
889 | static const int _serializedATNSegments = <length(model.segments)>; | |
890 | <model.segments:{segment|static final String _serializedATNSegment<i0> = | |
891 | '<segment; wrap={'<\n><\t>'}>';}; separator="\n"> | |
892 | static final String _serializedATN = [ | |
893 | <model.segments:{segment | _serializedATNSegment<i0>}; separator=",\n"> | |
894 | ].join(); | |
895 | <else> | |
896 | <! only one segment, can be inlined !> | |
897 | static const String _serializedATN = '<model.serialized; wrap={'<\n><\t>'}>'; | |
898 | <endif> | |
899 | static final ATN _ATN = | |
900 | ATNDeserializer().deserialize(_serializedATN.codeUnits); | |
901 | >> | |
902 | ||
903 | /// Using a type to init value map, try to init a type; if not in table | |
904 | /// must be an object, default value is "null". | |
905 | initValue(typeName) ::= << | |
906 | <dartTypeInitMap.(typeName)> | |
907 | >> | |
908 | ||
909 | codeFileExtension() ::= ".dart" |
150 | 150 | var parserATN []uint16 |
151 | 151 | <endif> |
152 | 152 | |
153 | var deserializer = antlr.NewATNDeserializer(nil) | |
154 | var deserializedATN = deserializer.DeserializeFromUInt16(parserATN) | |
155 | ||
156 | 153 | <if(parser.literalNames)> |
157 | 154 | var literalNames = []string{ |
158 | 155 | <parser.literalNames; null="\"\"", separator=", ", wrap>, |
178 | 175 | var ruleNames []string |
179 | 176 | <endif> |
180 | 177 | |
181 | var decisionToDFA = make([]*antlr.DFA, len(deserializedATN.DecisionToState)) | |
182 | ||
183 | func init() { | |
178 | type <parser.name> struct { | |
179 | <superClass; null="*antlr.BaseParser"> | |
180 | } | |
181 | ||
182 | // New<parser.name> produces a new parser instance for the optional input antlr.TokenStream. | |
183 | // | |
184 | // The *<parser.name> instance produced may be reused by calling the SetInputStream method. | |
185 | // The initial parser configuration is expensive to construct, and the object is not thread-safe; | |
186 | // however, if used within a Golang sync.Pool, the construction cost amortizes well and the | |
187 | // objects can be used in a thread-safe manner. | |
188 | func New<parser.name>(input antlr.TokenStream) *<parser.name> { | |
189 | this := new(<parser.name>) | |
190 | deserializer := antlr.NewATNDeserializer(nil) | |
191 | deserializedATN := deserializer.DeserializeFromUInt16(parserATN) | |
192 | decisionToDFA := make([]*antlr.DFA, len(deserializedATN.DecisionToState)) | |
184 | 193 | for index, ds := range deserializedATN.DecisionToState { |
185 | 194 | decisionToDFA[index] = antlr.NewDFA(ds, index) |
186 | 195 | } |
187 | } | |
188 | ||
189 | type <parser.name> struct { | |
190 | <superClass; null="*antlr.BaseParser"> | |
191 | } | |
192 | ||
193 | func New<parser.name>(input antlr.TokenStream) *<parser.name> { | |
194 | this := new(<parser.name>) | |
195 | ||
196 | 196 | this.BaseParser = antlr.NewBaseParser(input) |
197 | 197 | |
198 | 198 | this.Interpreter = antlr.NewParserATNSimulator(this, deserializedATN, decisionToDFA, antlr.NewPredictionContextCache()) |
203 | 203 | |
204 | 204 | return this |
205 | 205 | } |
206 | ||
206 | 207 | <if(namedActions.members)> |
207 | 208 | |
208 | 209 | <namedActions.members> |
1374 | 1375 | <endif> |
1375 | 1376 | |
1376 | 1377 | |
1377 | var lexerDeserializer = antlr.NewATNDeserializer(nil) | |
1378 | var lexerAtn = lexerDeserializer.DeserializeFromUInt16(serializedLexerAtn) | |
1379 | ||
1380 | 1378 | var lexerChannelNames = []string{ |
1381 | 1379 | "DEFAULT_TOKEN_CHANNEL", "HIDDEN"<if (lexer.channels)>, <lexer.channels:{c | "<c>"}; separator=", ", wrap><endif>, |
1382 | 1380 | } |
1410 | 1408 | <else> |
1411 | 1409 | var lexerRuleNames []string |
1412 | 1410 | <endif> |
1413 | ||
1414 | 1411 | |
1415 | 1412 | type <lexer.name> struct { |
1416 | 1413 | *<if(superClass)><superClass><else>antlr.BaseLexer<endif> |
1419 | 1416 | // TODO: EOF string |
1420 | 1417 | } |
1421 | 1418 | |
1422 | var lexerDecisionToDFA = make([]*antlr.DFA, len(lexerAtn.DecisionToState)) | |
1423 | ||
1424 | func init() { | |
1419 | // New<lexer.name> produces a new lexer instance for the optional input antlr.CharStream. | |
1420 | // | |
1421 | // The *<lexer.name> instance produced may be reused by calling the SetInputStream method. | |
1422 | // The initial lexer configuration is expensive to construct, and the object is not thread-safe; | |
1423 | // however, if used within a Golang sync.Pool, the construction cost amortizes well and the | |
1424 | // objects can be used in a thread-safe manner. | |
1425 | func New<lexer.name>(input antlr.CharStream) *<lexer.name> { | |
1426 | l := new(<lexer.name>) | |
1427 | lexerDeserializer := antlr.NewATNDeserializer(nil) | |
1428 | lexerAtn := lexerDeserializer.DeserializeFromUInt16(serializedLexerAtn) | |
1429 | lexerDecisionToDFA := make([]*antlr.DFA, len(lexerAtn.DecisionToState)) | |
1425 | 1430 | for index, ds := range lexerAtn.DecisionToState { |
1426 | 1431 | lexerDecisionToDFA[index] = antlr.NewDFA(ds, index) |
1427 | 1432 | } |
1428 | } | |
1429 | ||
1430 | func New<lexer.name>(input antlr.CharStream) *<lexer.name> { | |
1431 | ||
1432 | l := new(<lexer.name>) | |
1433 | ||
1434 | 1433 | l.BaseLexer = antlr.NewBaseLexer(input) |
1435 | 1434 | l.Interpreter = antlr.NewLexerATNSimulator(l, lexerAtn, lexerDecisionToDFA, antlr.NewPredictionContextCache()) |
1436 | 1435 |
233 | 233 | public static final int |
234 | 234 | <parser.tokens:{k | <k>=<parser.tokens.(k)>}; separator=", ", wrap, anchor>; |
235 | 235 | <endif> |
236 | <if(parser.rules)> | |
236 | 237 | public static final int |
237 | 238 | <parser.rules:{r | RULE_<r.name> = <r.index>}; separator=", ", wrap, anchor>; |
239 | <endif> | |
238 | 240 | private static String[] makeRuleNames() { |
239 | 241 | return new String[] { |
240 | 242 | <parser.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> |
47 | 47 | |
48 | 48 | ParserFile(file, parser, namedActions, contextSuperClass) ::= << |
49 | 49 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> |
50 | var antlr4 = require('antlr4/index'); | |
50 | import antlr4 from 'antlr4'; | |
51 | 51 | <if(file.genListener)> |
52 | var <file.grammarName>Listener = require('./<file.grammarName>Listener').<file.grammarName>Listener; | |
52 | import <file.grammarName>Listener from './<file.grammarName>Listener.js'; | |
53 | 53 | <endif> |
54 | 54 | <if(file.genVisitor)> |
55 | var <file.grammarName>Visitor = require('./<file.grammarName>Visitor').<file.grammarName>Visitor; | |
55 | import <file.grammarName>Visitor from './<file.grammarName>Visitor.js'; | |
56 | 56 | <endif> |
57 | 57 | |
58 | 58 | <namedActions.header> |
61 | 61 | |
62 | 62 | ListenerFile(file, header, namedActions) ::= << |
63 | 63 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> |
64 | var antlr4 = require('antlr4/index'); | |
64 | import antlr4 from 'antlr4'; | |
65 | 65 | |
66 | 66 | // This class defines a complete listener for a parse tree produced by <file.parserName>. |
67 | function <file.grammarName>Listener() { | |
68 | antlr4.tree.ParseTreeListener.call(this); | |
69 | return this; | |
70 | } | |
71 | ||
72 | <file.grammarName>Listener.prototype = Object.create(antlr4.tree.ParseTreeListener.prototype); | |
73 | <file.grammarName>Listener.prototype.constructor = <file.grammarName>Listener; | |
67 | export default class <file.grammarName>Listener extends antlr4.tree.ParseTreeListener { | |
74 | 68 | |
75 | 69 | <file.listenerNames:{lname | |
76 | // Enter a parse tree produced by <file.parserName>#<lname>. | |
77 | <file.grammarName>Listener.prototype.enter<lname; format="cap"> = function(ctx) { | |
78 | \}; | |
79 | ||
80 | // Exit a parse tree produced by <file.parserName>#<lname>. | |
81 | <file.grammarName>Listener.prototype.exit<lname; format="cap"> = function(ctx) { | |
82 | \}; | |
70 | // Enter a parse tree produced by <file.parserName>#<lname>. | |
71 | enter<lname; format="cap">(ctx) { | |
72 | \} | |
73 | ||
74 | // Exit a parse tree produced by <file.parserName>#<lname>. | |
75 | exit<lname; format="cap">(ctx) { | |
76 | \} | |
83 | 77 | |
84 | 78 | }; separator="\n"> |
85 | 79 | |
86 | exports.<file.grammarName>Listener = <file.grammarName>Listener; | |
80 | } | |
87 | 81 | >> |
88 | 82 | |
89 | 83 | |
90 | 84 | VisitorFile(file, header, namedActions) ::= << |
91 | 85 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> |
92 | var antlr4 = require('antlr4/index'); | |
86 | import antlr4 from 'antlr4'; | |
93 | 87 | |
94 | 88 | // This class defines a complete generic visitor for a parse tree produced by <file.parserName>. |
95 | 89 | |
96 | function <file.grammarName>Visitor() { | |
97 | antlr4.tree.ParseTreeVisitor.call(this); | |
98 | return this; | |
99 | } | |
100 | ||
101 | <file.grammarName>Visitor.prototype = Object.create(antlr4.tree.ParseTreeVisitor.prototype); | |
102 | <file.grammarName>Visitor.prototype.constructor = <file.grammarName>Visitor; | |
90 | export default class <file.grammarName>Visitor extends antlr4.tree.ParseTreeVisitor { | |
103 | 91 | |
104 | 92 | <file.visitorNames:{lname | |
105 | // Visit a parse tree produced by <file.parserName>#<lname>. | |
106 | <file.grammarName>Visitor.prototype.visit<lname; format="cap"> = function(ctx) { | |
107 | return this.visitChildren(ctx); | |
108 | \}; | |
93 | // Visit a parse tree produced by <file.parserName>#<lname>. | |
94 | visit<lname; format="cap">(ctx) { | |
95 | return this.visitChildren(ctx); | |
96 | \} | |
109 | 97 | |
110 | 98 | }; separator="\n"> |
111 | 99 | |
112 | exports.<file.grammarName>Visitor = <file.grammarName>Visitor; | |
100 | } | |
113 | 101 | >> |
114 | 102 | |
115 | 103 | |
120 | 108 | |
121 | 109 | Parser(parser, funcs, atn, sempredFuncs, superClass) ::= << |
122 | 110 | <if(superClass)> |
123 | var <superClass> = require('./<superClass>').<superClass>; | |
124 | <endif> | |
125 | ||
126 | var grammarFileName = "<parser.grammarFileName; format="java-escape">"; | |
111 | import <superClass> from './<superClass>.js'; | |
112 | <endif> | |
127 | 113 | |
128 | 114 | <atn> |
129 | 115 | |
130 | var atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN); | |
131 | ||
132 | var decisionsToDFA = atn.decisionToState.map( function(ds, index) { return new antlr4.dfa.DFA(ds, index); }); | |
133 | ||
134 | var sharedContextCache = new antlr4.PredictionContextCache(); | |
135 | ||
136 | var literalNames = [ <parser.literalNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ]; | |
137 | ||
138 | var symbolicNames = [ <parser.symbolicNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ]; | |
139 | ||
140 | var ruleNames = [ <parser.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> ]; | |
141 | ||
142 | function <parser.name> (input) { | |
143 | <superClass; null="antlr4.Parser">.call(this, input); | |
144 | this._interp = new antlr4.atn.ParserATNSimulator(this, atn, decisionsToDFA, sharedContextCache); | |
145 | this.ruleNames = ruleNames; | |
146 | this.literalNames = literalNames; | |
147 | this.symbolicNames = symbolicNames; | |
148 | <namedActions.members> | |
149 | return this; | |
150 | } | |
151 | ||
152 | <parser.name>.prototype = Object.create(<superClass; null="antlr4.Parser">.prototype); | |
153 | <parser.name>.prototype.constructor = <parser.name>; | |
154 | ||
155 | Object.defineProperty(<parser.name>.prototype, "atn", { | |
156 | get : function() { | |
157 | return atn; | |
158 | } | |
159 | }); | |
116 | const atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN); | |
117 | ||
118 | const decisionsToDFA = atn.decisionToState.map( (ds, index) => new antlr4.dfa.DFA(ds, index) ); | |
119 | ||
120 | const sharedContextCache = new antlr4.PredictionContextCache(); | |
121 | ||
122 | export default class <parser.name> extends <superClass; null="antlr4.Parser"> { | |
123 | ||
124 | static grammarFileName = "<parser.grammarFileName; format="java-escape">"; | |
125 | static literalNames = [ <parser.literalNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ]; | |
126 | static symbolicNames = [ <parser.symbolicNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ]; | |
127 | static ruleNames = [ <parser.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> ]; | |
128 | ||
129 | constructor(input) { | |
130 | super(input); | |
131 | this._interp = new antlr4.atn.ParserATNSimulator(this, atn, decisionsToDFA, sharedContextCache); | |
132 | this.ruleNames = <parser.name>.ruleNames; | |
133 | this.literalNames = <parser.name>.literalNames; | |
134 | this.symbolicNames = <parser.name>.symbolicNames; | |
135 | <namedActions.members> | |
136 | } | |
137 | ||
138 | get atn() { | |
139 | return atn; | |
140 | } | |
141 | ||
142 | <if(sempredFuncs)> | |
143 | sempred(localctx, ruleIndex, predIndex) { | |
144 | switch(ruleIndex) { | |
145 | <parser.sempredFuncs.values:{f | case <f.ruleIndex>: | |
146 | return this.<f.name>_sempred(localctx, predIndex);}; separator="\n"> | |
147 | default: | |
148 | throw "No predicate with index:" + ruleIndex; | |
149 | } | |
150 | } | |
151 | ||
152 | <sempredFuncs.values; separator="\n"> | |
153 | <endif> | |
154 | ||
155 | <funcs; separator="\n"> | |
156 | ||
157 | } | |
160 | 158 | |
161 | 159 | <parser.name>.EOF = antlr4.Token.EOF; |
162 | 160 | <if(parser.tokens)> |
163 | 161 | <parser.tokens:{k | <parser.name>.<k> = <parser.tokens.(k)>;}; separator="\n", wrap, anchor> |
164 | 162 | <endif> |
165 | 163 | |
164 | <if(parser.rules)> | |
166 | 165 | <parser.rules:{r | <parser.name>.RULE_<r.name> = <r.index>;}; separator="\n", wrap, anchor> |
167 | ||
168 | <funcs; separator="\n"> | |
169 | ||
170 | <if(sempredFuncs)> | |
171 | <parser.name>.prototype.sempred = function(localctx, ruleIndex, predIndex) { | |
172 | switch(ruleIndex) { | |
173 | <parser.sempredFuncs.values:{f | case <f.ruleIndex>: | |
174 | return this.<f.name>_sempred(localctx, predIndex);}; separator="\n"> | |
175 | default: | |
176 | throw "No predicate with index:" + ruleIndex; | |
177 | } | |
178 | }; | |
179 | ||
180 | <sempredFuncs.values; separator="\n"> | |
181 | <endif> | |
182 | ||
183 | exports.<parser.name> = <parser.name>; | |
184 | ||
166 | <endif> | |
167 | ||
168 | <funcs:{f | <ruleContexts(f)>}; separator="\n"> | |
169 | ||
170 | <! Define fields of this parser to export the context classes !> | |
171 | <parser.funcs:{f | <parser.name>.<f.ctxType> = <f.ctxType>; }; separator="\n"> | |
172 | ||
173 | >> | |
174 | ||
175 | ruleContexts(currentRule) ::= << | |
176 | <currentRule.ruleCtx> | |
177 | ||
178 | <currentRule.altLabelCtxs:{l | <currentRule.altLabelCtxs.(l)>}; separator="\n"> | |
185 | 179 | >> |
186 | 180 | |
187 | 181 | dumpActions(recog, argFuncs, actionFuncs, sempredFuncs) ::= << |
235 | 229 | * overriding implementation impossible to maintain. |
236 | 230 | */ |
237 | 231 | RuleSempredFunction(r, actions) ::= << |
238 | <if (r.factory.g.lexer)><lexer.name><else><parser.name><endif>.prototype.<r.name>_sempred = function(localctx, predIndex) { | |
232 | <if (r.factory.g.lexer)><lexer.name>.prototype.<r.name>_sempred = function<else><r.name>_sempred<endif>(localctx, predIndex) { | |
239 | 233 | switch(predIndex) { |
240 | 234 | <actions:{index| case <index>: |
241 | 235 | return <actions.(index)>;}; separator="\n"> |
248 | 242 | |
249 | 243 | RuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,postamble,exceptions) ::= << |
250 | 244 | |
251 | <ruleCtx> | |
252 | ||
253 | <altLabelCtxs:{l | <altLabelCtxs.(l)>}; separator="\n"> | |
254 | ||
255 | <! Define fields of this parser to export the context classes !> | |
256 | <parser.name>.<currentRule.ctxType> = <currentRule.ctxType>; | |
257 | ||
258 | <parser.name>.prototype.<currentRule.name> = function(<currentRule.args:{a | <a.name>}; separator=", ">) { | |
259 | ||
260 | var localctx = new <currentRule.ctxType>(this, this._ctx, this.state<currentRule.args:{a | , <a.name>}>); | |
245 | ||
246 | <currentRule.name>(<currentRule.args:{a | <a.name>}; separator=", ">) { | |
247 | let localctx = new <currentRule.ctxType>(this, this._ctx, this.state<currentRule.args:{a | , <a.name>}>); | |
261 | 248 | this.enterRule(localctx, <currentRule.startState>, <parser.name>.RULE_<currentRule.name>); |
262 | 249 | <namedActions.init> |
263 | 250 | <locals; separator="\n"> |
265 | 252 | <code> |
266 | 253 | <postamble; separator="\n"> |
267 | 254 | <namedActions.after> |
268 | <if(exceptions)> | |
255 | }<if(exceptions)> | |
269 | 256 | <exceptions; separator="\n"> |
270 | <else> | |
271 | } catch (re) { | |
257 | <else> catch (re) { | |
272 | 258 | if(re instanceof antlr4.error.RecognitionException) { |
273 | 259 | localctx.exception = re; |
274 | 260 | this._errHandler.reportError(this, re); |
281 | 267 | this.exitRule(); |
282 | 268 | } |
283 | 269 | return localctx; |
284 | }; | |
270 | } | |
285 | 271 | |
286 | 272 | >> |
287 | 273 | |
289 | 275 | namedActions,finallyAction,postamble) ::= |
290 | 276 | << |
291 | 277 | |
292 | <ruleCtx> | |
293 | <altLabelCtxs:{l | <altLabelCtxs.(l)>}; separator="\n"> | |
294 | ||
295 | <parser.name>.prototype.<currentRule.name> = function(_p<if(currentRule.args)>, <args:{a | , <a>}><endif>) { | |
278 | <currentRule.name>(_p<if(currentRule.args)>, <args:{a | , <a>}><endif>) { | |
296 | 279 | if(_p===undefined) { |
297 | 280 | _p = 0; |
298 | 281 | } |
299 | var _parentctx = this._ctx; | |
300 | var _parentState = this.state; | |
301 | var localctx = new <currentRule.ctxType>(this, this._ctx, _parentState<args:{a | , <a.name>}>); | |
302 | var _prevctx = localctx; | |
303 | var _startState = <currentRule.startState>; | |
282 | const _parentctx = this._ctx; | |
283 | const _parentState = this.state; | |
284 | let localctx = new <currentRule.ctxType>(this, this._ctx, _parentState<args:{a | , <a.name>}>); | |
285 | let _prevctx = localctx; | |
286 | const _startState = <currentRule.startState>; | |
304 | 287 | this.enterRecursionRule(localctx, <currentRule.startState>, <parser.name>.RULE_<currentRule.name>, _p); |
305 | 288 | <namedActions.init> |
306 | 289 | <locals; separator="\n"> |
321 | 304 | this.unrollRecursionContexts(_parentctx) |
322 | 305 | } |
323 | 306 | return localctx; |
324 | }; | |
307 | } | |
325 | 308 | |
326 | 309 | >> |
327 | 310 | |
596 | 579 | ThisRulePropertyRef_ctx(r) ::= "localctx" |
597 | 580 | ThisRulePropertyRef_parser(r) ::= "this" |
598 | 581 | |
599 | NonLocalAttrRef(s) ::= "getInvokingContext(<s.ruleIndex>).<s.name>" | |
600 | SetNonLocalAttr(s, rhsChunks) ::= "getInvokingContext(<s.ruleIndex>).<s.name> = <rhsChunks>" | |
582 | NonLocalAttrRef(s) ::= "this.getInvokingContext(<s.ruleIndex>).<s.name>" | |
583 | SetNonLocalAttr(s, rhsChunks) ::= "this.getInvokingContext(<s.ruleIndex>).<s.name> = <rhsChunks>" | |
601 | 584 | |
602 | 585 | AddToLabelList(a) ::= "<ctx(a.label)>.<a.listName>.push(<labelref(a.label)>);" |
603 | 586 | |
608 | 591 | RuleContextListDecl(rdecl) ::= "this.<rdecl.name> = []; // of <rdecl.ctxName>s" |
609 | 592 | |
610 | 593 | ContextTokenGetterDecl(t) ::= << |
611 | <t.name> = function() { | |
594 | <t.name>() { | |
612 | 595 | return this.getToken(<parser.name>.<t.name>, 0); |
613 | 596 | }; |
614 | 597 | >> |
615 | 598 | |
616 | 599 | // should never be called |
617 | 600 | ContextTokenListGetterDecl(t) ::= << |
618 | def <t.name>_list(self): | |
619 | return self.getTokens(<parser.name>.<t.name>) | |
601 | <t.name>_list() { | |
602 | return this.getTokens(<parser.name>.<t.name>); | |
603 | } | |
620 | 604 | >> |
621 | 605 | |
622 | 606 | ContextTokenListIndexedGetterDecl(t) ::= << |
634 | 618 | >> |
635 | 619 | |
636 | 620 | ContextRuleGetterDecl(r) ::= << |
637 | <r.name> = function() { | |
621 | <r.name>() { | |
638 | 622 | return this.getTypedRuleContext(<r.ctxName>,0); |
639 | 623 | }; |
640 | 624 | >> |
641 | 625 | |
642 | 626 | // should never be called |
643 | 627 | ContextRuleListGetterDecl(r) ::= << |
644 | def <r.name>_list(self): | |
645 | return self.getTypedRuleContexts(<parser.name>.<r.ctxName>) | |
646 | ||
628 | <r.name>_list() { | |
629 | return this.getTypedRuleContexts(<parser.name>.<r.ctxName>); | |
630 | } | |
647 | 631 | >> |
648 | 632 | |
649 | 633 | ContextRuleListIndexedGetterDecl(r) ::= << |
675 | 659 | CaptureNextTokenType(d) ::= "<d.varName> = this._input.LA(1);" |
676 | 660 | |
677 | 661 | StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers) ::= << |
678 | function <struct.name>(parser, parent, invokingState<struct.ctorAttrs:{a | , <a.name>}>) { | |
679 | if(parent===undefined) { | |
680 | parent = null; | |
662 | class <struct.name> extends <if(contextSuperClass)><contextSuperClass><else>antlr4.ParserRuleContext<endif> { | |
663 | ||
664 | constructor(parser, parent, invokingState<struct.ctorAttrs:{a | , <a.name>}>) { | |
665 | if(parent===undefined) { | |
666 | parent = null; | |
667 | } | |
668 | if(invokingState===undefined || invokingState===null) { | |
669 | invokingState = -1; | |
670 | } | |
671 | super(parent, invokingState); | |
672 | this.parser = parser; | |
673 | this.ruleIndex = <parser.name>.RULE_<struct.derivedFromName>; | |
674 | <attrs:{a | <a>}; separator="\n"> | |
675 | <struct.ctorAttrs:{a | this.<a.name> = <a.name> || null;}; separator="\n"> | |
676 | } | |
677 | ||
678 | <getters:{g | <g>}; separator="\n\n"> | |
679 | ||
680 | <if(struct.provideCopyFrom)> <! don't need copy unless we have subclasses !> | |
681 | copyFrom(ctx) { | |
682 | super.copyFrom(ctx); | |
683 | <struct.attrs:{a | this.<a.name> = ctx.<a.name>;}; separator="\n"> | |
681 | 684 | } |
682 | if(invokingState===undefined || invokingState===null) { | |
683 | invokingState = -1; | |
684 | } | |
685 | <if(contextSuperClass)><contextSuperClass><else>antlr4.ParserRuleContext<endif>.call(this, parent, invokingState); | |
686 | this.parser = parser; | |
687 | this.ruleIndex = <parser.name>.RULE_<struct.derivedFromName>; | |
688 | <attrs:{a | <a>}; separator="\n"> | |
689 | <struct.ctorAttrs:{a | this.<a.name> = <a.name> || null;}; separator="\n"> | |
690 | return this; | |
691 | } | |
692 | ||
693 | <struct.name>.prototype = Object.create(<if(contextSuperClass)><contextSuperClass><else>antlr4.ParserRuleContext<endif>.prototype); | |
694 | <struct.name>.prototype.constructor = <struct.name>; | |
695 | ||
696 | <getters:{g | <struct.name>.prototype.<g>}; separator="\n\n"> | |
697 | ||
698 | <if(struct.provideCopyFrom)> <! don't need copy unless we have subclasses !> | |
699 | <struct.name>.prototype.copyFrom = function(ctx) { | |
700 | <if(contextSuperClass)><contextSuperClass><else>antlr4.ParserRuleContext<endif>.prototype.copyFrom.call(this, ctx); | |
701 | <struct.attrs:{a | this.<a.name> = ctx.<a.name>;}; separator="\n"> | |
702 | }; | |
703 | <endif> | |
704 | <dispatchMethods; separator="\n"> | |
705 | <extensionMembers; separator="\n"> | |
685 | <endif> | |
686 | <dispatchMethods; separator="\n"> | |
687 | <extensionMembers; separator="\n"> | |
688 | ||
689 | } | |
706 | 690 | |
707 | 691 | >> |
708 | 692 | |
709 | 693 | AltLabelStructDecl(struct,attrs,getters,dispatchMethods) ::= << |
710 | function <struct.name>(parser, ctx) { | |
711 | <currentRule.name; format="cap">Context.call(this, parser); | |
712 | <attrs:{a | <a>;}; separator="\n"> | |
713 | <currentRule.name; format="cap">Context.prototype.copyFrom.call(this, ctx); | |
714 | return this; | |
715 | } | |
716 | ||
717 | <struct.name>.prototype = Object.create(<currentRule.name; format="cap">Context.prototype); | |
718 | <struct.name>.prototype.constructor = <struct.name>; | |
694 | class <struct.name> extends <struct.parentRule; format="cap">Context { | |
695 | ||
696 | constructor(parser, ctx) { | |
697 | super(parser); | |
698 | <attrs:{a | <a>;}; separator="\n"> | |
699 | super.copyFrom(ctx); | |
700 | } | |
701 | ||
702 | <getters:{g | <g>}; separator="\n\n"> | |
703 | ||
704 | <dispatchMethods; separator="\n"> | |
705 | ||
706 | } | |
719 | 707 | |
720 | 708 | <! Define fields of this parser to export this struct/context class !> |
721 | 709 | <parser.name>.<struct.name> = <struct.name>; |
722 | 710 | |
723 | <getters:{g | <struct.name>.prototype.<g>}; separator="\n\n"> | |
724 | <dispatchMethods; separator="\n"> | |
725 | ||
726 | 711 | >> |
727 | 712 | |
728 | 713 | ListenerDispatchMethod(method) ::= << |
729 | <struct.name>.prototype.<if(method.isEnter)>enter<else>exit<endif>Rule = function(listener) { | |
714 | <if(method.isEnter)>enter<else>exit<endif>Rule(listener) { | |
730 | 715 | if(listener instanceof <parser.grammarName>Listener ) { |
731 | 716 | listener.<if(method.isEnter)>enter<else>exit<endif><struct.derivedFromName; format="cap">(this); |
732 | 717 | } |
733 | }; | |
718 | } | |
734 | 719 | |
735 | 720 | >> |
736 | 721 | |
737 | 722 | VisitorDispatchMethod(method) ::= << |
738 | <struct.name>.prototype.accept = function(visitor) { | |
723 | accept(visitor) { | |
739 | 724 | if ( visitor instanceof <parser.grammarName>Visitor ) { |
740 | 725 | return visitor.visit<struct.derivedFromName; format="cap">(this); |
741 | 726 | } else { |
742 | 727 | return visitor.visitChildren(this); |
743 | 728 | } |
744 | }; | |
729 | } | |
745 | 730 | |
746 | 731 | >> |
747 | 732 | |
792 | 777 | |
793 | 778 | LexerFile(lexerFile, lexer, namedActions) ::= << |
794 | 779 | <fileHeader(lexerFile.grammarFileName, lexerFile.ANTLRVersion)> |
795 | var antlr4 = require('antlr4/index'); | |
780 | import antlr4 from 'antlr4'; | |
796 | 781 | |
797 | 782 | <namedActions.header> |
798 | 783 | |
802 | 787 | |
803 | 788 | Lexer(lexer, atn, actionFuncs, sempredFuncs, superClass) ::= << |
804 | 789 | <if(superClass)> |
805 | var <superClass> = require('./<superClass>').<superClass>; | |
790 | import <superClass> from './<superClass>.js'; | |
806 | 791 | <endif> |
807 | 792 | |
808 | 793 | <atn> |
809 | 794 | |
810 | var atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN); | |
811 | ||
812 | var decisionsToDFA = atn.decisionToState.map( function(ds, index) { return new antlr4.dfa.DFA(ds, index); }); | |
813 | ||
814 | function <lexer.name>(input) { | |
815 | <if(superClass)><superClass><else>antlr4.Lexer<endif>.call(this, input); | |
816 | this._interp = new antlr4.atn.LexerATNSimulator(this, atn, decisionsToDFA, new antlr4.PredictionContextCache()); | |
817 | return this; | |
818 | } | |
819 | ||
820 | <lexer.name>.prototype = Object.create(<if(superClass)><superClass><else>antlr4.Lexer<endif>.prototype); | |
821 | <lexer.name>.prototype.constructor = <lexer.name>; | |
822 | ||
823 | Object.defineProperty(<lexer.name>.prototype, "atn", { | |
824 | get : function() { | |
825 | return atn; | |
826 | } | |
827 | }); | |
795 | const atn = new antlr4.atn.ATNDeserializer().deserialize(serializedATN); | |
796 | ||
797 | const decisionsToDFA = atn.decisionToState.map( (ds, index) => new antlr4.dfa.DFA(ds, index) ); | |
798 | ||
799 | export default class <lexer.name> extends <if(superClass)><superClass><else>antlr4.Lexer<endif> { | |
800 | ||
801 | static grammarFileName = "<lexer.grammarFileName>"; | |
802 | static channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN"<if (lexer.channels)>, <lexer.channels:{c| "<c>"}; separator=", ", wrap, anchor><endif> ]; | |
803 | static modeNames = [ <lexer.modes:{m| "<m>"}; separator=", ", wrap, anchor> ]; | |
804 | static literalNames = [ <lexer.literalNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ]; | |
805 | static symbolicNames = [ <lexer.symbolicNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ]; | |
806 | static ruleNames = [ <lexer.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> ]; | |
807 | ||
808 | constructor(input) { | |
809 | super(input) | |
810 | this._interp = new antlr4.atn.LexerATNSimulator(this, atn, decisionsToDFA, new antlr4.PredictionContextCache()); | |
811 | <namedActions.members> | |
812 | } | |
813 | ||
814 | get atn() { | |
815 | return atn; | |
816 | } | |
817 | } | |
828 | 818 | |
829 | 819 | <lexer.name>.EOF = antlr4.Token.EOF; |
820 | <if(lexer.tokens)> | |
830 | 821 | <lexer.tokens:{k | <lexer.name>.<k> = <lexer.tokens.(k)>;}; separator="\n", wrap, anchor> |
822 | <endif> | |
831 | 823 | |
832 | 824 | <if(lexer.channels)> |
833 | 825 | <lexer.channels:{c| <lexer.name>.<c> = <lexer.channels.(c)>;}; separator="\n"> |
837 | 829 | <rest(lexer.modes):{m| <lexer.name>.<m> = <i>;}; separator="\n"> |
838 | 830 | |
839 | 831 | <endif> |
840 | <lexer.name>.prototype.channelNames = [ "DEFAULT_TOKEN_CHANNEL", "HIDDEN"<if (lexer.channels)>, <lexer.channels:{c| "<c>"}; separator=", ", wrap, anchor><endif> ]; | |
841 | ||
842 | <lexer.name>.prototype.modeNames = [ <lexer.modes:{m| "<m>"}; separator=", ", wrap, anchor> ]; | |
843 | ||
844 | <lexer.name>.prototype.literalNames = [ <lexer.literalNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ]; | |
845 | ||
846 | <lexer.name>.prototype.symbolicNames = [ <lexer.symbolicNames:{t | <t>}; null="null", separator=", ", wrap, anchor> ]; | |
847 | ||
848 | <lexer.name>.prototype.ruleNames = [ <lexer.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> ]; | |
849 | ||
850 | <lexer.name>.prototype.grammarFileName = "<lexer.grammarFileName>"; | |
851 | ||
852 | <namedActions.members> | |
853 | 832 | |
854 | 833 | <dumpActions(lexer, "", actionFuncs, sempredFuncs)> |
855 | 834 | |
856 | exports.<lexer.name> = <lexer.name>; | |
857 | 835 | |
858 | 836 | >> |
859 | 837 | |
860 | 838 | SerializedATN(model) ::= << |
861 | 839 | <! only one segment, can be inlined !> |
862 | 840 | |
863 | var serializedATN = ["<model.serialized; wrap={",<\n> "}>"].join(""); | |
841 | const serializedATN = ["<model.serialized; wrap={",<\n> "}>"].join(""); | |
864 | 842 | |
865 | 843 | >> |
866 | 844 |
0 | /* | |
1 | * [The "BSD license"] | |
2 | * Copyright (c) 2012-2016 Terence Parr | |
3 | * Copyright (c) 2012-2016 Sam Harwell | |
4 | * All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. The name of the author may not be used to endorse or promote products | |
16 | * derived from this software without specific prior written permission. | |
17 | * | |
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | */ | |
29 | ||
30 | phpTypeInitMap ::= [ | |
31 | "int":"0", | |
32 | "long":"0", | |
33 | "float":"0.0", | |
34 | "double":"0.0", | |
35 | "boolean":"false", | |
36 | default:"null" | |
37 | ] | |
38 | ||
39 | // args must be <object-model-object>, <fields-resulting-in-STs> | |
40 | ||
41 | ParserFile(file, parser, namedActions, contextSuperClass) ::= << | |
42 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> | |
43 | <parser> | |
44 | >> | |
45 | ||
46 | ListenerFile(file, header, namedActions) ::= << | |
47 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> | |
48 | <if(file.genPackage)> | |
49 | namespace <file.genPackage>; | |
50 | <endif> | |
51 | <header> | |
52 | use Antlr\\Antlr4\\Runtime\\Tree\\ParseTreeListener; | |
53 | ||
54 | /** | |
55 | * This interface defines a complete listener for a parse tree produced by | |
56 | * {@see <file.parserName>}. | |
57 | */ | |
58 | interface <file.grammarName>Listener extends ParseTreeListener { | |
59 | <file.listenerNames:{lname | | |
60 | /** | |
61 | <if(file.listenerLabelRuleNames.(lname))> | |
62 | * Enter a parse tree produced by the `<lname>` | |
63 | * labeled alternative in {@see <file.parserName>::<file.listenerLabelRuleNames.(lname)>()\}. | |
64 | <else> | |
65 | * Enter a parse tree produced by {@see <file.parserName>::<lname>()\}. | |
66 | <endif> | |
67 | * @param $context The parse tree. | |
68 | */ | |
69 | public function enter<lname; format="cap">(Context\\<lname; format="cap">Context $context) : void; | |
70 | /** | |
71 | <if(file.listenerLabelRuleNames.(lname))> | |
72 | * Exit a parse tree produced by the `<lname>` labeled alternative | |
73 | * in {@see <file.parserName>::<file.listenerLabelRuleNames.(lname)>()\}. | |
74 | <else> | |
75 | * Exit a parse tree produced by {@see <file.parserName>::<lname>()\}. | |
76 | <endif> | |
77 | * @param $context The parse tree. | |
78 | */ | |
79 | public function exit<lname; format="cap">(Context\\<lname; format="cap">Context $context) : void;}; separator="\n"> | |
80 | } | |
81 | >> | |
82 | ||
83 | BaseListenerFile(file, header, namedActions) ::= << | |
84 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> | |
85 | <if(file.genPackage)> | |
86 | namespace <file.genPackage>; | |
87 | <endif> | |
88 | <header> | |
89 | ||
90 | use Antlr\\Antlr4\\Runtime\\ParserRuleContext; | |
91 | use Antlr\\Antlr4\\Runtime\\Tree\\ErrorNode; | |
92 | use Antlr\\Antlr4\\Runtime\\Tree\\TerminalNode; | |
93 | ||
94 | /** | |
95 | * This class provides an empty implementation of {@see <file.grammarName>Listener}, | |
96 | * which can be extended to create a listener which only needs to handle a subset | |
97 | * of the available methods. | |
98 | */ | |
99 | class <file.grammarName>BaseListener implements <file.grammarName>Listener | |
100 | { | |
101 | <file.listenerNames:{lname | | |
102 | /** | |
103 | * {@inheritdoc\} | |
104 | * | |
105 | * The default implementation does nothing. | |
106 | */ | |
107 | public function enter<lname; format="cap">(Context\\<lname; format="cap">Context $context) : void {\} | |
108 | ||
109 | /** | |
110 | * {@inheritdoc\} | |
111 | * | |
112 | * The default implementation does nothing. | |
113 | */ | |
114 | public function exit<lname; format="cap">(Context\\<lname; format="cap">Context $context) : void {\}}; separator="\n"> | |
115 | ||
116 | /** | |
117 | * {@inheritdoc\} | |
118 | * | |
119 | * The default implementation does nothing. | |
120 | */ | |
121 | public function enterEveryRule(ParserRuleContext $context) : void {} | |
122 | ||
123 | /** | |
124 | * {@inheritdoc\} | |
125 | * | |
126 | * The default implementation does nothing. | |
127 | */ | |
128 | public function exitEveryRule(ParserRuleContext $context) : void {} | |
129 | ||
130 | /** | |
131 | * {@inheritdoc\} | |
132 | * | |
133 | * The default implementation does nothing. | |
134 | */ | |
135 | public function visitTerminal(TerminalNode $node) : void {} | |
136 | ||
137 | /** | |
138 | * {@inheritdoc\} | |
139 | * | |
140 | * The default implementation does nothing. | |
141 | */ | |
142 | public function visitErrorNode(ErrorNode $node) : void {} | |
143 | } | |
144 | >> | |
145 | ||
146 | VisitorFile(file, header, namedActions) ::= << | |
147 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> | |
148 | <if(file.genPackage)> | |
149 | namespace <file.genPackage>; | |
150 | <endif> | |
151 | ||
152 | <header> | |
153 | use Antlr\\Antlr4\\Runtime\\Tree\\ParseTreeVisitor; | |
154 | ||
155 | /** | |
156 | * This interface defines a complete generic visitor for a parse tree produced by {@see <file.parserName>}. | |
157 | */ | |
158 | interface <file.grammarName>Visitor extends ParseTreeVisitor | |
159 | { | |
160 | <file.visitorNames:{lname | | |
161 | /** | |
162 | <if(file.visitorLabelRuleNames.(lname))> | |
163 | * Visit a parse tree produced by the `<lname>` labeled alternative | |
164 | * in {@see <file.parserName>::<file.visitorLabelRuleNames.(lname)>()\}. | |
165 | <else> | |
166 | * Visit a parse tree produced by {@see <file.parserName>::<lname>()\}. | |
167 | <endif> | |
168 | * | |
169 | * @param Context\\<lname; format="cap">Context $context The parse tree. | |
170 | * | |
171 | * @return mixed The visitor result. | |
172 | */ | |
173 | public function visit<lname; format="cap">(Context\\<lname; format="cap">Context $context);}; separator="\n\n"> | |
174 | } | |
175 | >> | |
176 | ||
177 | BaseVisitorFile(file, header, namedActions) ::= << | |
178 | <fileHeader(file.grammarFileName, file.ANTLRVersion)> | |
179 | <if(file.genPackage)> | |
180 | namespace <file.genPackage>; | |
181 | <endif> | |
182 | <header> | |
183 | use Antlr\\Antlr4\\Runtime\\Tree\\AbstractParseTreeVisitor; | |
184 | ||
185 | /** | |
186 | * This class provides an empty implementation of {@see <file.grammarName>Visitor}, | |
187 | * which can be extended to create a visitor which only needs to handle a subset | |
188 | * of the available methods. | |
189 | */ | |
190 | class <file.grammarName>BaseVisitor extends AbstractParseTreeVisitor implements <file.grammarName>Visitor | |
191 | { | |
192 | <file.visitorNames:{lname | | |
193 | /** | |
194 | * {@inheritdoc\} | |
195 | * | |
196 | * The default implementation returns the result of calling | |
197 | * {@see self::visitChildren()\} on `context`. | |
198 | */ | |
199 | public function visit<lname; format="cap">(Context\\<lname; format="cap">Context $context) | |
200 | { | |
201 | return $this->visitChildren($context); | |
202 | \}}; separator="\n\n"> | |
203 | } | |
204 | >> | |
205 | ||
206 | fileHeader(grammarFileName, ANTLRVersion) ::= << | |
207 | \<?php | |
208 | ||
209 | /* | |
210 | * Generated from <grammarFileName> by ANTLR <ANTLRVersion> | |
211 | */ | |
212 | ||
213 | >> | |
214 | Parser(parser, funcs, atn, sempredFuncs, superClass) ::= << | |
215 | <Parser_(ctor="parser_ctor", ...)> | |
216 | >> | |
217 | ||
218 | Parser_(parser, funcs, atn, sempredFuncs, ctor, superClass) ::= << | |
219 | namespace<if(file.genPackage)> <file.genPackage><endif> { | |
220 | <if(namedActions.header)><namedActions.header><endif> | |
221 | use Antlr\\Antlr4\\Runtime\\Atn\\ATN; | |
222 | use Antlr\\Antlr4\\Runtime\\Atn\\ATNDeserializer; | |
223 | use Antlr\\Antlr4\\Runtime\\Atn\\ParserATNSimulator; | |
224 | use Antlr\\Antlr4\\Runtime\\Dfa\\DFA; | |
225 | use Antlr\\Antlr4\\Runtime\\Error\\Exceptions\\FailedPredicateException; | |
226 | use Antlr\\Antlr4\\Runtime\\Error\\Exceptions\\NoViableAltException; | |
227 | use Antlr\\Antlr4\\Runtime\\PredictionContexts\\PredictionContextCache; | |
228 | use Antlr\\Antlr4\\Runtime\\Error\\Exceptions\\RecognitionException; | |
229 | use Antlr\\Antlr4\\Runtime\\RuleContext; | |
230 | use Antlr\\Antlr4\\Runtime\\Token; | |
231 | use Antlr\\Antlr4\\Runtime\\TokenStream; | |
232 | use Antlr\\Antlr4\\Runtime\\Vocabulary; | |
233 | use Antlr\\Antlr4\\Runtime\\VocabularyImpl; | |
234 | use Antlr\\Antlr4\\Runtime\\RuntimeMetaData; | |
235 | use Antlr\\Antlr4\\Runtime\\Parser; | |
236 | <if(namedActions.definitions)><namedActions.definitions><endif> | |
237 | ||
238 | final class <parser.name> extends <superClass; null="Parser"> | |
239 | { | |
240 | <if(parser.tokens)> | |
241 | public const <parser.tokens:{k | <k> = <parser.tokens.(k)>}; separator=", ", wrap, anchor>; | |
242 | <endif> | |
243 | ||
244 | <if(parser.rules)> | |
245 | public const <parser.rules:{r | RULE_<r.name> = <r.index>}; separator=", ", wrap, anchor>; | |
246 | <endif> | |
247 | ||
248 | /** | |
249 | * @var array\<string> | |
250 | */ | |
251 | public const RULE_NAMES = [ | |
252 | <parser.ruleNames:{r | '<r>'}; separator=", ", wrap, anchor> | |
253 | ]; | |
254 | ||
255 | <vocabulary(parser.literalNames, parser.symbolicNames)> | |
256 | ||
257 | <atn> | |
258 | protected static $atn; | |
259 | protected static $decisionToDFA; | |
260 | protected static $sharedContextCache; | |
261 | <if(namedActions.members)> | |
262 | ||
263 | <namedActions.members> | |
264 | <endif> | |
265 | ||
266 | ||
267 | <parser:(ctor)()> | |
268 | ||
269 | private static function initialize() : void | |
270 | { | |
271 | if (self::$atn !== null) { | |
272 | return; | |
273 | } | |
274 | ||
275 | RuntimeMetaData::checkVersion('<file.ANTLRVersion>', RuntimeMetaData::VERSION); | |
276 | ||
277 | $atn = (new ATNDeserializer())->deserialize(self::SERIALIZED_ATN); | |
278 | ||
279 | $decisionToDFA = []; | |
280 | for ($i = 0, $count = $atn->getNumberOfDecisions(); $i \< $count; $i++) { | |
281 | $decisionToDFA[] = new DFA($atn->getDecisionState($i), $i); | |
282 | } | |
283 | ||
284 | self::$atn = $atn; | |
285 | self::$decisionToDFA = $decisionToDFA; | |
286 | self::$sharedContextCache = new PredictionContextCache(); | |
287 | } | |
288 | ||
289 | public function getGrammarFileName() : string | |
290 | { | |
291 | return "<parser.grammarFileName>"; | |
292 | } | |
293 | ||
294 | public function getRuleNames() : array | |
295 | { | |
296 | return self::RULE_NAMES; | |
297 | } | |
298 | ||
299 | public function getSerializedATN() : string | |
300 | { | |
301 | return self::SERIALIZED_ATN; | |
302 | } | |
303 | ||
304 | public function getATN() : ATN | |
305 | { | |
306 | return self::$atn; | |
307 | } | |
308 | ||
309 | public function getVocabulary() : Vocabulary | |
310 | { | |
311 | static $vocabulary; | |
312 | ||
313 | return $vocabulary = $vocabulary ?? new VocabularyImpl(self::LITERAL_NAMES, self::SYMBOLIC_NAMES); | |
314 | } | |
315 | <if(funcs)> | |
316 | ||
317 | <funcs; separator="\n\n"> | |
318 | <endif> | |
319 | <if(sempredFuncs)> | |
320 | ||
321 | public function sempred(?RuleContext $localContext, int $ruleIndex, int $predicateIndex) : bool | |
322 | { | |
323 | switch ($ruleIndex) { | |
324 | <parser.sempredFuncs.values:{f| | |
325 | case <f.ruleIndex>: | |
326 | return $this->sempred<f.name; format="cap">($localContext, $predicateIndex);}; separator="\n\n"> | |
327 | ||
328 | default: | |
329 | return true; | |
330 | } | |
331 | } | |
332 | ||
333 | <sempredFuncs.values; separator="\n\n"> | |
334 | <endif> | |
335 | } | |
336 | } | |
337 | ||
338 | namespace <if(file.genPackage)><file.genPackage>\\<endif>Context { | |
339 | use Antlr\\Antlr4\\Runtime\\ParserRuleContext; | |
340 | use Antlr\\Antlr4\\Runtime\\Token; | |
341 | use Antlr\\Antlr4\\Runtime\\Tree\\ParseTreeVisitor; | |
342 | use Antlr\\Antlr4\\Runtime\\Tree\\TerminalNode; | |
343 | use Antlr\\Antlr4\\Runtime\\Tree\\ParseTreeListener; | |
344 | use <if(file.genPackage)><file.genPackage>\\<endif><parser.name>; | |
345 | <if (file.genVisitor)>use <if(file.genPackage)><file.genPackage>\\<endif><file.grammarName>Visitor;<endif> | |
346 | <if (file.genListener)>use <if(file.genPackage)><file.genPackage>\\<endif><file.grammarName>Listener;<endif> | |
347 | <namedActions.contexts> | |
348 | ||
349 | <funcs :{ func | <func.ruleCtx><if(func.altLabelCtxs)> | |
350 | ||
351 | <func.altLabelCtxs:{l | <func.altLabelCtxs.(l)>}; separator="\n\n"><endif> }; separator="\n\n"> | |
352 | } | |
353 | >> | |
354 | ||
355 | vocabulary(literalNames, symbolicNames) ::= << | |
356 | /** | |
357 | * @var array\<string|null> | |
358 | */ | |
359 | private const LITERAL_NAMES = [ | |
360 | <literalNames:{t | <t>}; null="null", separator=", ", wrap, anchor> | |
361 | ]; | |
362 | ||
363 | /** | |
364 | * @var array\<string> | |
365 | */ | |
366 | private const SYMBOLIC_NAMES = [ | |
367 | <symbolicNames:{t | <t>}; null="null", separator=", ", wrap, anchor> | |
368 | ]; | |
369 | >> | |
370 | ||
371 | dumpActions(recog, argFuncs, actionFuncs, sempredFuncs) ::= << | |
372 | <if(actionFuncs)> | |
373 | ||
374 | public function action(?RuleContext $localContext, int $ruleIndex, int $actionIndex) : void | |
375 | { | |
376 | switch ($ruleIndex) { | |
377 | <recog.actionFuncs.values:{f| | |
378 | case <f.ruleIndex>: | |
379 | $this->action<f.name; format="cap">($localContext, $actionIndex); | |
380 | break;}; separator="\n\n"> | |
381 | } | |
382 | } | |
383 | ||
384 | <actionFuncs.values; separator="\n"> | |
385 | <endif> | |
386 | <if(sempredFuncs)> | |
387 | ||
388 | public function sempred(?RuleContext $localContext, int $ruleIndex, int $predicateIndex) : bool | |
389 | { | |
390 | switch ($ruleIndex) { | |
391 | <recog.sempredFuncs.values:{f| | |
392 | case <f.ruleIndex>: | |
393 | return $this->sempred<f.name; format="cap">($localContext, $predicateIndex);}; separator="\n\n"> | |
394 | } | |
395 | ||
396 | return true; | |
397 | } | |
398 | <sempredFuncs.values; separator="\n\n"> | |
399 | <endif> | |
400 | >> | |
401 | ||
402 | parser_ctor(p) ::= << | |
403 | public function __construct(TokenStream $input) | |
404 | { | |
405 | parent::__construct($input); | |
406 | ||
407 | self::initialize(); | |
408 | ||
409 | $this->interp = new ParserATNSimulator($this, self::$atn, self::$decisionToDFA, self::$sharedContextCache); | |
410 | } | |
411 | >> | |
412 | ||
413 | /** | |
414 | * This generates a private method since the actionIndex is generated, making | |
415 | * an overriding implementation impossible to maintain. | |
416 | */ | |
417 | RuleActionFunction(r, actions) ::= << | |
418 | private function action<r.name; format="cap">(?<r.ctxType> $localContext, int $actionIndex) : void | |
419 | { | |
420 | switch ($actionIndex) { | |
421 | <actions:{index| | |
422 | case <index>: | |
423 | <actions.(index)> | |
424 | ||
425 | break;}; separator="\n\n"> | |
426 | } | |
427 | } | |
428 | >> | |
429 | ||
430 | /** | |
431 | * This generates a private method since the predicateIndex is generated, making | |
432 | * an overriding implementation impossible to maintain. | |
433 | */ | |
434 | RuleSempredFunction(r, actions) ::= << | |
435 | private function sempred<r.name; format="cap">(?Context\\<r.ctxType> $localContext, int $predicateIndex) : bool | |
436 | { | |
437 | switch ($predicateIndex) { | |
438 | <actions:{index| | |
439 | case <index>: | |
440 | return <actions.(index)>;}; separator="\n\n"> | |
441 | } | |
442 | ||
443 | return true; | |
444 | } | |
445 | >> | |
446 | ||
447 | RuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,exceptions,postamble) ::= << | |
448 | /** | |
449 | * @throws RecognitionException | |
450 | */ | |
451 | <if(currentRule.modifiers)><currentRule.modifiers:{f | <f> }><endif>public function <currentRule.name>(<args; separator=",">) : Context\\<currentRule.ctxType> | |
452 | { | |
453 | $localContext = new Context\\<currentRule.ctxType>($this->ctx, $this->getState()<currentRule.args:{a | , $<a.name>}>); | |
454 | ||
455 | $this->enterRule($localContext, <currentRule.startState>, self::RULE_<currentRule.name>); | |
456 | <namedActions.init> | |
457 | <locals; separator="\n"> | |
458 | ||
459 | try { | |
460 | <code> | |
461 | <postamble; separator="\n"> | |
462 | <namedActions.after> | |
463 | }<if(exceptions)><exceptions; separator="\n"><else> catch (RecognitionException $exception) { | |
464 | $localContext->exception = $exception; | |
465 | $this->errorHandler->reportError($this, $exception); | |
466 | $this->errorHandler->recover($this, $exception); | |
467 | }<endif> finally { | |
468 | <finallyAction> | |
469 | $this->exitRule(); | |
470 | } | |
471 | ||
472 | return $localContext; | |
473 | } | |
474 | >> | |
475 | ||
476 | LeftRecursiveRuleFunction(currentRule,args,code,locals,ruleCtx,altLabelCtxs,namedActions,finallyAction,postamble) ::= << | |
477 | /** | |
478 | * @throws RecognitionException | |
479 | */ | |
480 | <if(currentRule.modifiers)><currentRule.modifiers:{f | <f> }><endif>public function <currentRule.name>(<args; separator=", ">) : Context\\<currentRule.ctxType> | |
481 | { | |
482 | return $this->recursive<currentRule.name; format="cap">(0<currentRule.args:{a | , <a.name>}>); | |
483 | } | |
484 | ||
485 | /** | |
486 | * @throws RecognitionException | |
487 | */ | |
488 | private function recursive<currentRule.name; format="cap">(int $precedence<args:{a | , <a>}>) : Context\\<currentRule.ctxType> | |
489 | { | |
490 | $parentContext = $this->ctx; | |
491 | $parentState = $this->getState(); | |
492 | $localContext = new Context\\<currentRule.ctxType>($this->ctx, $parentState<currentRule.args:{a | , <a.name>}>); | |
493 | $previousContext = $localContext; | |
494 | $startState = <currentRule.startState>; | |
495 | $this->enterRecursionRule($localContext, <currentRule.startState>, self::RULE_<currentRule.name>, $precedence); | |
496 | <namedActions.init> | |
497 | <locals; separator="\n"> | |
498 | ||
499 | try { | |
500 | <code> | |
501 | <postamble; separator="\n"> | |
502 | <namedActions.after> | |
503 | } catch (RecognitionException $exception) { | |
504 | $localContext->exception = $exception; | |
505 | $this->errorHandler->reportError($this, $exception); | |
506 | $this->errorHandler->recover($this, $exception); | |
507 | } finally { | |
508 | <finallyAction> | |
509 | $this->unrollRecursionContexts($parentContext); | |
510 | } | |
511 | ||
512 | return $localContext; | |
513 | } | |
514 | >> | |
515 | ||
516 | CodeBlockForOuterMostAlt(currentOuterMostAltCodeBlock, locals, preamble, ops) ::= << | |
517 | <if(currentOuterMostAltCodeBlock.altLabel)>$localContext = new Context\\<currentOuterMostAltCodeBlock.altLabel; format="cap">Context($localContext);<endif> | |
518 | $this->enterOuterAlt($localContext, <currentOuterMostAltCodeBlock.alt.altNum>); | |
519 | <CodeBlockForAlt(currentAltCodeBlock=currentOuterMostAltCodeBlock, ...)> | |
520 | >> | |
521 | ||
522 | CodeBlockForAlt(currentAltCodeBlock, locals, preamble, ops) ::= << | |
523 | <locals; separator="\n"> | |
524 | <preamble; separator="\n"> | |
525 | <ops; separator="\n"> | |
526 | >> | |
527 | ||
528 | LL1AltBlock(choice, preamble, alts, error) ::= << | |
529 | $this->setState(<choice.stateNumber>); | |
530 | $this->errorHandler->sync($this); | |
531 | <if(choice.label)><labelref(choice.label)> = $this->input->LT(1);<endif> | |
532 | <preamble; separator="\n"> | |
533 | ||
534 | switch ($this->input->LA(1)) { | |
535 | <choice.altLook,alts:{look,alt| <cases(ttypes=look)> | |
536 | <alt> | |
537 | break;}; separator="\n\n"> | |
538 | ||
539 | default: | |
540 | <error> | |
541 | } | |
542 | >> | |
543 | ||
544 | LL1OptionalBlock(choice, alts, error) ::= << | |
545 | $this->setState(<choice.stateNumber>); | |
546 | $this->errorHandler->sync($this); | |
547 | ||
548 | switch ($this->input->LA(1)) { | |
549 | <choice.altLook,alts:{look,alt| <cases(ttypes=look)> | |
550 | <alt> | |
551 | break;}; separator="\n\n"> | |
552 | ||
553 | default: | |
554 | break; | |
555 | } | |
556 | >> | |
557 | ||
558 | LL1OptionalBlockSingleAlt(choice, expr, alts, preamble, error, followExpr) ::= << | |
559 | $this->setState(<choice.stateNumber>); | |
560 | $this->errorHandler->sync($this); | |
561 | <preamble; separator="\n"> | |
562 | ||
563 | if (<expr>) { | |
564 | <alts; separator="\n"> | |
565 | } | |
566 | >> | |
567 | ||
568 | LL1StarBlockSingleAlt(choice, loopExpr, alts, preamble, iteration) ::= << | |
569 | $this->setState(<choice.stateNumber>); | |
570 | $this->errorHandler->sync($this); | |
571 | ||
572 | <preamble; separator="\n"> | |
573 | while (<loopExpr>) { | |
574 | <alts; separator="\n"> | |
575 | $this->setState(<choice.loopBackStateNumber>); | |
576 | $this->errorHandler->sync($this); | |
577 | <iteration> | |
578 | } | |
579 | >> | |
580 | ||
581 | LL1PlusBlockSingleAlt(choice, loopExpr, alts, preamble, iteration) ::= << | |
582 | $this->setState(<choice.blockStartStateNumber>); <! alt block decision !> | |
583 | $this->errorHandler->sync($this); | |
584 | ||
585 | <preamble; separator="\n"> | |
586 | do { | |
587 | <alts; separator="\n"> | |
588 | $this->setState(<choice.stateNumber>); <! loopback/exit decision !> | |
589 | $this->errorHandler->sync($this); | |
590 | <iteration> | |
591 | } while (<loopExpr>); | |
592 | >> | |
593 | ||
594 | // LL(*) stuff | |
595 | ||
596 | AltBlock(choice, preamble, alts, error) ::= << | |
597 | $this->setState(<choice.stateNumber>); | |
598 | $this->errorHandler->sync($this); | |
599 | <if(choice.label)><labelref(choice.label)> = $this->input->LT(1);<endif> | |
600 | <preamble; separator="\n"> | |
601 | ||
602 | switch ($this->getInterpreter()->adaptivePredict($this->input, <choice.decision>, $this->ctx)) { | |
603 | <alts:{alt | | |
604 | case <i>: | |
605 | <alt> | |
606 | break;}; separator="\n\n"> | |
607 | } | |
608 | >> | |
609 | ||
610 | OptionalBlock(choice, alts, error) ::= << | |
611 | $this->setState(<choice.stateNumber>); | |
612 | $this->errorHandler->sync($this); | |
613 | ||
614 | switch ($this->getInterpreter()->adaptivePredict($this->input, <choice.decision>, $this->ctx)) { | |
615 | <alts:{alt | | |
616 | case <i><if(!choice.ast.greedy)>+1<endif>: | |
617 | <alt> | |
618 | break;}; separator="\n\n"> | |
619 | } | |
620 | >> | |
621 | ||
622 | StarBlock(choice, alts, sync, iteration) ::= << | |
623 | $this->setState(<choice.stateNumber>); | |
624 | $this->errorHandler->sync($this); | |
625 | ||
626 | $alt = $this->getInterpreter()->adaptivePredict($this->input, <choice.decision>, $this->ctx); | |
627 | ||
628 | while ($alt !== <choice.exitAlt> && $alt !== ATN::INVALID_ALT_NUMBER) { | |
629 | if ($alt === 1<if(!choice.ast.greedy)>+1<endif>) { | |
630 | <iteration> | |
631 | <alts> <! should only be one !> | |
632 | } | |
633 | ||
634 | $this->setState(<choice.loopBackStateNumber>); | |
635 | $this->errorHandler->sync($this); | |
636 | ||
637 | $alt = $this->getInterpreter()->adaptivePredict($this->input, <choice.decision>, $this->ctx); | |
638 | } | |
639 | >> | |
640 | ||
641 | PlusBlock(choice, alts, error) ::= << | |
642 | $this->setState(<choice.blockStartStateNumber>); <! alt block decision !> | |
643 | $this->errorHandler->sync($this); | |
644 | ||
645 | $alt = 1<if(!choice.ast.greedy)>+1<endif>; | |
646 | ||
647 | do { | |
648 | switch ($alt) { | |
649 | <alts:{alt| | |
650 | case <i><if(!choice.ast.greedy)>+1<endif>: | |
651 | <alt> | |
652 | break;}; separator="\n\n"> | |
653 | default: | |
654 | <error> | |
655 | } | |
656 | ||
657 | $this->setState(<choice.loopBackStateNumber>); <! loopback/exit decision !> | |
658 | $this->errorHandler->sync($this); | |
659 | ||
660 | $alt = $this->getInterpreter()->adaptivePredict($this->input, <choice.decision>, $this->ctx); | |
661 | } while ($alt !== <choice.exitAlt> && $alt !== ATN::INVALID_ALT_NUMBER); | |
662 | >> | |
663 | ||
664 | Sync(s) ::= "sync(<s.expecting.name>);" | |
665 | ||
666 | ThrowNoViableAlt(t) ::= "throw new NoViableAltException($this);" | |
667 | ||
668 | TestSetInline(s) ::= << | |
669 | <s.bitsets:{bits | <if(rest(rest(bits.ttypes)))><bitsetBitfieldComparison(s, bits)><else><bitsetInlineComparison(s, bits)><endif>}; separator=" || "> | |
670 | >> | |
671 | ||
672 | // Java language spec 15.19 - shift operators mask operands rather than overflow to 0... need range test | |
673 | testShiftInRange(shiftAmount) ::= << | |
674 | ((<shiftAmount>) & ~0x3f) === 0 | |
675 | >> | |
676 | ||
677 | // produces smaller bytecode only when bits.ttypes contains more than two items | |
678 | bitsetBitfieldComparison(s, bits) ::= <% | |
679 | (<testShiftInRange({<offsetShiftVar(s.varName, bits.shift)>})> && ((1 \<\< <offsetShiftVar(s.varName, bits.shift)>) & (<bits.ttypes:{ttype | (1 \<\< <offsetShiftConst(ttype, bits.shift)>)}; separator=" | ">)) !== 0) | |
680 | %> | |
681 | ||
682 | isZero ::= [ | |
683 | "0":true, | |
684 | default:false | |
685 | ] | |
686 | ||
687 | offsetShiftVar(shiftAmount, offset) ::= <% | |
688 | <if(!isZero.(offset))>($<shiftAmount> - <offset>)<else>$<shiftAmount><endif> | |
689 | %> | |
690 | offsetShiftConst(shiftAmount, offset) ::= <% | |
691 | <if(!isZero.(offset))>(self::<shiftAmount> - <offset>)<else>self::<shiftAmount><endif> | |
692 | %> | |
693 | ||
694 | // produces more efficient bytecode when bits.ttypes contains at most two items | |
695 | bitsetInlineComparison(s, bits) ::= <% | |
696 | <bits.ttypes:{ttype | $<s.varName> === self::<ttype>}; separator=" || "> | |
697 | %> | |
698 | ||
699 | cases(ttypes) ::= << | |
700 | <ttypes:{t | case self::<t>:}; separator="\n"> | |
701 | >> | |
702 | ||
703 | InvokeRule(r, argExprsChunks) ::= << | |
704 | $this->setState(<r.stateNumber>); | |
705 | <if(r.labels)><r.labels:{l | <labelref(l)> = }><endif>$this-><if(r.ast.options.p)>recursive<r.name; format="cap"><else><r.name><endif>(<if(r.ast.options.p)><r.ast.options.p><if(argExprsChunks)>,<endif><endif><argExprsChunks>); | |
706 | >> | |
707 | ||
708 | MatchToken(m) ::= << | |
709 | $this->setState(<m.stateNumber>); | |
710 | <if(m.labels)><m.labels:{l | <labelref(l)> = }><endif>$this->match(self::<m.name>); | |
711 | >> | |
712 | ||
713 | MatchSet(m, expr, capture) ::= "<CommonSetStuff(m, expr, capture, false)>" | |
714 | ||
715 | MatchNotSet(m, expr, capture) ::= "<CommonSetStuff(m, expr, capture, true)>" | |
716 | ||
717 | CommonSetStuff(m, expr, capture, invert) ::= << | |
718 | $this->setState(<m.stateNumber>); | |
719 | ||
720 | <if(m.labels)><m.labels:{l | <labelref(l)> = }>$this->input->LT(1);<endif> | |
721 | <capture> | |
722 | ||
723 | if (<if(invert)>$<m.varName> \<= 0 || <else>!<endif>(<expr>)) { | |
724 | <if(m.labels)><m.labels:{l | <labelref(l)> = }><endif>$this->errorHandler->recoverInline($this); | |
725 | } else { | |
726 | if ($this->input->LA(1) === Token::EOF) { | |
727 | $this->matchedEOF = true; | |
728 | } | |
729 | ||
730 | $this->errorHandler->reportMatch($this); | |
731 | $this->consume(); | |
732 | } | |
733 | >> | |
734 | ||
735 | Wildcard(w) ::= << | |
736 | $this->setState(<w.stateNumber>); | |
737 | <if(w.labels)><w.labels:{l | <labelref(l)> = }><endif>$this->matchWildcard(); | |
738 | >> | |
739 | ||
740 | // ACTION STUFF | |
741 | ||
742 | Action(a, foo, chunks) ::= "<chunks>" | |
743 | ||
744 | ArgAction(a, chunks) ::= "<chunks>" | |
745 | ||
746 | SemPred(p, chunks, failChunks) ::= << | |
747 | $this->setState(<p.stateNumber>); | |
748 | ||
749 | if (!(<chunks>)) { | |
750 | throw new FailedPredicateException($this, <p.predicate><if(failChunks)>, <failChunks><elseif(p.msg)>, <p.msg><endif>); | |
751 | } | |
752 | >> | |
753 | ||
754 | ExceptionClause(e, catchArg, catchAction) ::= << | |
755 | catch (<catchArg>) { | |
756 | <catchAction> | |
757 | } | |
758 | >> | |
759 | ||
760 | // lexer actions are not associated with model objects | |
761 | ||
762 | LexerSkipCommand() ::= "$this->skip();" | |
763 | LexerMoreCommand() ::= "$this->more();" | |
764 | LexerPopModeCommand() ::= "$this->popMode();" | |
765 | ||
766 | LexerTypeCommand(arg, grammar) ::= "$this->type = <arg>;" | |
767 | LexerChannelCommand(arg, grammar) ::= "$this->channel = <arg>;" | |
768 | LexerModeCommand(arg, grammar) ::= "$this->mode = <arg>;" | |
769 | LexerPushModeCommand(arg, grammar) ::= "$this->pushMode(<arg>);" | |
770 | ||
771 | ActionText(t) ::= "<t.text>" | |
772 | ActionTemplate(t) ::= "<t.st>" | |
773 | ArgRef(a) ::= "$localContext-><a.name>" | |
774 | LocalRef(a) ::= "$localContext-><a.name>" | |
775 | RetValueRef(a) ::= "$localContext-><a.name>" | |
776 | QRetValueRef(a) ::= "<ctx(a)>-><a.dict>-><a.name>" | |
777 | /** How to translate $tokenLabel */ | |
778 | TokenRef(t) ::= "<ctx(t)>-><t.name>" | |
779 | LabelRef(t) ::= "<ctx(t)>-><t.name>" | |
780 | ListLabelRef(t) ::= "<ctx(t)>-><ListLabelName(t.name)>" | |
781 | SetAttr(s,rhsChunks) ::= "<ctx(s)>-><s.name> = <rhsChunks>;" | |
782 | ||
783 | TokenLabelType() ::= "<file.TokenLabelType; null={Token}>" | |
784 | InputSymbolType() ::= "<file.InputSymbolType; null={Token}>" | |
785 | ||
786 | TokenPropertyRef_text(t) ::= "(<ctx(t)>-><t.label> !== null ? <ctx(t)>-><t.label>->getText() : null)" | |
787 | TokenPropertyRef_type(t) ::= "(<ctx(t)>-><t.label> !== null ? <ctx(t)>-><t.label>->getType() : 0)" | |
788 | TokenPropertyRef_line(t) ::= "(<ctx(t)>-><t.label> !== null ? <ctx(t)>-><t.label>->getLine() : 0)" | |
789 | TokenPropertyRef_pos(t) ::= "(<ctx(t)>-><t.label> !== null ? <ctx(t)>-><t.label>->getCharPositionInLine() : 0)" | |
790 | TokenPropertyRef_channel(t) ::= "(<ctx(t)>-><t.label> !== null ? <ctx(t)>-><t.label>->getChannel() : 0)" | |
791 | TokenPropertyRef_index(t) ::= "(<ctx(t)>-><t.label> !== null ? <ctx(t)>-><t.label>->getTokenIndex() : 0)" | |
792 | TokenPropertyRef_int(t) ::= "(<ctx(t)>-><t.label> !== null ? (int) <ctx(t)>-><t.label>->getText() : 0)" | |
793 | ||
794 | RulePropertyRef_start(r) ::= "(<ctx(r)>-><r.label> !== null ? (<ctx(r)>-><r.label>->start) : null)" | |
795 | RulePropertyRef_stop(r) ::= "(<ctx(r)>-><r.label> !== null ? (<ctx(r)>-><r.label>->stop) : null)" | |
796 | RulePropertyRef_text(r) ::= "(<ctx(r)>-><r.label> !== null ? $this->input->getTextByTokens(<ctx(r)>-><r.label>->start, <ctx(r)>-><r.label>->stop) : null)" | |
797 | RulePropertyRef_ctx(r) ::= "<ctx(r)>-><r.label>" | |
798 | RulePropertyRef_parser(r)::= "\$this" | |
799 | ||
800 | ThisRulePropertyRef_start(r) ::= "$localContext->start" | |
801 | ThisRulePropertyRef_stop(r) ::= "$localContext->stop" | |
802 | ThisRulePropertyRef_text(r) ::= "$this->input->getTextByTokens($localContext->start, $this->input->LT(-1))" | |
803 | ThisRulePropertyRef_ctx(r) ::= "$localContext" | |
804 | ThisRulePropertyRef_parser(r)::= "$this" | |
805 | ||
806 | NonLocalAttrRef(s) ::= "\$this->getInvokingContext(<s.ruleIndex>)-><s.name>" | |
807 | SetNonLocalAttr(s, rhsChunks) ::= "\$this->getInvokingContext(<s.ruleIndex>)-><s.name> = <rhsChunks>;" | |
808 | ||
809 | AddToLabelList(a) ::= "<ctx(a.label)>-><a.listName>[] = <labelref(a.label)>;" | |
810 | ||
811 | TokenDecl(t) ::= "<TokenLabelType()> $<t.name>" | |
812 | TokenTypeDecl(t) ::= "" | |
813 | TokenListDecl(t) ::= "array $<t.name> = []" | |
814 | RuleContextDecl(r) ::= "<r.ctxName> $<r.name>" | |
815 | RuleContextListDecl(rdecl) ::= "array $<rdecl.name> = []" | |
816 | AttributeDecl(d) ::= "<d.type> $<d.name><if(d.initValue)> = <d.initValue><endif>" | |
817 | ||
818 | PropertiesDecl(struct) ::= << | |
819 | <if(struct.tokenListDecls)> | |
820 | <struct.tokenListDecls : {d | /** | |
821 | * @var array\<Token>|null $<d.name> | |
822 | */ | |
823 | public $<d.name>;}; separator="\n\n"> | |
824 | <endif> | |
825 | <if(struct.tokenDecls)> | |
826 | <if(struct.tokenListDecls)> | |
827 | ||
828 | <endif> | |
829 | <struct.tokenDecls : {d | /** | |
830 | * @var <TokenLabelType()>|null $<d.name> | |
831 | */ | |
832 | public $<d.name>;}; separator="\n\n"> | |
833 | <endif> | |
834 | <if(struct.ruleContextDecls)> | |
835 | <if(struct.tokenListDecls || struct.tokenDecls)> | |
836 | ||
837 | <endif> | |
838 | <struct.ruleContextDecls : {d | /** | |
839 | * @var <d.ctxName>|null $<d.name> | |
840 | */ | |
841 | public $<d.name>;}; separator="\n\n"> | |
842 | <endif> | |
843 | <if(struct.ruleContextListDecls)> | |
844 | <if(struct.tokenListDecls || struct.tokenDecls || struct.ruleContextDecls)> | |
845 | ||
846 | <endif> | |
847 | <struct.ruleContextListDecls : {d | /** | |
848 | * @var array\<<d.ctxName>\>|null $<d.name> | |
849 | */ | |
850 | public $<d.name>;}; separator="\n\n"> | |
851 | <endif> | |
852 | <if(struct.attributeDecls)> | |
853 | <if(struct.tokenListDecls || struct.tokenDecls || struct.ruleContextDecls || struct.ruleContextListDecls)> | |
854 | ||
855 | <endif> | |
856 | <struct.attributeDecls : {d | /** | |
857 | * @var <d.type><if(!d.initValue)>|null<endif> $<d.name> | |
858 | */ | |
859 | public $<d.name><if(d.initValue)> = <d.initValue><endif>;}; separator="\n\n"> | |
860 | <endif> | |
861 | ||
862 | >> | |
863 | ||
864 | ContextTokenGetterDecl(t) ::= << | |
865 | public function <t.name>() : ?TerminalNode | |
866 | { | |
867 | return $this->getToken(<parser.name>::<t.name>, 0); | |
868 | } | |
869 | >> | |
870 | ||
871 | ContextTokenListGetterDecl(t) ::= << | |
872 | >> | |
873 | ||
874 | ContextTokenListIndexedGetterDecl(t) ::= << | |
875 | /** | |
876 | * @return array\<TerminalNode>|TerminalNode|null | |
877 | */ | |
878 | public function <t.name>(?int $index = null) | |
879 | { | |
880 | if ($index === null) { | |
881 | return $this->getTokens(<parser.name>::<t.name>); | |
882 | } | |
883 | ||
884 | return $this->getToken(<parser.name>::<t.name>, $index); | |
885 | } | |
886 | >> | |
887 | ||
888 | ContextRuleGetterDecl(r) ::= << | |
889 | public function <r.name>() : ?<r.ctxName> | |
890 | { | |
891 | return $this->getTypedRuleContext(<r.ctxName>::class, 0); | |
892 | } | |
893 | >> | |
894 | ||
895 | ContextRuleListGetterDecl(r) ::= << | |
896 | >> | |
897 | ||
898 | ContextRuleListIndexedGetterDecl(r) ::= << | |
899 | /** | |
900 | * @return array\<<r.ctxName>\>|<r.ctxName>|null | |
901 | */ | |
902 | public function <r.name>(?int $index = null) | |
903 | { | |
904 | if ($index === null) { | |
905 | return $this->getTypedRuleContexts(<r.ctxName>::class); | |
906 | } | |
907 | ||
908 | return $this->getTypedRuleContext(<r.ctxName>::class, $index); | |
909 | } | |
910 | >> | |
911 | ||
912 | LexerRuleContext() ::= "RuleContext" | |
913 | ||
914 | /** | |
915 | * The rule context name is the rule followed by a suffix; e.g., r becomes rContext. | |
916 | */ | |
917 | RuleContextNameSuffix() ::= "Context" | |
918 | ||
919 | ImplicitTokenLabel(tokenName) ::= "<tokenName>" | |
920 | ImplicitRuleLabel(ruleName) ::= "<ruleName>" | |
921 | ImplicitSetLabel(id) ::= "_tset<id>" | |
922 | ListLabelName(label) ::= "<label>" | |
923 | ||
924 | CaptureNextToken(d) ::= "$<d.varName> = \$this->input->LT(1);" | |
925 | CaptureNextTokenType(d) ::= "$<d.varName> = $this->input->LA(1);" | |
926 | ||
927 | StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers) ::= << | |
928 | class <struct.name> extends <if(contextSuperClass)><contextSuperClass><else>ParserRuleContext<endif><if(interfaces)> implements <interfaces; separator=", "><endif> | |
929 | { | |
930 | <PropertiesDecl(struct)> | |
931 | public function __construct(?ParserRuleContext $parent, ?int $invokingState = null<ctorAttrs:{a | , ?<a> = null}>) | |
932 | { | |
933 | parent::__construct($parent, $invokingState); | |
934 | <if(struct.ctorAttrs)> | |
935 | ||
936 | <struct.ctorAttrs:{a | $this-><a.name> = $<a.name> ?? $this-><a.name>;}; separator="\n"> | |
937 | <endif> | |
938 | } | |
939 | ||
940 | public function getRuleIndex() : int | |
941 | { | |
942 | return <parser.name>::RULE_<struct.derivedFromName>; | |
943 | } | |
944 | <if(getters)> | |
945 | ||
946 | <getters:{g | <g>}; separator="\n\n"> | |
947 | <endif> | |
948 | <if(struct.provideCopyFrom)> <! don't need copy unless we have subclasses !> | |
949 | public function copyFrom(ParserRuleContext $context) : void | |
950 | { | |
951 | parent::copyFrom($context); | |
952 | ||
953 | <struct.attrs:{a | $this-><a.name> = $context-><a.name>;}; separator="\n"> | |
954 | } | |
955 | <endif> | |
956 | <if(dispatchMethods)> | |
957 | ||
958 | <dispatchMethods; separator="\n\n"> | |
959 | <endif> | |
960 | <if(extensionMembers)> | |
961 | ||
962 | <extensionMembers; separator="\n\n"> | |
963 | <endif> | |
964 | } | |
965 | >> | |
966 | ||
967 | AltLabelStructDecl(struct,attrs,getters,dispatchMethods) ::= << | |
968 | class <struct.name> extends <struct.parentRule; format="cap">Context | |
969 | { | |
970 | <PropertiesDecl(struct)> | |
971 | public function __construct(<struct.parentRule; format="cap">Context $context) | |
972 | { | |
973 | parent::__construct($context); | |
974 | ||
975 | $this->copyFrom($context); | |
976 | } | |
977 | <if(getters)> | |
978 | ||
979 | <getters:{g | <g>}; separator="\n\n"> | |
980 | <endif> | |
981 | <if(dispatchMethods)> | |
982 | ||
983 | <dispatchMethods; separator="\n\n"> | |
984 | <endif> | |
985 | } | |
986 | >> | |
987 | ||
988 | ListenerDispatchMethod(method) ::= << | |
989 | public function <if(method.isEnter)>enter<else>exit<endif>Rule(ParseTreeListener $listener) : void | |
990 | { | |
991 | if ($listener instanceof <parser.grammarName>Listener) { | |
992 | $listener-><if(method.isEnter)>enter<else>exit<endif><struct.derivedFromName; format="cap">($this); | |
993 | } | |
994 | } | |
995 | >> | |
996 | ||
997 | VisitorDispatchMethod(method) ::= << | |
998 | public function accept(ParseTreeVisitor $visitor) | |
999 | { | |
1000 | if ($visitor instanceof <parser.grammarName>Visitor) { | |
1001 | return $visitor->visit<struct.derivedFromName; format="cap">($this); | |
1002 | } | |
1003 | ||
1004 | return $visitor->visitChildren($this); | |
1005 | } | |
1006 | >> | |
1007 | ||
1008 | /** If we don't know location of label def x, use this template */ | |
1009 | labelref(x) ::= "<if(!x.isLocal)>$localContext-><endif><x.name>" | |
1010 | ||
1011 | /** For any action chunk, what is correctly-typed context struct ptr? */ | |
1012 | ctx(actionChunk) ::= "$localContext" | |
1013 | ||
1014 | // used for left-recursive rules | |
1015 | recRuleAltPredicate(ruleName,opPrec) ::= "\$this->precpred(\$this->ctx, <opPrec>)" | |
1016 | ||
1017 | recRuleSetReturnAction(src,name) ::= "\$<name> = \$<src>-><name>;" | |
1018 | ||
1019 | recRuleSetStopToken() ::= "$this->ctx->stop = $this->input->LT(-1);" | |
1020 | ||
1021 | recRuleAltStartAction(ruleName, ctxName, label, isListLabel) ::= << | |
1022 | $localContext = new Context\\<ctxName>Context($parentContext, $parentState); | |
1023 | <if(label)> | |
1024 | <if(isListLabel)> | |
1025 | $localContext-><label>[] = $previousContext; | |
1026 | <else> | |
1027 | $localContext-><label> = $previousContext; | |
1028 | <endif> | |
1029 | <endif> | |
1030 | ||
1031 | $this->pushNewRecursionContext($localContext, $startState, self::RULE_<ruleName>); | |
1032 | >> | |
1033 | ||
1034 | recRuleLabeledAltStartAction(ruleName, currentAltLabel, label, isListLabel) ::= << | |
1035 | $localContext = new Context\\<currentAltLabel; format="cap">Context(new Context\\<ruleName; format="cap">Context($parentContext, $parentState)); | |
1036 | <if(label)> | |
1037 | <if(isListLabel)> | |
1038 | $localContext-><label>[] = $previousContext; | |
1039 | <else> | |
1040 | $localContext-><label> = $previousContext; | |
1041 | <endif> | |
1042 | <endif> | |
1043 | ||
1044 | $this->pushNewRecursionContext($localContext, $startState, self::RULE_<ruleName>); | |
1045 | >> | |
1046 | ||
1047 | recRuleReplaceContext(ctxName) ::= << | |
1048 | $localContext = new Context\\<ctxName>Context($localContext); | |
1049 | $this->ctx = $localContext; | |
1050 | $previousContext = $localContext; | |
1051 | >> | |
1052 | ||
1053 | recRuleSetPrevCtx() ::= << | |
1054 | if ($this->getParseListeners() !== null) { | |
1055 | $this->triggerExitRuleEvent(); | |
1056 | } | |
1057 | ||
1058 | $previousContext = $localContext; | |
1059 | >> | |
1060 | ||
1061 | ||
1062 | LexerFile(lexerFile, lexer, namedActions) ::= << | |
1063 | <fileHeader(lexerFile.grammarFileName, lexerFile.ANTLRVersion)> | |
1064 | <lexer> | |
1065 | >> | |
1066 | ||
1067 | Lexer(lexer, atn, actionFuncs, sempredFuncs, superClass) ::= << | |
1068 | namespace<if(lexerFile.genPackage)> <lexerFile.genPackage><endif> { | |
1069 | <if(namedActions.header)><namedActions.header><endif> | |
1070 | use Antlr\\Antlr4\\Runtime\\Atn\\ATNDeserializer; | |
1071 | use Antlr\\Antlr4\\Runtime\\Atn\\LexerATNSimulator; | |
1072 | use Antlr\\Antlr4\\Runtime\\Lexer; | |
1073 | use Antlr\\Antlr4\\Runtime\\CharStream; | |
1074 | use Antlr\\Antlr4\\Runtime\\PredictionContexts\\PredictionContextCache; | |
1075 | use Antlr\\Antlr4\\Runtime\\RuleContext; | |
1076 | use Antlr\\Antlr4\\Runtime\\Atn\\ATN; | |
1077 | use Antlr\\Antlr4\\Runtime\\Dfa\\DFA; | |
1078 | use Antlr\\Antlr4\\Runtime\\Vocabulary; | |
1079 | use Antlr\\Antlr4\\Runtime\\RuntimeMetaData; | |
1080 | use Antlr\\Antlr4\\Runtime\\VocabularyImpl; | |
1081 | <if(namedActions.definitions)><namedActions.definitions><endif> | |
1082 | ||
1083 | final class <lexer.name> extends <superClass; null="Lexer"> | |
1084 | { | |
1085 | <if(lexer.tokens)> | |
1086 | public const <lexer.tokens:{k | <k> = <lexer.tokens.(k)>}; separator=", ", wrap, anchor>; | |
1087 | <endif> | |
1088 | ||
1089 | <if(lexer.channels)> | |
1090 | public const <lexer.channels:{c | <c> = <lexer.channels.(c)>}; separator=", ", wrap, anchor>; | |
1091 | <endif> | |
1092 | ||
1093 | <if(rest(lexer.modes))> | |
1094 | public const <rest(lexer.modes):{m | <m>=<i>}; separator=", ", wrap, anchor>; | |
1095 | <endif> | |
1096 | ||
1097 | /** | |
1098 | * @var array\<string> | |
1099 | */ | |
1100 | public const CHANNEL_NAMES = [ | |
1101 | 'DEFAULT_TOKEN_CHANNEL', 'HIDDEN'<if (lexer.channels)>, <lexer.channels:{c| '<c>'}; separator=", ", wrap, anchor><endif> | |
1102 | ]; | |
1103 | ||
1104 | /** | |
1105 | * @var array\<string> | |
1106 | */ | |
1107 | public const MODE_NAMES = [ | |
1108 | <lexer.modes:{m| '<m>'}; separator=", ", wrap, anchor> | |
1109 | ]; | |
1110 | ||
1111 | /** | |
1112 | * @var array\<string> | |
1113 | */ | |
1114 | public const RULE_NAMES = [ | |
1115 | <lexer.ruleNames:{r | '<r>'}; separator=", ", wrap, anchor> | |
1116 | ]; | |
1117 | ||
1118 | <vocabulary(lexer.literalNames, lexer.symbolicNames)> | |
1119 | ||
1120 | <atn> | |
1121 | protected static $atn; | |
1122 | protected static $decisionToDFA; | |
1123 | protected static $sharedContextCache; | |
1124 | <if(namedActions.members)> | |
1125 | ||
1126 | <namedActions.members> | |
1127 | <endif> | |
1128 | ||
1129 | public function __construct(CharStream $input) | |
1130 | { | |
1131 | parent::__construct($input); | |
1132 | ||
1133 | self::initialize(); | |
1134 | ||
1135 | $this->interp = new LexerATNSimulator($this, self::$atn, self::$decisionToDFA, self::$sharedContextCache); | |
1136 | } | |
1137 | ||
1138 | private static function initialize() : void | |
1139 | { | |
1140 | if (self::$atn !== null) { | |
1141 | return; | |
1142 | } | |
1143 | ||
1144 | RuntimeMetaData::checkVersion('<lexerFile.ANTLRVersion>', RuntimeMetaData::VERSION); | |
1145 | ||
1146 | $atn = (new ATNDeserializer())->deserialize(self::SERIALIZED_ATN); | |
1147 | ||
1148 | $decisionToDFA = []; | |
1149 | for ($i = 0, $count = $atn->getNumberOfDecisions(); $i \< $count; $i++) { | |
1150 | $decisionToDFA[] = new DFA($atn->getDecisionState($i), $i); | |
1151 | } | |
1152 | ||
1153 | self::$atn = $atn; | |
1154 | self::$decisionToDFA = $decisionToDFA; | |
1155 | self::$sharedContextCache = new PredictionContextCache(); | |
1156 | } | |
1157 | ||
1158 | public static function vocabulary() : Vocabulary | |
1159 | { | |
1160 | static $vocabulary; | |
1161 | ||
1162 | return $vocabulary = $vocabulary ?? new VocabularyImpl(self::LITERAL_NAMES, self::SYMBOLIC_NAMES); | |
1163 | } | |
1164 | ||
1165 | public function getGrammarFileName() : string | |
1166 | { | |
1167 | return '<lexer.grammarFileName>'; | |
1168 | } | |
1169 | ||
1170 | public function getRuleNames() : array | |
1171 | { | |
1172 | return self::RULE_NAMES; | |
1173 | } | |
1174 | ||
1175 | public function getSerializedATN() : string | |
1176 | { | |
1177 | return self::SERIALIZED_ATN; | |
1178 | } | |
1179 | ||
1180 | /** | |
1181 | * @return array\<string> | |
1182 | */ | |
1183 | public function getChannelNames() : array | |
1184 | { | |
1185 | return self::CHANNEL_NAMES; | |
1186 | } | |
1187 | ||
1188 | /** | |
1189 | * @return array\<string> | |
1190 | */ | |
1191 | public function getModeNames() : array | |
1192 | { | |
1193 | return self::MODE_NAMES; | |
1194 | } | |
1195 | ||
1196 | public function getATN() : ATN | |
1197 | { | |
1198 | return self::$atn; | |
1199 | } | |
1200 | ||
1201 | public function getVocabulary() : Vocabulary | |
1202 | { | |
1203 | return self::vocabulary(); | |
1204 | } | |
1205 | <dumpActions(lexer, "", actionFuncs, sempredFuncs)> | |
1206 | } | |
1207 | } | |
1208 | >> | |
1209 | ||
1210 | SerializedATN(model) ::= << | |
1211 | <if(rest(model.segments))> | |
1212 | /** | |
1213 | * @var string | |
1214 | */ | |
1215 | private const SERIALIZED_ATN = | |
1216 | <model.segments:{segment| "<segment; wrap={" .<\n>"}>"}; separator=" .\n">; | |
1217 | <else> | |
1218 | /** | |
1219 | * @var string | |
1220 | */ | |
1221 | private const SERIALIZED_ATN = | |
1222 | "<model.serialized; wrap={" .<\n> "}>"; | |
1223 | <endif> | |
1224 | >> | |
1225 | ||
1226 | /** | |
1227 | * Using a type to init value map, try to init a type; if not in table | |
1228 | * must be an object, default value is `null`. | |
1229 | */ | |
1230 | initValue(typeName) ::= << | |
1231 | <phpTypeInitMap.(typeName)> | |
1232 | >> | |
1233 | ||
1234 | codeFileExtension() ::= ".php" |
109 | 109 | |
110 | 110 | Parser_(parser, funcs, atn, sempredFuncs, ctor, superClass) ::= << |
111 | 111 | <if(superClass)> |
112 | from .<superClass> import <superClass> | |
112 | if __name__ is not None and "." in __name__: | |
113 | from .<superClass> import <superClass> | |
114 | else: | |
115 | from <superClass> import <superClass> | |
113 | 116 | |
114 | 117 | <endif> |
115 | 118 | <atn> |
128 | 131 | |
129 | 132 | symbolicNames = [ <parser.symbolicNames:{t | u<t>}; null="u\"\<INVALID>\"", separator=", ", wrap, anchor> ] |
130 | 133 | |
134 | <if(parser.rules)> | |
131 | 135 | <parser.rules:{r | RULE_<r.name> = <r.index>}; separator="\n", wrap, anchor> |
136 | <endif> | |
132 | 137 | |
133 | 138 | ruleNames = [ <parser.ruleNames:{r | u"<r>"}; separator=", ", wrap, anchor> ] |
134 | 139 | |
516 | 521 | >> |
517 | 522 | |
518 | 523 | ExceptionClause(e, catchArg, catchAction) ::= << |
519 | catch (<catchArg>) { | |
524 | except <catchArg>: | |
520 | 525 | <catchAction> |
521 | } | |
522 | 526 | >> |
523 | 527 | |
524 | 528 | // lexer actions are not associated with model objects |
548 | 552 | InputSymbolType() ::= "<file.InputSymbolType; null={Token}>" |
549 | 553 | |
550 | 554 | TokenPropertyRef_text(t) ::= "(None if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.text)" |
551 | TokenPropertyRef_type(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.type()" | |
555 | TokenPropertyRef_type(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.type)" | |
552 | 556 | TokenPropertyRef_line(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.line)" |
553 | 557 | TokenPropertyRef_pos(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.column)" |
554 | TokenPropertyRef_channel(t) ::= "(0 if (<ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.channel)" | |
558 | TokenPropertyRef_channel(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.channel)" | |
555 | 559 | TokenPropertyRef_index(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.tokenIndex)" |
556 | 560 | TokenPropertyRef_int(t) ::= "(0 if <ctx(t)>.<t.label> is None else int(<ctx(t)>.<t.label>.text))" |
557 | 561 | |
558 | 562 | RulePropertyRef_start(r) ::= "(None if <ctx(r)>.<r.label> is None else <ctx(r)>.<r.label>.start)" |
559 | 563 | RulePropertyRef_stop(r) ::= "(None if <ctx(r)>.<r.label> is None else <ctx(r)>.<r.label>.stop)" |
560 | RulePropertyRef_text(r) ::= "(None if <ctx(r)>.<r.label> is None else self._input.getText((<ctx(r)>.<r.label>.start,<ctx(r)>.<r.label>.stop)))" | |
564 | RulePropertyRef_text(r) ::= "(None if <ctx(r)>.<r.label> is None else self._input.getText(<ctx(r)>.<r.label>.start,<ctx(r)>.<r.label>.stop))" | |
561 | 565 | RulePropertyRef_ctx(r) ::= "<ctx(r)>.<r.label>" |
562 | 566 | RulePropertyRef_parser(r) ::= "self" |
563 | 567 | |
564 | 568 | ThisRulePropertyRef_start(r) ::= "localctx.start" |
565 | 569 | ThisRulePropertyRef_stop(r) ::= "localctx.stop" |
566 | ThisRulePropertyRef_text(r) ::= "self._input.getText((localctx.start, self._input.LT(-1)))" | |
570 | ThisRulePropertyRef_text(r) ::= "self._input.getText(localctx.start, self._input.LT(-1))" | |
567 | 571 | ThisRulePropertyRef_ctx(r) ::= "localctx" |
568 | 572 | ThisRulePropertyRef_parser(r) ::= "self" |
569 | 573 | |
570 | NonLocalAttrRef(s) ::= "getInvokingContext(<s.ruleIndex>).<s.name>" | |
571 | SetNonLocalAttr(s, rhsChunks) ::= "getInvokingContext(<s.ruleIndex>).<s.name> = <rhsChunks>" | |
574 | NonLocalAttrRef(s) ::= "self.getInvokingContext(<s.ruleIndex>).<s.name>" | |
575 | SetNonLocalAttr(s, rhsChunks) ::= "self.getInvokingContext(<s.ruleIndex>).<s.name> = <rhsChunks>" | |
572 | 576 | |
573 | 577 | AddToLabelList(a) ::= "<ctx(a.label)>.<a.listName>.append(<labelref(a.label)>)" |
574 | 578 | |
749 | 753 | |
750 | 754 | Lexer(lexer, atn, actionFuncs, sempredFuncs, superClass) ::= << |
751 | 755 | <if(superClass)> |
752 | from .<superClass> import <superClass> | |
756 | if __name__ is not None and "." in __name__: | |
757 | from .<superClass> import <superClass> | |
758 | else: | |
759 | from <superClass> import <superClass> | |
753 | 760 | |
754 | 761 | <endif> |
755 | 762 | |
769 | 776 | <rest(lexer.modes):{m| <m> = <i>}; separator="\n"> |
770 | 777 | |
771 | 778 | <endif> |
779 | <if(lexer.tokens)> | |
772 | 780 | <lexer.tokens:{k | <k> = <lexer.tokens.(k)>}; separator="\n", wrap, anchor> |
781 | <endif> | |
773 | 782 | |
774 | 783 | channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN"<if (lexer.channels)>, <lexer.channels:{c| u"<c>"}; separator=", ", wrap, anchor><endif> ] |
775 | 784 |
50 | 50 | # encoding: utf-8 |
51 | 51 | from antlr4 import * |
52 | 52 | from io import StringIO |
53 | from typing.io import TextIO | |
54 | 53 | import sys |
54 | if sys.version_info[1] > 5: | |
55 | from typing import TextIO | |
56 | else: | |
57 | from typing.io import TextIO | |
55 | 58 | |
56 | 59 | <namedActions.header> |
57 | 60 | <parser> |
81 | 84 | |
82 | 85 | }; separator="\n"> |
83 | 86 | |
87 | del <file.parserName> | |
84 | 88 | >> |
85 | 89 | |
86 | 90 | |
140 | 144 | |
141 | 145 | symbolicNames = [ <parser.symbolicNames:{t | <t>}; null="\"\<INVALID>\"", separator=", ", wrap, anchor> ] |
142 | 146 | |
147 | <if(parser.rules)> | |
143 | 148 | <parser.rules:{r | RULE_<r.name> = <r.index>}; separator="\n", wrap, anchor> |
149 | <endif> | |
144 | 150 | |
145 | 151 | ruleNames = [ <parser.ruleNames:{r | "<r>"}; separator=", ", wrap, anchor> ] |
146 | 152 | |
528 | 534 | >> |
529 | 535 | |
530 | 536 | ExceptionClause(e, catchArg, catchAction) ::= << |
531 | catch (<catchArg>) { | |
537 | except <catchArg>: | |
532 | 538 | <catchAction> |
533 | } | |
534 | 539 | >> |
535 | 540 | |
536 | 541 | // lexer actions are not associated with model objects |
560 | 565 | InputSymbolType() ::= "<file.InputSymbolType; null={Token}>" |
561 | 566 | |
562 | 567 | TokenPropertyRef_text(t) ::= "(None if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.text)" |
563 | TokenPropertyRef_type(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.type()" | |
568 | TokenPropertyRef_type(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.type)" | |
564 | 569 | TokenPropertyRef_line(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.line)" |
565 | 570 | TokenPropertyRef_pos(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.column)" |
566 | TokenPropertyRef_channel(t) ::= "(0 if (<ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.channel)" | |
571 | TokenPropertyRef_channel(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.channel)" | |
567 | 572 | TokenPropertyRef_index(t) ::= "(0 if <ctx(t)>.<t.label> is None else <ctx(t)>.<t.label>.tokenIndex)" |
568 | 573 | TokenPropertyRef_int(t) ::= "(0 if <ctx(t)>.<t.label> is None else int(<ctx(t)>.<t.label>.text))" |
569 | 574 | |
570 | 575 | RulePropertyRef_start(r) ::= "(None if <ctx(r)>.<r.label> is None else <ctx(r)>.<r.label>.start)" |
571 | 576 | RulePropertyRef_stop(r) ::= "(None if <ctx(r)>.<r.label> is None else <ctx(r)>.<r.label>.stop)" |
572 | RulePropertyRef_text(r) ::= "(None if <ctx(r)>.<r.label> is None else self._input.getText((<ctx(r)>.<r.label>.start,<ctx(r)>.<r.label>.stop)))" | |
577 | RulePropertyRef_text(r) ::= "(None if <ctx(r)>.<r.label> is None else self._input.getText(<ctx(r)>.<r.label>.start,<ctx(r)>.<r.label>.stop))" | |
573 | 578 | RulePropertyRef_ctx(r) ::= "<ctx(r)>.<r.label>" |
574 | 579 | RulePropertyRef_parser(r) ::= "self" |
575 | 580 | |
576 | 581 | ThisRulePropertyRef_start(r) ::= "localctx.start" |
577 | 582 | ThisRulePropertyRef_stop(r) ::= "localctx.stop" |
578 | ThisRulePropertyRef_text(r) ::= "self._input.getText((localctx.start, self._input.LT(-1)))" | |
583 | ThisRulePropertyRef_text(r) ::= "self._input.getText(localctx.start, self._input.LT(-1))" | |
579 | 584 | ThisRulePropertyRef_ctx(r) ::= "localctx" |
580 | 585 | ThisRulePropertyRef_parser(r) ::= "self" |
581 | 586 | |
582 | NonLocalAttrRef(s) ::= "getInvokingContext(<s.ruleIndex>).<s.name>" | |
583 | SetNonLocalAttr(s, rhsChunks) ::= "getInvokingContext(<s.ruleIndex>).<s.name> = <rhsChunks>" | |
587 | NonLocalAttrRef(s) ::= "self.getInvokingContext(<s.ruleIndex>).<s.name>" | |
588 | SetNonLocalAttr(s, rhsChunks) ::= "self.getInvokingContext(<s.ruleIndex>).<s.name> = <rhsChunks>" | |
584 | 589 | |
585 | 590 | AddToLabelList(a) ::= "<ctx(a.label)>.<a.listName>.append(<labelref(a.label)>)" |
586 | 591 | |
648 | 653 | |
649 | 654 | StructDecl(struct,ctorAttrs,attrs,getters,dispatchMethods,interfaces,extensionMembers) ::= << |
650 | 655 | class <struct.name>(<if(contextSuperClass)><contextSuperClass><else>ParserRuleContext<endif>): |
656 | __slots__ = 'parser' | |
651 | 657 | |
652 | 658 | def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1<struct.ctorAttrs:{a | , <a.name><if(a.type)>:<a.type><endif>=None}>): |
653 | 659 | super().__init__(parent, invokingState) |
749 | 755 | <fileHeader(lexerFile.grammarFileName, lexerFile.ANTLRVersion)> |
750 | 756 | from antlr4 import * |
751 | 757 | from io import StringIO |
752 | from typing.io import TextIO | |
753 | 758 | import sys |
759 | if sys.version_info[1] > 5: | |
760 | from typing import TextIO | |
761 | else: | |
762 | from typing.io import TextIO | |
754 | 763 | |
755 | 764 | <namedActions.header> |
756 | 765 | |
781 | 790 | <rest(lexer.modes):{m| <m> = <i>}; separator="\n"> |
782 | 791 | |
783 | 792 | <endif> |
793 | <if(lexer.tokens)> | |
784 | 794 | <lexer.tokens:{k | <k> = <lexer.tokens.(k)>}; separator="\n", wrap, anchor> |
795 | <endif> | |
785 | 796 | |
786 | 797 | channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN"<if (lexer.channels)>, <lexer.channels:{c| u"<c>"}; separator=", ", wrap, anchor><endif> ] |
787 | 798 |
137 | 137 | * |
138 | 138 | * \<p>The default implementation does nothing.\</p> |
139 | 139 | */ |
140 | <accessLevelOpenOK(file)> func enterEveryRule(_ ctx: ParserRuleContext) { } | |
140 | <accessLevelOpenOK(file)> func enterEveryRule(_ ctx: ParserRuleContext) throws { } | |
141 | 141 | /** |
142 | 142 | * {@inheritDoc\} |
143 | 143 | * |
144 | 144 | * \<p>The default implementation does nothing.\</p> |
145 | 145 | */ |
146 | <accessLevelOpenOK(file)> func exitEveryRule(_ ctx: ParserRuleContext) { } | |
146 | <accessLevelOpenOK(file)> func exitEveryRule(_ ctx: ParserRuleContext) throws { } | |
147 | 147 | /** |
148 | 148 | * {@inheritDoc\} |
149 | 149 | * |
251 | 251 | enum Tokens: Int { |
252 | 252 | case EOF = -1, <parser.tokens:{k | <k> = <parser.tokens.(k)>}; separator=", ", wrap, anchor> |
253 | 253 | } |
254 | <endif> | |
254 | <endif> | |
255 | 255 | |
256 | 256 | <accessLevelNotOpen(parser)> |
257 | <if(parser.rules)> | |
257 | 258 | static let <parser.rules:{r | RULE_<r.name> = <r.index>}; separator=", ", wrap, anchor> |
259 | <endif> | |
258 | 260 | |
259 | 261 | <accessLevelNotOpen(parser)> |
260 | 262 | static let ruleNames: [String] = [ |
353 | 355 | |
354 | 356 | override <accessLevelNotOpen(parser)> |
355 | 357 | init(_ input:TokenStream) throws { |
356 | RuntimeMetaData.checkVersion("4.7.2", RuntimeMetaData.VERSION) | |
358 | RuntimeMetaData.checkVersion("4.9.2", RuntimeMetaData.VERSION) | |
357 | 359 | try super.init(input) |
358 | 360 | _interp = ParserATNSimulator(self,<p.name>._ATN,<p.name>._decisionToDFA, <parser.name>._sharedContextCache) |
359 | 361 | } |
437 | 439 | @discardableResult |
438 | 440 | private func <currentRule.name>(_ _p<args:{a | , <a>}>: Int) throws -> <currentRule.ctxType> { |
439 | 441 | let _parentctx: ParserRuleContext? = _ctx |
440 | var _parentState: Int = getState() | |
442 | let _parentState: Int = getState() | |
441 | 443 | var _localctx: <currentRule.ctxType> = <currentRule.ctxType>(_ctx, _parentState<currentRule.args:{a | , <a.name>}>) |
442 | var _prevctx: <currentRule.ctxType> = _localctx | |
443 | var _startState: Int = <currentRule.startState> | |
444 | var _prevctx: <currentRule.ctxType> = _localctx | |
445 | let _startState: Int = <currentRule.startState> | |
444 | 446 | try enterRecursionRule(_localctx, <currentRule.startState>, <parser.name>.RULE_<currentRule.name>, _p) |
445 | 447 | <namedActions.init> |
446 | 448 | <locals; separator="\n"> |
847 | 849 | func getRuleIndex() -> Int { |
848 | 850 | return <parser.name>.RULE_<struct.derivedFromName> |
849 | 851 | } |
850 | <if(struct.provideCopyFrom)> <! don't need copy unless we have subclasses !> | |
851 | <! <accessLevelNotOpen(parser)> init() { }!> | |
852 | <if(struct.provideCopyFrom && struct.attrs)> <! don't need copy unless we have subclasses !> | |
852 | 853 | <accessLevelOpenOK(parser)> |
853 | func copyFrom(_ ctx: <struct.name>) { | |
854 | super.copyFrom(ctx) | |
854 | override func copyFrom(_ ctx_: ParserRuleContext) { | |
855 | super.copyFrom(ctx_) | |
856 | let ctx = ctx_ as! <struct.name> | |
855 | 857 | <struct.attrs:{a | self.<a.name> = ctx.<a.name>;}; separator="\n"> |
856 | 858 | } |
857 | 859 | <endif> |
976 | 978 | internal static let _sharedContextCache = PredictionContextCache() |
977 | 979 | |
978 | 980 | <accessLevelNotOpen(lexer)> |
981 | <if(lexer.tokens)> | |
979 | 982 | static let <lexer.tokens:{k | <k>=<lexer.tokens.(k)>}; separator=", ", wrap, anchor> |
983 | <endif> | |
980 | 984 | |
981 | 985 | <if(lexer.channels)> |
982 | 986 | <accessLevelNotOpen(lexer)> |
281 | 281 | return sb.toString(); |
282 | 282 | } |
283 | 283 | |
284 | private static boolean shouldUseUnicodeEscapeForCodePointInDoubleQuotedString(int codePoint) { | |
284 | protected boolean shouldUseUnicodeEscapeForCodePointInDoubleQuotedString(int codePoint) { | |
285 | 285 | // We don't want anyone passing 0x0A (newline) or 0x22 |
286 | 286 | // (double-quote) here because Java treats \\u000A as |
287 | 287 | // a literal newline and \\u0022 as a literal |
16 | 16 | /** A StructDecl to handle a -> label on alt */ |
17 | 17 | public class AltLabelStructDecl extends StructDecl { |
18 | 18 | public int altNum; |
19 | public String parentRule; | |
19 | 20 | public AltLabelStructDecl(OutputModelFactory factory, Rule r, |
20 | 21 | int altNum, String label) |
21 | 22 | { |
23 | 24 | this.altNum = altNum; |
24 | 25 | this.name = // override name set in super to the label ctx |
25 | 26 | factory.getGenerator().getTarget().getAltLabelContextStructName(label); |
27 | this.parentRule = r.name; | |
26 | 28 | derivedFromName = label; |
27 | 29 | } |
28 | 30 |
27 | 27 | |
28 | 28 | @Override |
29 | 29 | public String getVersion() { |
30 | return "4.7.2"; | |
30 | return "4.9.2"; | |
31 | 31 | } |
32 | 32 | |
33 | 33 | @Override |
46 | 46 | |
47 | 47 | public CppTarget(CodeGenerator gen) { |
48 | 48 | super(gen, "Cpp"); |
49 | targetCharValueEscape['?'] = "\\?"; | |
49 | 50 | } |
50 | 51 | |
51 | 52 | public String getVersion() { |
52 | return "4.7.2"; | |
53 | return "4.9.2"; | |
53 | 54 | } |
54 | 55 | |
55 | 56 | public boolean needsHeader() { return true; } |
66 | 67 | badWords.addAll(Arrays.asList(cppKeywords)); |
67 | 68 | badWords.add("rule"); |
68 | 69 | badWords.add("parserRule"); |
70 | } | |
71 | ||
72 | @Override | |
73 | protected boolean shouldUseUnicodeEscapeForCodePointInDoubleQuotedString(int codePoint) { | |
74 | if (codePoint == '?') { | |
75 | // in addition to the default escaped code points, also escape ? to prevent trigraphs | |
76 | // ideally, we would escape ? with \?, but escaping as unicode \u003F works as well | |
77 | return true; | |
78 | } | |
79 | else { | |
80 | return super.shouldUseUnicodeEscapeForCodePointInDoubleQuotedString(codePoint); | |
81 | } | |
69 | 82 | } |
70 | 83 | |
71 | 84 | @Override |
0 | /* | |
1 | * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. | |
2 | * Use of this file is governed by the BSD 3-clause license that | |
3 | * can be found in the LICENSE.txt file in the project root. | |
4 | */ | |
5 | ||
6 | package org.antlr.v4.codegen.target; | |
7 | ||
8 | import org.antlr.v4.Tool; | |
9 | import org.antlr.v4.codegen.CodeGenerator; | |
10 | import org.antlr.v4.codegen.Target; | |
11 | import org.antlr.v4.codegen.UnicodeEscapes; | |
12 | import org.antlr.v4.tool.ast.GrammarAST; | |
13 | import org.stringtemplate.v4.STGroup; | |
14 | import org.stringtemplate.v4.StringRenderer; | |
15 | ||
16 | import java.util.Arrays; | |
17 | import java.util.HashSet; | |
18 | import java.util.Set; | |
19 | ||
20 | public class DartTarget extends Target { | |
21 | ||
22 | /** | |
23 | * The Java target can cache the code generation templates. | |
24 | */ | |
25 | private static final ThreadLocal<STGroup> targetTemplates = new ThreadLocal<STGroup>(); | |
26 | ||
27 | protected static final String[] javaKeywords = { | |
28 | "abstract", "dynamic", "implements", "show", | |
29 | "as", "else", "import", "static", | |
30 | "assert", "enum", "in", "super", | |
31 | "async", "export", "interface", "switch", | |
32 | "await", "extends", "is", "sync", | |
33 | "break", "external", "library", "this", | |
34 | "case", "factory", "mixin", "throw", | |
35 | "catch", "false", "new", "true", | |
36 | "class", "final", "null", "try", | |
37 | "const", "finally", "on", "typedef", | |
38 | "continue", "for", "operator", "var", | |
39 | "covariant", "Function", "part", "void", | |
40 | "default", "get", "rethrow", "while", | |
41 | "deferred", "hide", "return", "with", | |
42 | "do", "if", "set", "yield", | |
43 | }; | |
44 | ||
45 | /// Avoid grammar symbols in this set to prevent conflicts in gen'd code. | |
46 | protected final Set<String> badWords = new HashSet<String>(); | |
47 | ||
48 | public DartTarget(CodeGenerator gen) { | |
49 | super(gen, "Dart"); | |
50 | ||
51 | targetCharValueEscape['$'] = "\\$"; | |
52 | } | |
53 | ||
54 | @Override | |
55 | public String getTargetStringLiteralFromANTLRStringLiteral(CodeGenerator generator, String literal, boolean addQuotes) { | |
56 | return super.getTargetStringLiteralFromANTLRStringLiteral(generator, literal, addQuotes).replace("$", "\\$"); | |
57 | } | |
58 | ||
59 | @Override | |
60 | public String getVersion() { | |
61 | return Tool.VERSION; // Java and tool versions move in lock step | |
62 | } | |
63 | ||
64 | public Set<String> getBadWords() { | |
65 | if (badWords.isEmpty()) { | |
66 | addBadWords(); | |
67 | } | |
68 | ||
69 | return badWords; | |
70 | } | |
71 | ||
72 | protected void addBadWords() { | |
73 | badWords.addAll(Arrays.asList(javaKeywords)); | |
74 | badWords.add("rule"); | |
75 | badWords.add("parserRule"); | |
76 | } | |
77 | ||
78 | @Override | |
79 | public int getSerializedATNSegmentLimit() { | |
80 | // 65535 is the class file format byte limit for a UTF-8 encoded string literal | |
81 | // 3 is the maximum number of bytes it takes to encode a value in the range 0-0xFFFF | |
82 | return 65535 / 3; | |
83 | } | |
84 | ||
85 | @Override | |
86 | protected boolean visibleGrammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode) { | |
87 | return getBadWords().contains(idNode.getText()); | |
88 | } | |
89 | ||
90 | @Override | |
91 | protected STGroup loadTemplates() { | |
92 | STGroup result = super.loadTemplates(); | |
93 | result.registerRenderer(String.class, new StringRenderer(), true); | |
94 | ||
95 | return result; | |
96 | } | |
97 | ||
98 | @Override | |
99 | public String encodeIntAsCharEscape(int v) { | |
100 | if (v < Character.MIN_VALUE || v > Character.MAX_VALUE) { | |
101 | throw new IllegalArgumentException(String.format("Cannot encode the specified value: %d", v)); | |
102 | } | |
103 | ||
104 | return String.format("\\u{%X}", v & 0xFFFF); | |
105 | } | |
106 | ||
107 | @Override | |
108 | protected void appendUnicodeEscapedCodePoint(int codePoint, StringBuilder sb) { | |
109 | UnicodeEscapes.appendJavaStyleEscapedCodePoint(codePoint, sb); | |
110 | } | |
111 | } |
70 | 70 | |
71 | 71 | @Override |
72 | 72 | public String getVersion() { |
73 | return "4.7.2"; | |
73 | return "4.9.2"; | |
74 | 74 | } |
75 | 75 | |
76 | 76 | public Set<String> getBadWords() { |
50 | 50 | |
51 | 51 | @Override |
52 | 52 | public String getVersion() { |
53 | return "4.7.2"; | |
53 | return "4.9.2"; | |
54 | 54 | } |
55 | 55 | |
56 | 56 | public Set<String> getBadWords() { |
0 | /* | |
1 | * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. | |
2 | * Use of this file is governed by the BSD 3-clause license that | |
3 | * can be found in the LICENSE.txt file in the project root. | |
4 | */ | |
5 | ||
6 | package org.antlr.v4.codegen.target; | |
7 | ||
8 | import org.antlr.v4.codegen.CodeGenerator; | |
9 | import org.antlr.v4.codegen.Target; | |
10 | import org.antlr.v4.codegen.UnicodeEscapes; | |
11 | import org.antlr.v4.tool.ast.GrammarAST; | |
12 | import org.stringtemplate.v4.STGroup; | |
13 | import org.stringtemplate.v4.StringRenderer; | |
14 | ||
15 | import java.util.Arrays; | |
16 | import java.util.HashSet; | |
17 | import java.util.Set; | |
18 | ||
19 | public class PHPTarget extends Target { | |
20 | private static final String[] phpKeywords = { | |
21 | "abstract", "and", "array", "as", | |
22 | "break", | |
23 | "callable", "case", "catch", "class", "clone", "const", "continue", | |
24 | "declare", "default", "die", "do", | |
25 | "echo", "else", "elseif", "empty", "enddeclare", "endfor", "endforeach", | |
26 | "endif", "endswitch", "endwhile", "eval", "exit", "extends", | |
27 | "final", "finally", "for", "foreach", "function", | |
28 | "global", "goto", | |
29 | "if", "implements", "include", "include_once", "instanceof", "insteadof", "interface", "isset", | |
30 | "list", | |
31 | "namespace", "new", | |
32 | "or", | |
33 | "print", "private", "protected", "public", | |
34 | "require", "require_once", "return", | |
35 | "static", "switch", | |
36 | "throw", "trait", "try", | |
37 | "unset", "use", | |
38 | "var", | |
39 | "while", | |
40 | "xor", | |
41 | "yield", | |
42 | "__halt_compiler", "__CLASS__", "__DIR__", "__FILE__", "__FUNCTION__", | |
43 | "__LINE__", "__METHOD__", "__NAMESPACE__", "__TRAIT__" | |
44 | }; | |
45 | ||
46 | private final Set<String> badWords = new HashSet<String>(); | |
47 | ||
48 | public PHPTarget(CodeGenerator gen) { | |
49 | super(gen, "PHP"); | |
50 | ||
51 | targetCharValueEscape['$'] = "\\$"; | |
52 | } | |
53 | ||
54 | @Override | |
55 | public String getVersion() { | |
56 | return "4.9.2"; | |
57 | } | |
58 | ||
59 | @Override | |
60 | public String encodeIntAsCharEscape(int v) { | |
61 | if (v < Character.MIN_VALUE || v > Character.MAX_VALUE) { | |
62 | throw new IllegalArgumentException(String.format("Cannot encode the specified value: %d", v)); | |
63 | } | |
64 | ||
65 | return String.format("\\u{%X}", v & 0xFFFF); | |
66 | } | |
67 | ||
68 | public Set<String> getBadWords() { | |
69 | if (badWords.isEmpty()) { | |
70 | addBadWords(); | |
71 | } | |
72 | ||
73 | return badWords; | |
74 | } | |
75 | ||
76 | protected void addBadWords() { | |
77 | badWords.addAll(Arrays.asList(phpKeywords)); | |
78 | badWords.add("rule"); | |
79 | badWords.add("parserRule"); | |
80 | } | |
81 | ||
82 | @Override | |
83 | protected boolean visibleGrammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode) { | |
84 | return getBadWords().contains(idNode.getText()); | |
85 | } | |
86 | ||
87 | @Override | |
88 | protected STGroup loadTemplates() { | |
89 | STGroup result = super.loadTemplates(); | |
90 | result.registerRenderer(String.class, new StringRenderer(), true); | |
91 | ||
92 | return result; | |
93 | } | |
94 | ||
95 | @Override | |
96 | public boolean supportsOverloadedMethods() { | |
97 | return false; | |
98 | } | |
99 | ||
100 | @Override | |
101 | protected void appendUnicodeEscapedCodePoint(int codePoint, StringBuilder sb) { | |
102 | UnicodeEscapes.appendPythonStyleEscapedCodePoint(codePoint, sb); | |
103 | } | |
104 | ||
105 | @Override | |
106 | public String getTargetStringLiteralFromANTLRStringLiteral(CodeGenerator generator, String literal, boolean addQuotes) { | |
107 | String targetStringLiteral = super.getTargetStringLiteralFromANTLRStringLiteral(generator, literal, addQuotes); | |
108 | targetStringLiteral = targetStringLiteral.replace("$", "\\$"); | |
109 | ||
110 | return targetStringLiteral; | |
111 | } | |
112 | } |
94 | 94 | |
95 | 95 | @Override |
96 | 96 | public String getVersion() { |
97 | return "4.7.2"; | |
97 | return "4.9.2"; | |
98 | 98 | } |
99 | 99 | |
100 | 100 | public Set<String> getBadWords() { |
96 | 96 | |
97 | 97 | @Override |
98 | 98 | public String getVersion() { |
99 | return "4.7.2"; | |
99 | return "4.9.2"; | |
100 | 100 | } |
101 | 101 | |
102 | 102 | /** Avoid grammar symbols in this set to prevent conflicts in gen'd code. */ |
86 | 86 | |
87 | 87 | @Override |
88 | 88 | public String getVersion() { |
89 | return "4.7.2"; // Java and tool versions move in lock step | |
89 | return "4.9.2"; // Java and tool versions move in lock step | |
90 | 90 | } |
91 | 91 | |
92 | 92 | public Set<String> getBadWords() { |
804 | 804 | // lexer specification. It matches a single character of any value and being |
805 | 805 | // the last rule in the file will match when no other rule knows what to do |
806 | 806 | // about the character. It is reported as an error but is not passed on to the |
807 | // parser. This means that the parser to deal with the gramamr file anyway | |
807 | // parser. This means that the parser to deal with the grammar file anyway | |
808 | 808 | // but we will not try to analyse or code generate from a file with lexical |
809 | 809 | // errors. |
810 | 810 | // |
269 | 269 | : IMPORT delegateGrammar (COMMA delegateGrammar)* SEMI -> ^(IMPORT delegateGrammar+) |
270 | 270 | ; |
271 | 271 | |
272 | // A possibly named grammar file that should be imported to this gramamr | |
272 | // A possibly named grammar file that should be imported to this grammar | |
273 | 273 | // and delgated to for the rules it specifies |
274 | 274 | delegateGrammar |
275 | 275 | : id ASSIGN^ id |
724 | 724 | ) |
725 | 725 | ; |
726 | 726 | |
727 | // A block of gramamr structure optionally followed by standard EBNF | |
727 | // A block of grammar structure optionally followed by standard EBNF | |
728 | 728 | // notation, or ANTLR specific notation. I.E. ? + ^ and so on |
729 | 729 | ebnf |
730 | 730 | : block |
320 | 320 | } |
321 | 321 | |
322 | 322 | void checkNumRules(GrammarAST rulesNode) { |
323 | if ( rulesNode.getChildCount()==0 ) { | |
323 | Boolean emptyGrammar = true; | |
324 | ||
325 | for (Rule rule : ruleCollector.rules.values()) { | |
326 | if (!rule.isFragment()) { | |
327 | emptyGrammar = false; | |
328 | break; | |
329 | } | |
330 | } | |
331 | ||
332 | if (emptyGrammar) { | |
324 | 333 | GrammarAST root = (GrammarAST)rulesNode.getParent(); |
325 | 334 | GrammarAST IDNode = (GrammarAST)root.getChild(0); |
326 | 335 | g.tool.errMgr.grammarError(ErrorType.NO_RULES, g.fileName, |
340 | 340 | * <li>implicitly generated grammar <em>grammar</em> has no rules</li> |
341 | 341 | * </ul> |
342 | 342 | */ |
343 | NO_RULES(99, "<if(arg2.implicitLexerOwner)>implicitly generated <endif>grammar <arg> has no rules", ErrorSeverity.ERROR), | |
343 | NO_RULES(99, "<if(arg2.implicitLexerOwner)>implicitly generated <endif>grammar <arg> has no non-fragment rules", ErrorSeverity.ERROR), | |
344 | 344 | /** |
345 | 345 | * Compiler Error 105. |
346 | 346 | * |
9 | 9 | <parent> |
10 | 10 | <groupId>org.antlr</groupId> |
11 | 11 | <artifactId>antlr4-master</artifactId> |
12 | <version>4.7.2</version> | |
12 | <version>4.9.2</version> | |
13 | 13 | </parent> |
14 | 14 | <artifactId>antlr4-tool-testsuite</artifactId> |
15 | 15 | <name>ANTLR 4 Tool Tests</name> |
25 | 25 | <dependency> |
26 | 26 | <groupId>org.antlr</groupId> |
27 | 27 | <artifactId>ST4</artifactId> |
28 | <version>4.1</version> | |
28 | <version>4.3</version> | |
29 | 29 | <scope>test</scope> |
30 | 30 | </dependency> |
31 | 31 | <dependency> |
44 | 44 | <dependency> |
45 | 45 | <groupId>junit</groupId> |
46 | 46 | <artifactId>junit</artifactId> |
47 | <version>4.12</version> | |
48 | <scope>test</scope> | |
47 | <version>4.13.1</version> | |
48 | <scope>test</scope> | |
49 | 49 | </dependency> |
50 | 50 | </dependencies> |
51 | 51 | |
66 | 66 | <systemPropertyVariables> |
67 | 67 | <antlr-python2-runtime>../../antlr4-python2/src</antlr-python2-runtime> |
68 | 68 | <antlr-python3-runtime>../../antlr4-python3/src</antlr-python3-runtime> |
69 | <antlr-csharp-runtime-project>../../antlr4-csharp/runtime/CSharp/Antlr4.Runtime/Antlr4.Runtime.mono.csproj</antlr-csharp-runtime-project> | |
70 | 69 | <antlr-cpp-runtime>../../antlr4-cpp/src</antlr-cpp-runtime> |
71 | 70 | <antlr-javascript-runtime>../../antlr4-javascript/src</antlr-javascript-runtime> |
72 | 71 | </systemPropertyVariables> |
0 | package org.antlr.v4.misc; | |
1 | ||
2 | import org.antlr.runtime.Token; | |
3 | import org.antlr.v4.tool.ast.GrammarAST; | |
4 | import org.junit.Assert; | |
5 | import org.junit.Test; | |
6 | ||
7 | import java.util.ArrayList; | |
8 | ||
9 | public class UtilsTest { | |
10 | ||
11 | @Test | |
12 | public void testStripFileExtension() { | |
13 | Assert.assertNull(Utils.stripFileExtension(null)); | |
14 | Assert.assertEquals("foo", Utils.stripFileExtension("foo")); | |
15 | Assert.assertEquals("foo", Utils.stripFileExtension("foo.txt")); | |
16 | } | |
17 | ||
18 | @Test | |
19 | public void testJoin() { | |
20 | Assert.assertEquals("foobbar", | |
21 | Utils.join(new String[]{"foo", "bar"}, "b")); | |
22 | Assert.assertEquals("foo,bar", | |
23 | Utils.join(new String[]{"foo", "bar"}, ",")); | |
24 | } | |
25 | ||
26 | @Test | |
27 | public void testSortLinesInString() { | |
28 | Assert.assertEquals("bar\nbaz\nfoo\n", | |
29 | Utils.sortLinesInString("foo\nbar\nbaz")); | |
30 | } | |
31 | ||
32 | @Test | |
33 | public void testNodesToStrings() { | |
34 | ArrayList<GrammarAST> values = new ArrayList<>(); | |
35 | values.add(new GrammarAST(Token.EOR_TOKEN_TYPE)); | |
36 | values.add(new GrammarAST(Token.DOWN)); | |
37 | values.add(new GrammarAST(Token.UP)); | |
38 | ||
39 | Assert.assertNull(Utils.nodesToStrings(null)); | |
40 | Assert.assertNotNull(Utils.nodesToStrings(values)); | |
41 | } | |
42 | ||
43 | @Test | |
44 | public void testCapitalize() { | |
45 | Assert.assertEquals("Foo", Utils.capitalize("foo")); | |
46 | } | |
47 | ||
48 | @Test | |
49 | public void testDecapitalize() { | |
50 | Assert.assertEquals("fOO", Utils.decapitalize("FOO")); | |
51 | } | |
52 | ||
53 | @Test | |
54 | public void testSelect() { | |
55 | ArrayList<String> strings = new ArrayList<>(); | |
56 | strings.add("foo"); | |
57 | strings.add("bar"); | |
58 | ||
59 | Utils.Func1<String, String> func1 = new Utils.Func1() { | |
60 | @Override | |
61 | public Object exec(Object arg1) { | |
62 | return "baz"; | |
63 | } | |
64 | }; | |
65 | ||
66 | ArrayList<String> retval = new ArrayList<>(); | |
67 | retval.add("baz"); | |
68 | retval.add("baz"); | |
69 | ||
70 | Assert.assertEquals(retval, Utils.select(strings, func1)); | |
71 | Assert.assertNull(Utils.select(null, null)); | |
72 | } | |
73 | ||
74 | @Test | |
75 | public void testFind() { | |
76 | ArrayList<String> strings = new ArrayList<>(); | |
77 | strings.add("foo"); | |
78 | strings.add("bar"); | |
79 | Assert.assertEquals("foo", Utils.find(strings, String.class)); | |
80 | ||
81 | Assert.assertNull(Utils.find(new ArrayList<>(), String.class)); | |
82 | } | |
83 | ||
84 | @Test | |
85 | public void testIndexOf() { | |
86 | ArrayList<String> strings = new ArrayList<>(); | |
87 | strings.add("foo"); | |
88 | strings.add("bar"); | |
89 | Utils.Filter filter = new Utils.Filter() { | |
90 | @Override | |
91 | public boolean select(Object o) { | |
92 | return true; | |
93 | } | |
94 | }; | |
95 | Assert.assertEquals(0, Utils.indexOf(strings, filter)); | |
96 | Assert.assertEquals(-1, Utils.indexOf(new ArrayList<>(), null)); | |
97 | } | |
98 | ||
99 | @Test | |
100 | public void testLastIndexOf() { | |
101 | ArrayList<String> strings = new ArrayList<>(); | |
102 | strings.add("foo"); | |
103 | strings.add("bar"); | |
104 | Utils.Filter filter = new Utils.Filter() { | |
105 | @Override | |
106 | public boolean select(Object o) { | |
107 | return true; | |
108 | } | |
109 | }; | |
110 | Assert.assertEquals(1, Utils.lastIndexOf(strings, filter)); | |
111 | Assert.assertEquals(-1, Utils.lastIndexOf(new ArrayList<>(), null)); | |
112 | } | |
113 | ||
114 | @Test | |
115 | public void testSetSize() { | |
116 | ArrayList<String> strings = new ArrayList<>(); | |
117 | strings.add("foo"); | |
118 | strings.add("bar"); | |
119 | strings.add("baz"); | |
120 | Assert.assertEquals(3, strings.size()); | |
121 | ||
122 | Utils.setSize(strings, 2); | |
123 | Assert.assertEquals(2, strings.size()); | |
124 | ||
125 | Utils.setSize(strings, 4); | |
126 | Assert.assertEquals(4, strings.size()); | |
127 | } | |
128 | } |
15 | 15 | import static org.junit.Assert.assertEquals; |
16 | 16 | |
17 | 17 | public class BaseJavaToolTest extends BaseJavaTest { |
18 | ||
18 | 19 | public void testErrors(String[] pairs, boolean printTree) { |
19 | 20 | for (int i = 0; i < pairs.length; i+=2) { |
20 | 21 | String grammarStr = pairs[i]; |
22 | 23 | |
23 | 24 | String[] lines = grammarStr.split("\n"); |
24 | 25 | String fileName = getFilenameFromFirstLineOfGrammar(lines[0]); |
25 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, null, fileName, grammarStr, false); // use default language target in case test overrides | |
26 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), null, fileName, grammarStr, false); // use default language target in case test overrides | |
26 | 27 | |
27 | 28 | String actual = equeue.toString(true); |
28 | actual = actual.replace(tmpdir + File.separator, ""); | |
29 | actual = actual.replace(getTempDirPath() + File.separator, ""); | |
29 | 30 | // System.err.println(actual); |
30 | 31 | String msg = grammarStr; |
31 | 32 | msg = msg.replace("\n","\\n"); |
0 | /* | |
1 | * Copyright (c) 2012-2019 The ANTLR Project. All rights reserved. | |
2 | * Use of this file is governed by the BSD 3-clause license that | |
3 | * can be found in the LICENSE.txt file in the project root. | |
4 | */ | |
5 | ||
6 | package org.antlr.v4.test.tool; | |
7 | ||
8 | import org.antlr.v4.misc.CharSupport; | |
9 | import org.antlr.v4.runtime.misc.IntervalSet; | |
10 | import org.junit.Assert; | |
11 | import org.junit.Test; | |
12 | ||
13 | public class CharSupportTest { | |
14 | ||
15 | @Test | |
16 | public void testGetANTLRCharLiteralForChar() { | |
17 | Assert.assertEquals("'<INVALID>'", | |
18 | CharSupport.getANTLRCharLiteralForChar(-1)); | |
19 | Assert.assertEquals("'\\n'", | |
20 | CharSupport.getANTLRCharLiteralForChar('\n')); | |
21 | Assert.assertEquals("'\\\\'", | |
22 | CharSupport.getANTLRCharLiteralForChar('\\')); | |
23 | Assert.assertEquals("'\\''", | |
24 | CharSupport.getANTLRCharLiteralForChar('\'')); | |
25 | Assert.assertEquals("'b'", | |
26 | CharSupport.getANTLRCharLiteralForChar('b')); | |
27 | Assert.assertEquals("'\\uFFFF'", | |
28 | CharSupport.getANTLRCharLiteralForChar(0xFFFF)); | |
29 | Assert.assertEquals("'\\u{10FFFF}'", | |
30 | CharSupport.getANTLRCharLiteralForChar(0x10FFFF)); | |
31 | } | |
32 | ||
33 | @Test | |
34 | public void testGetCharValueFromGrammarCharLiteral() { | |
35 | Assert.assertEquals(-1, | |
36 | CharSupport.getCharValueFromGrammarCharLiteral(null)); | |
37 | Assert.assertEquals(-1, | |
38 | CharSupport.getCharValueFromGrammarCharLiteral("")); | |
39 | Assert.assertEquals(-1, | |
40 | CharSupport.getCharValueFromGrammarCharLiteral("b")); | |
41 | Assert.assertEquals(111, | |
42 | CharSupport.getCharValueFromGrammarCharLiteral("foo")); | |
43 | } | |
44 | ||
45 | @Test | |
46 | public void testGetStringFromGrammarStringLiteral() { | |
47 | Assert.assertNull(CharSupport | |
48 | .getStringFromGrammarStringLiteral("foo\\u{bbb")); | |
49 | Assert.assertNull(CharSupport | |
50 | .getStringFromGrammarStringLiteral("foo\\u{[]bb")); | |
51 | Assert.assertNull(CharSupport | |
52 | .getStringFromGrammarStringLiteral("foo\\u[]bb")); | |
53 | Assert.assertNull(CharSupport | |
54 | .getStringFromGrammarStringLiteral("foo\\ubb")); | |
55 | ||
56 | Assert.assertEquals("oo»b", CharSupport | |
57 | .getStringFromGrammarStringLiteral("foo\\u{bb}bb")); | |
58 | } | |
59 | ||
60 | @Test | |
61 | public void testGetCharValueFromCharInGrammarLiteral() { | |
62 | Assert.assertEquals(102, | |
63 | CharSupport.getCharValueFromCharInGrammarLiteral("f")); | |
64 | ||
65 | Assert.assertEquals(-1, | |
66 | CharSupport.getCharValueFromCharInGrammarLiteral("\' ")); | |
67 | Assert.assertEquals(-1, | |
68 | CharSupport.getCharValueFromCharInGrammarLiteral("\\ ")); | |
69 | Assert.assertEquals(39, | |
70 | CharSupport.getCharValueFromCharInGrammarLiteral("\\\'")); | |
71 | Assert.assertEquals(10, | |
72 | CharSupport.getCharValueFromCharInGrammarLiteral("\\n")); | |
73 | ||
74 | Assert.assertEquals(-1, | |
75 | CharSupport.getCharValueFromCharInGrammarLiteral("foobar")); | |
76 | Assert.assertEquals(4660, | |
77 | CharSupport.getCharValueFromCharInGrammarLiteral("\\u1234")); | |
78 | Assert.assertEquals(18, | |
79 | CharSupport.getCharValueFromCharInGrammarLiteral("\\u{12}")); | |
80 | ||
81 | Assert.assertEquals(-1, | |
82 | CharSupport.getCharValueFromCharInGrammarLiteral("\\u{")); | |
83 | Assert.assertEquals(-1, | |
84 | CharSupport.getCharValueFromCharInGrammarLiteral("foo")); | |
85 | } | |
86 | ||
87 | @Test | |
88 | public void testParseHexValue() { | |
89 | Assert.assertEquals(-1, CharSupport.parseHexValue("foobar", -1, 3)); | |
90 | Assert.assertEquals(-1, CharSupport.parseHexValue("foobar", 1, -1)); | |
91 | Assert.assertEquals(-1, CharSupport.parseHexValue("foobar", 1, 3)); | |
92 | Assert.assertEquals(35, CharSupport.parseHexValue("123456", 1, 3)); | |
93 | } | |
94 | ||
95 | @Test | |
96 | public void testCapitalize() { | |
97 | Assert.assertEquals("Foo", CharSupport.capitalize("foo")); | |
98 | } | |
99 | ||
100 | @Test | |
101 | public void testGetIntervalSetEscapedString() { | |
102 | Assert.assertEquals("", | |
103 | CharSupport.getIntervalSetEscapedString(new IntervalSet())); | |
104 | Assert.assertEquals("'\\u0000'", | |
105 | CharSupport.getIntervalSetEscapedString(new IntervalSet(0))); | |
106 | Assert.assertEquals("'\\u0001'..'\\u0003'", | |
107 | CharSupport.getIntervalSetEscapedString(new IntervalSet(3, 1, 2))); | |
108 | } | |
109 | ||
110 | @Test | |
111 | public void testGetRangeEscapedString() { | |
112 | Assert.assertEquals("'\\u0002'..'\\u0004'", | |
113 | CharSupport.getRangeEscapedString(2, 4)); | |
114 | Assert.assertEquals("'\\u0002'", | |
115 | CharSupport.getRangeEscapedString(2, 2)); | |
116 | } | |
117 | } |
8 | 8 | import org.antlr.v4.automata.ParserATNFactory; |
9 | 9 | import org.antlr.v4.runtime.Lexer; |
10 | 10 | import org.antlr.v4.runtime.NoViableAltException; |
11 | import org.antlr.v4.runtime.TokenStream; | |
11 | 12 | import org.antlr.v4.runtime.atn.ATN; |
12 | 13 | import org.antlr.v4.runtime.atn.ATNState; |
13 | 14 | import org.antlr.v4.runtime.atn.BlockStartState; |
14 | 15 | import org.antlr.v4.runtime.atn.LexerATNSimulator; |
15 | 16 | import org.antlr.v4.runtime.dfa.DFA; |
16 | 17 | import org.antlr.v4.runtime.misc.IntegerList; |
18 | import org.antlr.v4.test.runtime.MockIntTokenStream; | |
17 | 19 | import org.antlr.v4.tool.DOTGenerator; |
18 | 20 | import org.antlr.v4.tool.Grammar; |
19 | 21 | import org.antlr.v4.tool.LexerGrammar; |
21 | 23 | import org.junit.Before; |
22 | 24 | import org.junit.Test; |
23 | 25 | |
26 | import static org.antlr.v4.test.runtime.RuntimeTestUtils.getTokenTypesViaATN; | |
24 | 27 | import static org.junit.Assert.assertEquals; |
25 | 28 | |
26 | 29 | // NOTICE: TOKENS IN LEXER, PARSER MUST BE SAME OR TOKEN TYPE MISMATCH |
372 | 375 | ParserATNFactory f = new ParserATNFactory(g); |
373 | 376 | ATN atn = f.createATN(); |
374 | 377 | |
375 | IntTokenStream input = new IntTokenStream(types); | |
378 | TokenStream input = new MockIntTokenStream(types); | |
376 | 379 | // System.out.println("input="+input.types); |
377 | 380 | ParserInterpreterForTesting interp = new ParserInterpreterForTesting(g, input); |
378 | 381 | ATNState startState = atn.ruleToStartState[g.getRule("a").index]; |
10 | 10 | import org.antlr.v4.runtime.atn.ATN; |
11 | 11 | import org.antlr.v4.runtime.atn.ATNState; |
12 | 12 | import org.antlr.v4.runtime.misc.Utils; |
13 | import org.antlr.v4.test.runtime.RuntimeTestUtils; | |
13 | 14 | import org.antlr.v4.tool.DOTGenerator; |
14 | 15 | import org.antlr.v4.tool.LexerGrammar; |
15 | 16 | import org.junit.Before; |
385 | 386 | DOTGenerator dot = new DOTGenerator(lg); |
386 | 387 | // System.out.println(dot.getDOT(startState, true)); |
387 | 388 | |
388 | List<String> tokenTypes = getTokenTypes(lg, atn, input); | |
389 | List<String> tokenTypes = RuntimeTestUtils.getTokenTypes(lg, atn, input); | |
389 | 390 | |
390 | 391 | String result = Utils.join(tokenTypes.iterator(), ", "); |
391 | 392 | // System.out.println(tokenTypes); |
16 | 16 | import org.antlr.v4.runtime.atn.PredictionContextCache; |
17 | 17 | import org.antlr.v4.runtime.dfa.DFA; |
18 | 18 | import org.antlr.v4.runtime.misc.IntegerList; |
19 | import org.antlr.v4.test.runtime.MockIntTokenStream; | |
19 | 20 | import org.antlr.v4.tool.DOTGenerator; |
20 | 21 | import org.antlr.v4.tool.Grammar; |
21 | 22 | import org.antlr.v4.tool.LeftRecursiveRule; |
26 | 27 | |
27 | 28 | import java.util.Arrays; |
28 | 29 | |
30 | import static org.antlr.v4.test.runtime.RuntimeTestUtils.getTokenTypesViaATN; | |
29 | 31 | import static org.junit.Assert.assertEquals; |
30 | 32 | import static org.junit.Assert.assertTrue; |
31 | 33 | |
525 | 527 | |
526 | 528 | // Check ATN prediction |
527 | 529 | // ParserATNSimulator interp = new ParserATNSimulator(atn); |
528 | TokenStream input = new IntTokenStream(types); | |
530 | TokenStream input = new MockIntTokenStream(types); | |
529 | 531 | ParserInterpreterForTesting interp = new ParserInterpreterForTesting(g, input); |
530 | 532 | int alt = interp.adaptivePredict(input, decision, ParserRuleContext.EMPTY); |
531 | 533 | |
558 | 560 | // Check DFA |
559 | 561 | IntegerList types = getTokenTypesViaATN(inputString[i], lexInterp); |
560 | 562 | // System.out.println(types); |
561 | TokenStream input = new IntTokenStream(types); | |
563 | TokenStream input = new MockIntTokenStream(types); | |
562 | 564 | try { |
563 | 565 | interp.adaptivePredict(input, decision, ParserRuleContext.EMPTY); |
564 | 566 | } |
7 | 7 | |
8 | 8 | import org.antlr.v4.test.runtime.BaseRuntimeTest; |
9 | 9 | import org.antlr.v4.test.runtime.ErrorQueue; |
10 | import org.antlr.v4.test.runtime.RuntimeTestUtils; | |
10 | 11 | import org.antlr.v4.tool.ANTLRMessage; |
11 | 12 | import org.antlr.v4.tool.ErrorType; |
12 | 13 | import org.antlr.v4.tool.Grammar; |
17 | 18 | import java.io.File; |
18 | 19 | |
19 | 20 | import static org.antlr.v4.test.runtime.BaseRuntimeTest.writeFile; |
21 | import static org.antlr.v4.test.runtime.RuntimeTestUtils.sort; | |
20 | 22 | import static org.junit.Assert.assertEquals; |
21 | 23 | import static org.junit.Assert.assertNull; |
22 | 24 | |
33 | 35 | String slave = |
34 | 36 | "parser grammar S;\n" + |
35 | 37 | "a : B {System.out.println(\"S.a\");} ;\n"; |
36 | BaseRuntimeTest.mkdir(tmpdir); | |
37 | String subdir = tmpdir + "/sub"; | |
38 | BaseRuntimeTest.mkdir(subdir); | |
38 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
39 | String subdir = getTempDirPath() + PATH_SEP + "sub"; | |
40 | RuntimeTestUtils.mkdir(subdir); | |
39 | 41 | writeFile(subdir, "S.g4", slave); |
40 | 42 | String master = |
41 | 43 | "grammar M;\n" + |
43 | 45 | "s : a ;\n" + |
44 | 46 | "B : 'b' ;" + // defines B from inherited token space |
45 | 47 | "WS : (' '|'\\n') -> skip ;\n" ; |
46 | writeFile(tmpdir, "M.g4", master); | |
47 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", subdir); | |
48 | writeFile(getTempDirPath(), "M.g4", master); | |
49 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", subdir); | |
48 | 50 | assertEquals(0, equeue.size()); |
49 | 51 | } |
50 | 52 | |
51 | 53 | // Test for https://github.com/antlr/antlr4/issues/1317 |
52 | 54 | @Test public void testImportSelfLoop() throws Exception { |
53 | BaseRuntimeTest.mkdir(tmpdir); | |
55 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
54 | 56 | String master = |
55 | 57 | "grammar M;\n" + |
56 | 58 | "import M;\n" + |
57 | 59 | "s : 'a' ;\n"; |
58 | writeFile(tmpdir, "M.g4", master); | |
59 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", tmpdir); | |
60 | writeFile(getTempDirPath(), "M.g4", master); | |
61 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", getTempDirPath()); | |
60 | 62 | assertEquals(0, equeue.size()); |
61 | 63 | } |
62 | 64 | |
63 | 65 | @Test public void testImportIntoLexerGrammar() throws Exception { |
64 | BaseRuntimeTest.mkdir(tmpdir); | |
66 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
65 | 67 | |
66 | 68 | String master = |
67 | 69 | "lexer grammar M;\n" + |
68 | 70 | "import S;\n" + |
69 | 71 | "A : 'a';\n" + |
70 | 72 | "B : 'b';\n"; |
71 | writeFile(tmpdir, "M.g4", master); | |
72 | ||
73 | String slave = | |
73 | writeFile(getTempDirPath(), "M.g4", master); | |
74 | ||
75 | String slave = | |
74 | 76 | "lexer grammar S;\n" + |
75 | 77 | "C : 'c';\n"; |
76 | writeFile(tmpdir, "S.g4", slave); | |
77 | ||
78 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", tmpdir); | |
78 | writeFile(getTempDirPath(), "S.g4", slave); | |
79 | ||
80 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", getTempDirPath()); | |
79 | 81 | assertEquals(0, equeue.errors.size()); |
80 | 82 | } |
81 | 83 | |
82 | 84 | @Test public void testImportModesIntoLexerGrammar() throws Exception { |
83 | BaseRuntimeTest.mkdir(tmpdir); | |
85 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
84 | 86 | |
85 | 87 | String master = |
86 | 88 | "lexer grammar M;\n" + |
87 | 89 | "import S;\n" + |
88 | 90 | "A : 'a' -> pushMode(X);\n" + |
89 | 91 | "B : 'b';\n"; |
90 | writeFile(tmpdir, "M.g4", master); | |
91 | ||
92 | String slave = | |
92 | writeFile(getTempDirPath(), "M.g4", master); | |
93 | ||
94 | String slave = | |
93 | 95 | "lexer grammar S;\n" + |
94 | 96 | "D : 'd';\n" + |
95 | 97 | "mode X;\n" + |
96 | 98 | "C : 'c' -> popMode;\n"; |
97 | writeFile(tmpdir, "S.g4", slave); | |
98 | ||
99 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", tmpdir); | |
99 | writeFile(getTempDirPath(), "S.g4", slave); | |
100 | ||
101 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", getTempDirPath()); | |
100 | 102 | assertEquals(0, equeue.errors.size()); |
101 | 103 | } |
102 | ||
104 | ||
103 | 105 | @Test public void testImportChannelsIntoLexerGrammar() throws Exception { |
104 | BaseRuntimeTest.mkdir(tmpdir); | |
106 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
105 | 107 | |
106 | 108 | String master = |
107 | 109 | "lexer grammar M;\n" + |
109 | 111 | "channels {CH_A, CH_B}\n" + |
110 | 112 | "A : 'a' -> channel(CH_A);\n" + |
111 | 113 | "B : 'b' -> channel(CH_B);\n"; |
112 | writeFile(tmpdir, "M.g4", master); | |
113 | ||
114 | String slave = | |
114 | writeFile(getTempDirPath(), "M.g4", master); | |
115 | ||
116 | String slave = | |
115 | 117 | "lexer grammar S;\n" + |
116 | 118 | "C : 'c';\n"; |
117 | writeFile(tmpdir, "S.g4", slave); | |
118 | ||
119 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", tmpdir); | |
119 | writeFile(getTempDirPath(), "S.g4", slave); | |
120 | ||
121 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", getTempDirPath()); | |
120 | 122 | assertEquals(0, equeue.errors.size()); |
121 | 123 | } |
122 | ||
124 | ||
123 | 125 | @Test public void testImportMixedChannelsIntoLexerGrammar() throws Exception { |
124 | BaseRuntimeTest.mkdir(tmpdir); | |
126 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
125 | 127 | |
126 | 128 | String master = |
127 | 129 | "lexer grammar M;\n" + |
129 | 131 | "channels {CH_A, CH_B}\n" + |
130 | 132 | "A : 'a' -> channel(CH_A);\n" + |
131 | 133 | "B : 'b' -> channel(CH_B);\n"; |
132 | writeFile(tmpdir, "M.g4", master); | |
133 | ||
134 | String slave = | |
134 | writeFile(getTempDirPath(), "M.g4", master); | |
135 | ||
136 | String slave = | |
135 | 137 | "lexer grammar S;\n" + |
136 | 138 | "channels {CH_C}\n" + |
137 | 139 | "C : 'c' -> channel(CH_C);\n"; |
138 | writeFile(tmpdir, "S.g4", slave); | |
139 | ||
140 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", tmpdir); | |
140 | writeFile(getTempDirPath(), "S.g4", slave); | |
141 | ||
142 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", getTempDirPath()); | |
141 | 143 | assertEquals(0, equeue.errors.size()); |
142 | 144 | } |
143 | 145 | |
144 | 146 | @Test public void testImportClashingChannelsIntoLexerGrammar() throws Exception { |
145 | BaseRuntimeTest.mkdir(tmpdir); | |
147 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
146 | 148 | |
147 | 149 | String master = |
148 | 150 | "lexer grammar M;\n" + |
151 | 153 | "A : 'a' -> channel(CH_A);\n" + |
152 | 154 | "B : 'b' -> channel(CH_B);\n" + |
153 | 155 | "C : 'C' -> channel(CH_C);\n"; |
154 | writeFile(tmpdir, "M.g4", master); | |
155 | ||
156 | String slave = | |
156 | writeFile(getTempDirPath(), "M.g4", master); | |
157 | ||
158 | String slave = | |
157 | 159 | "lexer grammar S;\n" + |
158 | 160 | "channels {CH_C}\n" + |
159 | 161 | "C : 'c' -> channel(CH_C);\n"; |
160 | writeFile(tmpdir, "S.g4", slave); | |
161 | ||
162 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", tmpdir); | |
162 | writeFile(getTempDirPath(), "S.g4", slave); | |
163 | ||
164 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", getTempDirPath()); | |
163 | 165 | assertEquals(0, equeue.errors.size()); |
164 | } | |
165 | ||
166 | } | |
167 | ||
166 | 168 | @Test public void testMergeModesIntoLexerGrammar() throws Exception { |
167 | BaseRuntimeTest.mkdir(tmpdir); | |
169 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
168 | 170 | |
169 | 171 | String master = |
170 | 172 | "lexer grammar M;\n" + |
172 | 174 | "A : 'a' -> pushMode(X);\n" + |
173 | 175 | "mode X;\n" + |
174 | 176 | "B : 'b';\n"; |
175 | writeFile(tmpdir, "M.g4", master); | |
176 | ||
177 | String slave = | |
177 | writeFile(getTempDirPath(), "M.g4", master); | |
178 | ||
179 | String slave = | |
178 | 180 | "lexer grammar S;\n" + |
179 | 181 | "D : 'd';\n" + |
180 | 182 | "mode X;\n" + |
181 | 183 | "C : 'c' -> popMode;\n"; |
182 | writeFile(tmpdir, "S.g4", slave); | |
183 | ||
184 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", tmpdir); | |
184 | writeFile(getTempDirPath(), "S.g4", slave); | |
185 | ||
186 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", getTempDirPath()); | |
185 | 187 | assertEquals(0, equeue.errors.size()); |
186 | 188 | } |
187 | ||
189 | ||
188 | 190 | @Test public void testEmptyModesInLexerGrammar() throws Exception { |
189 | BaseRuntimeTest.mkdir(tmpdir); | |
191 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
190 | 192 | |
191 | 193 | String master = |
192 | 194 | "lexer grammar M;\n" + |
193 | 195 | "import S;\n" + |
194 | 196 | "A : 'a';\n" + |
195 | "C : 'e';\n" + | |
197 | "C : 'e';\n" + | |
196 | 198 | "B : 'b';\n"; |
197 | writeFile(tmpdir, "M.g4", master); | |
198 | ||
199 | String slave = | |
199 | writeFile(getTempDirPath(), "M.g4", master); | |
200 | ||
201 | String slave = | |
200 | 202 | "lexer grammar S;\n" + |
201 | 203 | "D : 'd';\n" + |
202 | 204 | "mode X;\n" + |
203 | 205 | "C : 'c' -> popMode;\n"; |
204 | writeFile(tmpdir, "S.g4", slave); | |
205 | ||
206 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", tmpdir); | |
206 | writeFile(getTempDirPath(), "S.g4", slave); | |
207 | ||
208 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", getTempDirPath()); | |
207 | 209 | assertEquals(0, equeue.errors.size()); |
208 | 210 | } |
209 | ||
211 | ||
210 | 212 | @Test public void testCombinedGrammarImportsModalLexerGrammar() throws Exception { |
211 | BaseRuntimeTest.mkdir(tmpdir); | |
213 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
212 | 214 | |
213 | 215 | String master = |
214 | 216 | "grammar M;\n" + |
216 | 218 | "A : 'a';\n" + |
217 | 219 | "B : 'b';\n" + |
218 | 220 | "r : A B;\n"; |
219 | writeFile(tmpdir, "M.g4", master); | |
220 | ||
221 | String slave = | |
221 | writeFile(getTempDirPath(), "M.g4", master); | |
222 | ||
223 | String slave = | |
222 | 224 | "lexer grammar S;\n" + |
223 | 225 | "D : 'd';\n" + |
224 | 226 | "mode X;\n" + |
225 | 227 | "C : 'c' -> popMode;\n"; |
226 | writeFile(tmpdir, "S.g4", slave); | |
227 | ||
228 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", tmpdir); | |
228 | writeFile(getTempDirPath(), "S.g4", slave); | |
229 | ||
230 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", getTempDirPath()); | |
229 | 231 | assertEquals(1, equeue.errors.size()); |
230 | 232 | ANTLRMessage msg = equeue.errors.get(0); |
231 | 233 | assertEquals(ErrorType.MODE_NOT_IN_LEXER, msg.getErrorType()); |
233 | 235 | assertEquals(3, msg.line); |
234 | 236 | assertEquals(5, msg.charPosition); |
235 | 237 | assertEquals("M.g4", new File(msg.fileName).getName()); |
236 | } | |
238 | } | |
237 | 239 | |
238 | 240 | @Test public void testDelegatesSeeSameTokenType() throws Exception { |
239 | 241 | String slaveS = |
245 | 247 | "tokens { C, B, A } // reverse order\n"+ |
246 | 248 | "y : A ;\n"; |
247 | 249 | |
248 | BaseRuntimeTest.mkdir(tmpdir); | |
249 | writeFile(tmpdir, "S.g4", slaveS); | |
250 | writeFile(tmpdir, "T.g4", slaveT); | |
250 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
251 | writeFile(getTempDirPath(), "S.g4", slaveS); | |
252 | writeFile(getTempDirPath(), "T.g4", slaveT); | |
251 | 253 | |
252 | 254 | String master = |
253 | 255 | "// The lexer will create rules to match letters a, b, c.\n"+ |
267 | 269 | "A : 'a' ;\n"+ |
268 | 270 | "C : 'c' ;\n"+ |
269 | 271 | "WS : (' '|'\\n') -> skip ;\n"; |
270 | writeFile(tmpdir, "M.g4", master); | |
272 | writeFile(getTempDirPath(), "M.g4", master); | |
271 | 273 | ErrorQueue equeue = new ErrorQueue(); |
272 | Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue); | |
274 | Grammar g = new Grammar(getTempDirPath()+"/M.g4", master, equeue); | |
273 | 275 | String expectedTokenIDToTypeMap = "{EOF=-1, B=1, A=2, C=3, WS=4}"; |
274 | 276 | String expectedStringLiteralToTypeMap = "{'a'=2, 'b'=1, 'c'=3}"; |
275 | 277 | String expectedTypeToTokenList = "[B, A, C, WS]"; |
283 | 285 | String slave = |
284 | 286 | "parser grammar S;\n" + |
285 | 287 | "a : 'a' | c;\n"; |
286 | BaseRuntimeTest.mkdir(tmpdir); | |
287 | writeFile(tmpdir, "S.g4", slave); | |
288 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
289 | writeFile(getTempDirPath(), "S.g4", slave); | |
288 | 290 | String master = |
289 | 291 | "grammar M;\n" + |
290 | 292 | "import S;\n"; |
291 | writeFile(tmpdir, "M.g4", master); | |
292 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-lib", tmpdir); | |
293 | writeFile(getTempDirPath(), "M.g4", master); | |
294 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-lib", getTempDirPath()); | |
293 | 295 | ANTLRMessage msg = equeue.errors.get(0); |
294 | 296 | assertEquals(ErrorType.UNDEFINED_RULE_REF, msg.getErrorType()); |
295 | 297 | assertEquals("c", msg.getArgs()[0]); |
302 | 304 | String slave = |
303 | 305 | "parser grammar S;\n" + |
304 | 306 | "a : B {System.out.println(\"S.a\");} ;\n"; |
305 | BaseRuntimeTest.mkdir(tmpdir); | |
306 | String outdir = tmpdir + "/out"; | |
307 | BaseRuntimeTest.mkdir(outdir); | |
307 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
308 | String outdir = getTempDirPath() + "/out"; | |
309 | RuntimeTestUtils.mkdir(outdir); | |
308 | 310 | writeFile(outdir, "S.g4", slave); |
309 | 311 | String master = |
310 | 312 | "grammar M;\n" + |
312 | 314 | "s : a ;\n" + |
313 | 315 | "B : 'b' ;" + // defines B from inherited token space |
314 | 316 | "WS : (' '|'\\n') -> skip ;\n" ; |
315 | writeFile(tmpdir, "M.g4", master); | |
316 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-o", outdir); | |
317 | writeFile(getTempDirPath(), "M.g4", master); | |
318 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-o", outdir); | |
317 | 319 | assertEquals(ErrorType.CANNOT_FIND_IMPORTED_GRAMMAR, equeue.errors.get(0).getErrorType()); |
318 | 320 | } |
319 | 321 | |
321 | 323 | String slave = |
322 | 324 | "parser grammar S;\n" + |
323 | 325 | "a : B {System.out.println(\"S.a\");} ;\n"; |
324 | BaseRuntimeTest.mkdir(tmpdir); | |
325 | String subdir = tmpdir + "/sub"; | |
326 | BaseRuntimeTest.mkdir(subdir); | |
326 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
327 | String subdir = getTempDirPath() + "/sub"; | |
328 | RuntimeTestUtils.mkdir(subdir); | |
327 | 329 | writeFile(subdir, "S.g4", slave); |
328 | 330 | String master = |
329 | 331 | "grammar M;\n" + |
331 | 333 | "s : a ;\n" + |
332 | 334 | "B : 'b' ;" + // defines B from inherited token space |
333 | 335 | "WS : (' '|'\\n') -> skip ;\n" ; |
334 | writeFile(tmpdir, "M.g4", master); | |
335 | String outdir = tmpdir + "/out"; | |
336 | BaseRuntimeTest.mkdir(outdir); | |
337 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", false, "-o", outdir, "-lib", subdir); | |
336 | writeFile(getTempDirPath(), "M.g4", master); | |
337 | String outdir = getTempDirPath() + "/out"; | |
338 | RuntimeTestUtils.mkdir(outdir); | |
339 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", false, "-o", outdir, "-lib", subdir); | |
338 | 340 | assertEquals(0, equeue.size()); |
339 | 341 | } |
340 | 342 | |
342 | 344 | String slave = |
343 | 345 | "parser grammar S;\n" + |
344 | 346 | "a : B {System.out.println(\"S.a\");} ;\n"; |
345 | BaseRuntimeTest.mkdir(tmpdir); | |
346 | String subdir = tmpdir + "/sub"; | |
347 | BaseRuntimeTest.mkdir(subdir); | |
347 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
348 | String subdir = getTempDirPath() + "/sub"; | |
349 | RuntimeTestUtils.mkdir(subdir); | |
348 | 350 | writeFile(subdir, "S.g4", slave); |
349 | 351 | String parser = |
350 | 352 | "parser grammar MParser;\n" + |
351 | 353 | "import S;\n" + |
352 | 354 | "options {tokenVocab=MLexer;}\n" + |
353 | 355 | "s : a ;\n"; |
354 | writeFile(tmpdir, "MParser.g4", parser); | |
356 | writeFile(getTempDirPath(), "MParser.g4", parser); | |
355 | 357 | String lexer = |
356 | 358 | "lexer grammar MLexer;\n" + |
357 | 359 | "B : 'b' ;" + // defines B from inherited token space |
358 | 360 | "WS : (' '|'\\n') -> skip ;\n" ; |
359 | writeFile(tmpdir, "MLexer.g4", lexer); | |
360 | String outdir = tmpdir + "/out"; | |
361 | BaseRuntimeTest.mkdir(outdir); | |
362 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "MLexer.g4", false, "-o", outdir); | |
361 | writeFile(getTempDirPath(), "MLexer.g4", lexer); | |
362 | String outdir = getTempDirPath() + "/out"; | |
363 | RuntimeTestUtils.mkdir(outdir); | |
364 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "MLexer.g4", false, "-o", outdir); | |
363 | 365 | assertEquals(0, equeue.size()); |
364 | equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "MParser.g4", false, "-o", outdir, "-lib", subdir); | |
366 | equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "MParser.g4", false, "-o", outdir, "-lib", subdir); | |
365 | 367 | assertEquals(0, equeue.size()); |
366 | 368 | } |
367 | 369 | |
372 | 374 | "options {tokenVocab=whatever;}\n" + |
373 | 375 | "tokens { A }\n" + |
374 | 376 | "x : A {System.out.println(\"S.x\");} ;\n"; |
375 | BaseRuntimeTest.mkdir(tmpdir); | |
376 | writeFile(tmpdir, "S.g4", slave); | |
377 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
378 | writeFile(getTempDirPath(), "S.g4", slave); | |
377 | 379 | |
378 | 380 | String master = |
379 | 381 | "grammar M;\n" + |
380 | 382 | "import S;\n" + |
381 | 383 | "s : x ;\n" + |
382 | 384 | "WS : (' '|'\\n') -> skip ;\n" ; |
383 | writeFile(tmpdir, "M.g4", master); | |
384 | Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue); | |
385 | writeFile(getTempDirPath(), "M.g4", master); | |
386 | Grammar g = new Grammar(getTempDirPath()+"/M.g4", master, equeue); | |
385 | 387 | |
386 | 388 | Object expectedArg = "S"; |
387 | 389 | ErrorType expectedMsgID = ErrorType.OPTIONS_IN_DELEGATE; |
398 | 400 | String slave = |
399 | 401 | "parser grammar S;\n" + |
400 | 402 | "options {toke\n"; |
401 | BaseRuntimeTest.mkdir(tmpdir); | |
402 | writeFile(tmpdir, "S.g4", slave); | |
403 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
404 | writeFile(getTempDirPath(), "S.g4", slave); | |
403 | 405 | |
404 | 406 | String master = |
405 | 407 | "grammar M;\n" + |
406 | 408 | "import S;\n" + |
407 | 409 | "s : x ;\n" + |
408 | 410 | "WS : (' '|'\\n') -> skip ;\n" ; |
409 | writeFile(tmpdir, "M.g4", master); | |
410 | /*Grammar g =*/ new Grammar(tmpdir+"/M.g4", master, equeue); | |
411 | writeFile(getTempDirPath(), "M.g4", master); | |
412 | /*Grammar g =*/ new Grammar(getTempDirPath()+"/M.g4", master, equeue); | |
411 | 413 | |
412 | 414 | assertEquals(ErrorType.SYNTAX_ERROR, equeue.errors.get(0).getErrorType()); |
413 | 415 | } |
418 | 420 | String slave = |
419 | 421 | "parser grammar T;\n" + |
420 | 422 | "a : T ;\n" ; |
421 | BaseRuntimeTest.mkdir(tmpdir); | |
422 | writeFile(tmpdir, "T.g4", slave); | |
423 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
424 | writeFile(getTempDirPath(), "T.g4", slave); | |
423 | 425 | String slave2 = |
424 | 426 | "parser grammar S;\n" + |
425 | 427 | "import T;\n" + |
426 | 428 | "a : S ;\n" ; |
427 | BaseRuntimeTest.mkdir(tmpdir); | |
428 | writeFile(tmpdir, "S.g4", slave2); | |
429 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
430 | writeFile(getTempDirPath(), "S.g4", slave2); | |
429 | 431 | |
430 | 432 | String master = |
431 | 433 | "grammar M;\n" + |
432 | 434 | "import S;\n" + |
433 | 435 | "a : M ;\n" ; |
434 | writeFile(tmpdir, "M.g4", master); | |
435 | Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue); | |
436 | writeFile(getTempDirPath(), "M.g4", master); | |
437 | Grammar g = new Grammar(getTempDirPath()+"/M.g4", master, equeue); | |
436 | 438 | |
437 | 439 | String expectedTokenIDToTypeMap = "{EOF=-1, M=1}"; // S and T aren't imported; overridden |
438 | 440 | String expectedStringLiteralToTypeMap = "{}"; |
458 | 460 | "parser grammar T;\n" + |
459 | 461 | "tokens{T}\n" + |
460 | 462 | "x : T ;\n" ; |
461 | BaseRuntimeTest.mkdir(tmpdir); | |
462 | writeFile(tmpdir, "T.g4", slave); | |
463 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
464 | writeFile(getTempDirPath(), "T.g4", slave); | |
463 | 465 | slave = |
464 | 466 | "parser grammar S;\n" + |
465 | 467 | "import T;\n" + |
466 | 468 | "tokens{S}\n" + |
467 | 469 | "y : S ;\n" ; |
468 | BaseRuntimeTest.mkdir(tmpdir); | |
469 | writeFile(tmpdir, "S.g4", slave); | |
470 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
471 | writeFile(getTempDirPath(), "S.g4", slave); | |
470 | 472 | |
471 | 473 | slave = |
472 | 474 | "parser grammar C;\n" + |
473 | 475 | "tokens{C}\n" + |
474 | 476 | "i : C ;\n" ; |
475 | BaseRuntimeTest.mkdir(tmpdir); | |
476 | writeFile(tmpdir, "C.g4", slave); | |
477 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
478 | writeFile(getTempDirPath(), "C.g4", slave); | |
477 | 479 | slave = |
478 | 480 | "parser grammar B;\n" + |
479 | 481 | "tokens{B}\n" + |
480 | 482 | "j : B ;\n" ; |
481 | BaseRuntimeTest.mkdir(tmpdir); | |
482 | writeFile(tmpdir, "B.g4", slave); | |
483 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
484 | writeFile(getTempDirPath(), "B.g4", slave); | |
483 | 485 | slave = |
484 | 486 | "parser grammar A;\n" + |
485 | 487 | "import B,C;\n" + |
486 | 488 | "tokens{A}\n" + |
487 | 489 | "k : A ;\n" ; |
488 | BaseRuntimeTest.mkdir(tmpdir); | |
489 | writeFile(tmpdir, "A.g4", slave); | |
490 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
491 | writeFile(getTempDirPath(), "A.g4", slave); | |
490 | 492 | |
491 | 493 | String master = |
492 | 494 | "grammar M;\n" + |
493 | 495 | "import S,A;\n" + |
494 | 496 | "tokens{M}\n" + |
495 | 497 | "a : M ;\n" ; |
496 | writeFile(tmpdir, "M.g4", master); | |
497 | Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue); | |
498 | writeFile(getTempDirPath(), "M.g4", master); | |
499 | Grammar g = new Grammar(getTempDirPath()+"/M.g4", master, equeue); | |
498 | 500 | |
499 | 501 | assertEquals("[]", equeue.errors.toString()); |
500 | 502 | assertEquals("[]", equeue.warnings.toString()); |
519 | 521 | String slave = |
520 | 522 | "parser grammar T;\n" + |
521 | 523 | "x : T ;\n" ; |
522 | BaseRuntimeTest.mkdir(tmpdir); | |
523 | writeFile(tmpdir, "T.g4", slave); | |
524 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
525 | writeFile(getTempDirPath(), "T.g4", slave); | |
524 | 526 | String slave2 = |
525 | 527 | "parser grammar S;\n" + // A, B, C token type order |
526 | 528 | "import T;\n" + |
527 | 529 | "a : S ;\n" ; |
528 | BaseRuntimeTest.mkdir(tmpdir); | |
529 | writeFile(tmpdir, "S.g4", slave2); | |
530 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
531 | writeFile(getTempDirPath(), "S.g4", slave2); | |
530 | 532 | |
531 | 533 | String master = |
532 | 534 | "grammar M;\n" + |
533 | 535 | "import S;\n" + |
534 | 536 | "a : M x ;\n" ; // x MUST BE VISIBLE TO M |
535 | writeFile(tmpdir, "M.g4", master); | |
536 | Grammar g = new Grammar(tmpdir+"/M.g4", master, equeue); | |
537 | writeFile(getTempDirPath(), "M.g4", master); | |
538 | Grammar g = new Grammar(getTempDirPath()+"/M.g4", master, equeue); | |
537 | 539 | |
538 | 540 | String expectedTokenIDToTypeMap = "{EOF=-1, M=1, T=2}"; |
539 | 541 | String expectedStringLiteralToTypeMap = "{}"; |
557 | 559 | "T2: '2';\n" + |
558 | 560 | "T3: '3';\n" + |
559 | 561 | "T4: '4';\n" ; |
560 | BaseRuntimeTest.mkdir(tmpdir); | |
561 | writeFile(tmpdir, "L.g4", gstr); | |
562 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
563 | writeFile(getTempDirPath(), "L.g4", gstr); | |
562 | 564 | gstr = |
563 | 565 | "parser grammar G1;\n" + |
564 | 566 | "s: a | b;\n" + |
565 | 567 | "a: T1;\n" + |
566 | 568 | "b: T2;\n" ; |
567 | BaseRuntimeTest.mkdir(tmpdir); | |
568 | writeFile(tmpdir, "G1.g4", gstr); | |
569 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
570 | writeFile(getTempDirPath(), "G1.g4", gstr); | |
569 | 571 | |
570 | 572 | gstr = |
571 | 573 | "parser grammar G2;\n" + |
572 | 574 | "import G1;\n" + |
573 | 575 | "a: T3;\n" ; |
574 | BaseRuntimeTest.mkdir(tmpdir); | |
575 | writeFile(tmpdir, "G2.g4", gstr); | |
576 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
577 | writeFile(getTempDirPath(), "G2.g4", gstr); | |
576 | 578 | String G3str = |
577 | 579 | "grammar G3;\n" + |
578 | 580 | "import G2;\n" + |
579 | 581 | "b: T4;\n" ; |
580 | BaseRuntimeTest.mkdir(tmpdir); | |
581 | writeFile(tmpdir, "G3.g4", G3str); | |
582 | ||
583 | Grammar g = new Grammar(tmpdir+"/G3.g4", G3str, equeue); | |
582 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
583 | writeFile(getTempDirPath(), "G3.g4", G3str); | |
584 | ||
585 | Grammar g = new Grammar(getTempDirPath()+"/G3.g4", G3str, equeue); | |
584 | 586 | |
585 | 587 | String expectedTokenIDToTypeMap = "{EOF=-1, T4=1, T3=2}"; |
586 | 588 | String expectedStringLiteralToTypeMap = "{}"; |
604 | 606 | String slave = |
605 | 607 | "parser grammar S;\n" + |
606 | 608 | "a : B {System.out.print(\"S.a\");} ;\n"; |
607 | BaseRuntimeTest.mkdir(tmpdir); | |
608 | writeFile(tmpdir, "S.g4", slave); | |
609 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
610 | writeFile(getTempDirPath(), "S.g4", slave); | |
609 | 611 | String master = |
610 | 612 | "grammar M;\n" + |
611 | 613 | "import S;\n" + |
613 | 615 | "s : a ;\n" + |
614 | 616 | "B : 'b' ;" + // defines B from inherited token space |
615 | 617 | "WS : (' '|'\\n') -> skip ;\n" ; |
616 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "M.g4", master, false); | |
618 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "M.g4", master, false); | |
617 | 619 | int expecting = 0; // should be ok |
618 | 620 | assertEquals(expecting, equeue.errors.size()); |
619 | 621 | } |
632 | 634 | "grammar NewJava;\n" + |
633 | 635 | "import Java;\n"; |
634 | 636 | |
635 | BaseRuntimeTest.mkdir(tmpdir); | |
636 | writeFile(tmpdir, "Java.g4", slave); | |
637 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
638 | writeFile(getTempDirPath(), "Java.g4", slave); | |
637 | 639 | String found = execParser("NewJava.g4", master, "NewJavaParser", "NewJavaLexer", |
638 | 640 | null, null, "compilationUnit", "package Foo;", debug); |
639 | 641 | assertEquals(null, found); |
640 | assertNull(stderrDuringParse); | |
642 | assertNull(getParseErrors()); | |
641 | 643 | } |
642 | 644 | |
643 | 645 | /** |
660 | 662 | "import Java;\n" + |
661 | 663 | "s : e ;\n"; |
662 | 664 | |
663 | BaseRuntimeTest.mkdir(tmpdir); | |
664 | writeFile(tmpdir, "Java.g4", slave); | |
665 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
666 | writeFile(getTempDirPath(), "Java.g4", slave); | |
665 | 667 | String found = execParser("T.g4", master, "TParser", "TLexer", |
666 | 668 | null, null, "s", "a=b", debug); |
667 | 669 | assertEquals(null, found); |
668 | assertNull(stderrDuringParse); | |
670 | assertNull(getParseErrors()); | |
669 | 671 | } |
670 | 672 | } |
27 | 27 | String found = execParser("T.g4", grammar, "TParser", "TLexer", |
28 | 28 | null, null, "a", "x", true); |
29 | 29 | assertTrue(found.indexOf(this.getClass().getSimpleName())>=0); |
30 | assertNull(this.stderrDuringParse); | |
30 | assertNull(getParseErrors()); | |
31 | 31 | } |
32 | 32 | |
33 | 33 | } |
74 | 74 | "s1-INT->s2\n" + |
75 | 75 | "s2-EOF->:s3=>1\n"; // Must point at accept state |
76 | 76 | assertEquals(expecting, result); |
77 | assertNull(this.stderrDuringParse); | |
77 | assertNull(getParseErrors()); | |
78 | 78 | } |
79 | 79 | |
80 | 80 | /** |
87 | 87 | String grammar = load("Psl.g4", "UTF-8"); |
88 | 88 | String found = execParser("Psl.g4", grammar, "PslParser", "PslLexer", null, null, "floating_constant", " . 234", false); |
89 | 89 | assertEquals(null, found); |
90 | assertEquals("line 1:6 rule floating_constant DEC:A floating-point constant cannot have internal white space\n", stderrDuringParse); | |
90 | assertEquals("line 1:6 rule floating_constant DEC:A floating-point constant cannot have internal white space\n", getParseErrors()); | |
91 | 91 | } |
92 | 92 | |
93 | 93 | /** |
128 | 128 | String found = execParser("ModeTagsParser.g4", parserGrammar, "ModeTagsParser", "ModeTagsLexer", |
129 | 129 | null, null, "file", "", false); |
130 | 130 | assertEquals(null, found); |
131 | assertNull(stderrDuringParse); | |
131 | assertNull(getParseErrors()); | |
132 | 132 | } |
133 | 133 | |
134 | 134 | /** |
157 | 157 | String found = execParser("Data.g4", grammar, "DataParser", "DataLexer", |
158 | 158 | null, null, "file", input, false); |
159 | 159 | assertEquals("6\n", found); |
160 | assertNull(stderrDuringParse); | |
160 | assertNull(getParseErrors()); | |
161 | 161 | } |
162 | 162 | } |
222 | 222 | " {decision=1, contextSensitivities=0, errors=0, ambiguities=0, SLL_lookahead=6, " + |
223 | 223 | "SLL_ATNTransitions=3, SLL_DFATransitions=3, LL_Fallback=0, LL_lookahead=0, LL_ATNTransitions=0}]\n"; |
224 | 224 | assertEquals(expecting, found); |
225 | assertEquals(null, stderrDuringParse); | |
225 | assertEquals(null, getParseErrors()); | |
226 | 226 | } |
227 | 227 | |
228 | 228 | public DecisionInfo[] interpAndGetDecisionInfo( |
41 | 41 | import org.antlr.v4.runtime.tree.TerminalNode; |
42 | 42 | import org.antlr.v4.test.runtime.BaseRuntimeTest; |
43 | 43 | import org.antlr.v4.test.runtime.ErrorQueue; |
44 | import org.antlr.v4.test.runtime.RuntimeTestUtils; | |
44 | 45 | import org.junit.Assert; |
45 | 46 | import org.junit.Before; |
46 | 47 | import org.junit.Test; |
700 | 701 | builder.append(", Grammar=").append(USE_LR_GRAMMAR ? "LR" : "Standard"); |
701 | 702 | builder.append(", ForceAtn=").append(FORCE_ATN); |
702 | 703 | |
703 | builder.append(newline); | |
704 | builder.append(NEW_LINE); | |
704 | 705 | |
705 | 706 | builder.append("Op=Lex").append(RUN_PARSER ? "+Parse" : " only"); |
706 | 707 | builder.append(", Strategy=").append(BAIL_ON_ERROR ? BailErrorStrategy.class.getSimpleName() : DefaultErrorStrategy.class.getSimpleName()); |
707 | 708 | builder.append(", BuildParseTree=").append(BUILD_PARSE_TREES); |
708 | 709 | builder.append(", WalkBlankListener=").append(BLANK_LISTENER); |
709 | 710 | |
710 | builder.append(newline); | |
711 | builder.append(NEW_LINE); | |
711 | 712 | |
712 | 713 | builder.append("Lexer=").append(REUSE_LEXER ? "setInputStream" : "newInstance"); |
713 | 714 | builder.append(", Parser=").append(REUSE_PARSER ? "setInputStream" : "newInstance"); |
714 | 715 | builder.append(", AfterPass=").append(CLEAR_DFA ? "newInstance" : "setInputStream"); |
715 | 716 | |
716 | builder.append(newline); | |
717 | builder.append(NEW_LINE); | |
717 | 718 | |
718 | 719 | return builder.toString(); |
719 | 720 | } |
1134 | 1135 | |
1135 | 1136 | protected ParserFactory getParserFactory(String lexerName, String parserName, String listenerName, final String entryPoint) { |
1136 | 1137 | try { |
1137 | ClassLoader loader = new URLClassLoader(new URL[] { new File(tmpdir).toURI().toURL() }, ClassLoader.getSystemClassLoader()); | |
1138 | ClassLoader loader = new URLClassLoader(new URL[] { getTempTestDir().toURI().toURL() }, ClassLoader.getSystemClassLoader()); | |
1138 | 1139 | final Class<? extends Lexer> lexerClass = loader.loadClass(lexerName).asSubclass(Lexer.class); |
1139 | 1140 | final Class<? extends Parser> parserClass = loader.loadClass(parserName).asSubclass(Parser.class); |
1140 | 1141 | final Class<? extends ParseTreeListener> listenerClass = loader.loadClass(listenerName).asSubclass(ParseTreeListener.class); |
1951 | 1952 | "\n" + |
1952 | 1953 | "rule_%d_%d : EOF;\n"; |
1953 | 1954 | |
1954 | BaseRuntimeTest.mkdir(tmpdir); | |
1955 | RuntimeTestUtils.mkdir(getTempDirPath()); | |
1955 | 1956 | |
1956 | 1957 | long startTime = System.nanoTime(); |
1957 | 1958 | |
1959 | 1960 | for (int level = 0; level < levels; level++) { |
1960 | 1961 | String leafPrefix = level == levels - 1 ? "//" : ""; |
1961 | 1962 | String grammar1 = String.format(grammarFormat, level, 1, leafPrefix, level + 1, level + 1, level, 1); |
1962 | writeFile(tmpdir, "Level_" + level + "_1.g4", grammar1); | |
1963 | writeFile(getTempDirPath(), "Level_" + level + "_1.g4", grammar1); | |
1963 | 1964 | if (level > 0) { |
1964 | 1965 | String grammar2 = String.format(grammarFormat, level, 2, leafPrefix, level + 1, level + 1, level, 1); |
1965 | writeFile(tmpdir, "Level_" + level + "_2.g4", grammar2); | |
1966 | } | |
1967 | } | |
1968 | ||
1969 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(tmpdir, "Java", "Level_0_1.g4", false); | |
1966 | writeFile(getTempDirPath(), "Level_" + level + "_2.g4", grammar2); | |
1967 | } | |
1968 | } | |
1969 | ||
1970 | ErrorQueue equeue = BaseRuntimeTest.antlrOnString(getTempDirPath(), "Java", "Level_0_1.g4", false); | |
1970 | 1971 | Assert.assertTrue(equeue.errors.isEmpty()); |
1971 | 1972 | |
1972 | 1973 | long endTime = System.nanoTime(); |
12 | 12 | import org.junit.Test; |
13 | 13 | |
14 | 14 | public class TestToolSyntaxErrors extends BaseJavaToolTest { |
15 | static String[] A = { | |
16 | // INPUT | |
15 | static String[] A = { | |
16 | // INPUT | |
17 | 17 | "grammar A;\n" + |
18 | 18 | "", |
19 | 19 | // YIELDS |
20 | "error(" + ErrorType.NO_RULES.code + "): A.g4::: grammar A has no rules\n", | |
20 | "error(" + ErrorType.NO_RULES.code + "): A.g4::: grammar A has no non-fragment rules\n", | |
21 | 21 | |
22 | 22 | "lexer grammar A;\n" + |
23 | 23 | "", |
24 | "error(" + ErrorType.NO_RULES.code + "): A.g4::: grammar A has no rules\n", | |
24 | "error(" + ErrorType.NO_RULES.code + "): A.g4::: grammar A has no non-fragment rules\n", | |
25 | ||
26 | "lexer grammar A;\n" + | |
27 | "fragment FRAGMENT: 'FRAGMENT';\n" + | |
28 | "", | |
29 | "error(" + ErrorType.NO_RULES.code + "): A.g4::: grammar A has no non-fragment rules\n", | |
25 | 30 | |
26 | 31 | "A;", |
27 | 32 | "error(" + ErrorType.SYNTAX_ERROR.code + "): A.g4:1:0: syntax error: 'A' came as a complete surprise to me\n", |