14 | Zephir is a high level language that eases the creation and maintainability
15 | of extensions for PHP. Zephir extensions are exported to C code that can be compiled
16 | and optimized by major C compilers such as gcc/clang/vc++. Functionality is exposed
17 | to the PHP language.
18 |
19 |
20 |
Highlighted Features
21 |
22 |
Syntax highlighting
23 |
Basic syntax definition
24 |
Basic autocompletion support
25 |
Basic syntax check support
26 |
27 | ]]>
28 |
29 | com.intellij.modules.platform
30 | com.intellij.modules.lang
31 |
32 |
33 |
34 |
36 |
37 |
38 |
39 |
40 |
42 |
43 |
44 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto init
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto init
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :init
68 | @rem Get command-line arguments, handling Windows variants
69 |
70 | if not "%OS%" == "Windows_NT" goto win9xME_args
71 |
72 | :win9xME_args
73 | @rem Slurp the command line arguments.
74 | set CMD_LINE_ARGS=
75 | set _SKIP=2
76 |
77 | :win9xME_args_slurp
78 | if "x%~1" == "x" goto execute
79 |
80 | set CMD_LINE_ARGS=%*
81 |
82 | :execute
83 | @rem Setup the command line
84 |
85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
86 |
87 |
88 | @rem Execute Gradle
89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
90 |
91 | :end
92 | @rem End local scope for the variables with windows NT shell
93 | if "%ERRORLEVEL%"=="0" goto mainEnd
94 |
95 | :fail
96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
97 | rem the _cmd.exe /c_ return code!
98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
99 | exit /b 1
100 |
101 | :mainEnd
102 | if "%OS%"=="Windows_NT" endlocal
103 |
104 | :omega
105 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
99 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/pluginIcon_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
99 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/zephir/ide/actions/ZephirCreateFileAction.kt:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014-2020 Zephir Team
2 | //
3 | // This source file is subject the MIT license, that is bundled with
4 | // this package in the file LICENSE, and is available through the
5 | // world-wide-web at the following url:
6 | //
7 | // https://github.com/zephir-lang/idea-plugin/blob/master/LICENSE
8 |
9 | package com.zephir.ide.actions
10 |
11 | import com.intellij.icons.AllIcons
12 | import com.intellij.ide.actions.CreateFileFromTemplateAction
13 | import com.intellij.ide.actions.CreateFileFromTemplateDialog
14 | import com.intellij.ide.fileTemplates.FileTemplate
15 | import com.intellij.ide.fileTemplates.FileTemplateManager
16 | import com.intellij.ide.fileTemplates.actions.AttributesDefaults
17 | import com.intellij.ide.fileTemplates.ui.CreateFromTemplateDialog
18 | import com.intellij.openapi.project.Project
19 | import com.intellij.openapi.util.io.FileUtilRt
20 | import com.intellij.psi.PsiDirectory
21 | import com.intellij.psi.PsiFile
22 | import com.intellij.util.IncorrectOperationException
23 | import com.zephir.lang.core.ZephirFileType
24 | import java.util.*
25 |
26 | // TODO(serghei): Put all natural language strings into the resource bundle src/main/resources/.../zephir.properties
27 | // TODO(serghei): Add a note about resource bundle to CONTRIBUTING.md
28 | class ZephirCreateFileAction : CreateFileFromTemplateAction(
29 | "Zephir File/Class",
30 | "Creates new Zephir file or class",
31 | ZephirFileType.icon
32 | ) {
33 | override fun buildDialog(
34 | project: Project,
35 | directory: PsiDirectory,
36 | builder: CreateFileFromTemplateDialog.Builder
37 | ) {
38 | // TODO(serghei): setValidator(ZephirNameValidator)
39 | builder.setTitle("New Zephir File/Class")
40 | .addKind("File", ZephirFileType.icon, "Zephir File")
41 | .addKind("Class", AllIcons.Nodes.Class, "Zephir Class")
42 | .addKind("Interface", AllIcons.Nodes.Interface, "Zephir Interface")
43 | }
44 |
45 | override fun getActionName(directory: PsiDirectory?, newName: String, templateName: String?): String =
46 | "Zephir File/Class"
47 |
48 | override fun createFileFromTemplate(name: String, template: FileTemplate, dir: PsiDirectory): PsiFile? {
49 | val project = dir.project
50 | val className = FileUtilRt.getNameWithoutExtension(name)
51 | val properties = createProperties(project, className)
52 |
53 | val element = try {
54 | CreateFromTemplateDialog(
55 | project,
56 | dir,
57 | template,
58 | AttributesDefaults(className).withFixedName(true),
59 | properties
60 | ).create()
61 | } catch (e: IncorrectOperationException) {
62 | LOG.error("Error while creating new file", e)
63 | throw e
64 | } catch (e: Exception) {
65 | LOG.error("Error while creating new file", e)
66 | null
67 | }
68 |
69 | return element?.containingFile
70 | }
71 |
72 | private companion object {
73 | fun createProperties(project: Project, className: String): Properties {
74 | val properties = FileTemplateManager.getInstance(project).defaultProperties
75 |
76 | // TODO(serghei): Do this better.
77 | // For example we can transform \Acme\Service to:
78 | // - "Acme" as a namespace
79 | // - "Service" as a class
80 | properties += "NAMESPACE" to project.name
81 | properties += "NAME" to className
82 |
83 | return properties
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](http://keepachangelog.com)
5 | and this project adheres to [Semantic Versioning](http://semver.org).
6 |
7 | ## [Unreleased][Unreleased]
8 | ## [0.4.0][0.4.0] - 2020-05-24
9 | ### Added
10 | - Amended Color Scheme configuration
11 | - Introduced recognition of angle brackets as paired ones
12 | - Added ability to create an empty Zephir File
13 |
14 | ### Changed
15 | - Migrated build to Gradle
16 | - Rewrote plugin from Java to Kotlin
17 | - Redesigned logic, determining when a closed brace/bracket should be inserted after an opened one
18 |
19 | ### Fixed
20 | - Corrected `New > Zephir File` dialog to use project's directory as a namespace
21 |
22 | ### Removed
23 | - Drop support of IDE's versions below `191`
24 |
25 | ## [0.3.6][0.3.6] - 2020-05-18
26 | ### Changed
27 | - Updated file icons
28 | - Corrected `change-notes` section to store changes only for the latest version of the plugin
29 |
30 | ## [0.3.5][0.3.5] - 2020-05-13
31 | ### Removed
32 | - Drop support of IDE's versions below `182`
33 |
34 | ## [0.3.4][0.3.4] - 2020-05-12
35 | ### Fixed
36 | - Replaced usage of deprecated API by new one
37 |
38 | ## [0.3.3][0.3.3] - 2019-09-07
39 | ### Fixed
40 | - Fixed recognizing strings with regular expressions
41 |
42 | ## [0.3.2][0.3.2] - 2017-12-27
43 | ### Added
44 | - Completion list now shows members of class
45 |
46 | ### Changed
47 | - Improved syntax support
48 |
49 | ## [0.3.1][0.3.1] - 2017-05-18
50 | ### Fixed
51 | - Fixed many bugs with syntax recognition
52 | - Fixed extra space in completion for method params
53 |
54 | ## [0.3.0][0.3.0] - 2017-05-12
55 | ### Added
56 | - Added few words to highlight
57 |
58 | ### Changed
59 | - Improved completion
60 |
61 | ### Fixed
62 | - Fixed many bugs with syntax recognition
63 |
64 | ## [0.2.5][0.2.5] - 2017-05-06
65 | ### Fixed
66 | - Fixed `switch` keyword detection
67 |
68 | ## [0.2.4][0.2.4] - 2014-09-22
69 | ### Added
70 | - Added brace matching support
71 |
72 | ## [0.2.3][0.2.3] - 2014-09-20
73 | ### Fixed
74 | - Fixed build
75 |
76 | ## [0.2.2][0.2.2] - 2014-09-15
77 | ### Added
78 | - Added color settings page
79 |
80 | ### Changed
81 | - Improve highlighter
82 |
83 | ## [0.2.1][0.2.2] - 2014-09-15
84 | ### Changed
85 | - Disabled "New Zephir class" dialog
86 |
87 | ## [0.2][0.2] - 2014-09-15
88 | ### Added
89 | - Added lexer and simple syntax highlighter
90 |
91 | ## 0.1 - 2014-09-08
92 | ### Added
93 | - Initial release
94 |
95 | [Unreleased]: https://github.com/zephir-lang/idea-plugin/compare/0.4.0...HEAD
96 | [0.4.0]: https://github.com/zephir-lang/idea-plugin/compare/0.3.6...0.4.0
97 | [0.3.6]: https://github.com/zephir-lang/idea-plugin/compare/0.3.5...0.3.6
98 | [0.3.5]: https://github.com/zephir-lang/idea-plugin/compare/0.3.4...0.3.5
99 | [0.3.4]: https://github.com/zephir-lang/idea-plugin/compare/0.3.3...0.3.4
100 | [0.3.3]: https://github.com/zephir-lang/idea-plugin/compare/0.3.2...0.3.3
101 | [0.3.2]: https://github.com/zephir-lang/idea-plugin/compare/0.3.1...0.3.2
102 | [0.3.1]: https://github.com/zephir-lang/idea-plugin/compare/0.3.0...0.3.1
103 | [0.3.0]: https://github.com/zephir-lang/idea-plugin/compare/0.2.5...0.3.0
104 | [0.2.5]: https://github.com/zephir-lang/idea-plugin/compare/0.2.4...0.2.5
105 | [0.2.4]: https://github.com/zephir-lang/idea-plugin/compare/0.2.3...0.2.4
106 | [0.2.3]: https://github.com/zephir-lang/idea-plugin/compare/0.2.2...0.2.3
107 | [0.2.2]: https://github.com/zephir-lang/idea-plugin/compare/0.2.1...0.2.2
108 | [0.2.1]: https://github.com/zephir-lang/idea-plugin/compare/0.2...0.2.1
109 | [0.2]: https://github.com/zephir-lang/idea-plugin/compare/0.1...0.2
110 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Zephir plugin for the IntelliJ Platform
2 |
3 | Zephir plugin for the IntelliJ Platform is an open source project and a
4 | volunteer effort. This project welcomes contribution from everyone. The
5 | following summarizes the process for contributing changes, and some
6 | guidelines on how to set up the project. Please take a moment to review
7 | this document in order to make the contribution process easy and effective
8 | for everyone involved.
9 |
10 | ## Prerequisites
11 |
12 | ### Kotlin
13 |
14 | We use [Kotlin][kotlin] language for the plugin. If you can program in Java,
15 | you should be able to read and write Kotlin code right away. Kotlin is deeply
16 | similar to Java, but has less verbose syntax and better safety. It also shares
17 | some characteristics with Rust: type inference, immutability by default, no
18 | null pointers (apart from those that come from Java).
19 |
20 | If you are unsure how to implement something in Kotlin, ask a question in our
21 | [Discord][discord] (use `#editorsupport` channel), send a PR in Java, or use
22 | **Convert Java to Kotlin** action in the IDE.
23 |
24 | Feel free to ask question or make suggestions in our [issue tracker][issues].
25 |
26 | ### Plugins
27 |
28 | You might want to install the following plugins:
29 |
30 | - [Grammar-Kit][g-kit] to get highlighting for the files with BNFish grammar
31 | - [PsiViewer][psi-view] to view the AST of Zephir files right in the IDE
32 | - [Kotlin][kotlin-plugin] to enable Kotlin support for your IDE
33 | - Plugin DevKit (built-in, just make sure you've enabled it)
34 |
35 | ## Getting started
36 |
37 | ### Clone
38 |
39 | ```shell script
40 | $ git clone https://github.com/zephir-lang/idea-plugin.git
41 | $ cd idea-plugin
42 | ```
43 |
44 | ### Building & Running
45 |
46 | Run `./gradlew runIde` run configuration to build and launch development IDE
47 | with the plugin.
48 |
49 | We use gradle with [gradle-intellij][gradle-intellij] plugin to build the
50 | plugin. It comes with a wrapper script (`gradlew` in the root of the
51 | repository) which downloads appropriate version of gradle automatically as
52 | long as you have JDK installed.
53 |
54 | Common Gradle tasks are:
55 |
56 | - `./gradlew build` -- Fully build plugin and create an archive at
57 | `build/distributions` which can be installed into IntelliJ IDEA via
58 | `Install plugin from disk...` action found in `Settings > Plugins`
59 | - `./gradlew runIde` - Runs Intellij IDEA with installed plugin. Break points
60 | works like a charm.
61 | - `./gradlew test` - Runs the unit tests. To run gradle with single class and
62 | method use something like this: `gradle test --tests com.zephir.ns.Class`
63 |
64 | ### Development in IntelliJ IDEA
65 |
66 | You can get the latest IntelliJ IDEA Community Edition [here][idea], it is
67 | free. Import the plugin project as you would do with any other gradle based
68 | project. For example, Ctrl + Shift + A,
69 | `Import Project from Existing Sources...` and select `build.gradle.kts` from
70 | the root directory of the plugin.
71 |
72 | ## Contributing
73 |
74 | To find a problem to work on, look for [`help wanted`][help] issues on Github,
75 | or, even better, try to fix a problem you face yourself when using the plugin.
76 |
77 | Work in progress pull requests are very welcome! It is also a great way to ask
78 | questions.
79 |
80 | ### Code style
81 |
82 | Please use **reformat code** action to maintain consistent style. Pay attention
83 | to IDEA's warning and suggestions, and try to keep the code green. If you are
84 | sure that the warning is false positive, use an annotation to suppress it.
85 |
86 | Try to avoid copy-paste and boilerplate as much as possible. For example,
87 | proactively use `?:` to deal with nullable values.
88 |
89 | If you add a new file, please make sure that it contains a license preamble, as
90 | all other files do.
91 |
92 | [kotlin]: https://kotlinlang.org
93 | [kotlin-plugin]: https://plugins.jetbrains.com/plugin/6954-kotlin
94 | [discord]: https://discord.gg/PNFsSsr
95 | [issues]: https://github.com/zephir-lang/zephir-mode/issues
96 | [gradle-intellij]: https://github.com/JetBrains/gradle-intellij-plugin
97 | [idea]: https://www.jetbrains.com/idea/download/
98 | [g-kit]: https://plugins.jetbrains.com/plugin/6606-grammar-kit
99 | [psi-view]: https://plugins.jetbrains.com/plugin/227-psiviewer
100 | [help]: https://github.com/zephir-lang/idea-plugin/labels/help%20wanted
101 |
--------------------------------------------------------------------------------
/src/test/testData/parser/Issue12.txt:
--------------------------------------------------------------------------------
1 | Zephir File
2 | ZephirNamespaceStatementImpl(NAMESPACE_STATEMENT)
3 | PsiElement(namespace)('namespace')
4 | PsiWhiteSpace(' ')
5 | ZephirComplexIdImpl(COMPLEX_ID)
6 | ZephirIdImpl(ID)
7 | PsiElement(IDENTIFIER)('Zephir')
8 | PsiElement(;)(';')
9 | PsiWhiteSpace('\n\n')
10 | ZephirClassDefinitionImpl(CLASS_DEFINITION)
11 | PsiElement(class)('class')
12 | PsiWhiteSpace(' ')
13 | ZephirIdImpl(ID)
14 | PsiElement(IDENTIFIER)('Issue12')
15 | PsiWhiteSpace(' ')
16 | ZephirClassBodyImpl(CLASS_BODY)
17 | PsiElement({)('{')
18 | PsiWhiteSpace('\n ')
19 | ZephirMethodDefinitionImpl(METHOD_DEFINITION)
20 | ZephirVisibilityImpl(VISIBILITY)
21 | PsiElement(public)('public')
22 | PsiWhiteSpace(' ')
23 | PsiElement(function)('function')
24 | PsiWhiteSpace(' ')
25 | ZephirIdImpl(ID)
26 | PsiElement(IDENTIFIER)('test')
27 | PsiElement(()('(')
28 | PsiElement())(')')
29 | PsiWhiteSpace(' ')
30 | ZephirMethodBodyImpl(METHOD_BODY)
31 | ZephirCodeBlockImpl(CODE_BLOCK)
32 | PsiElement({)('{')
33 | PsiWhiteSpace('\n ')
34 | ZephirCodeImpl(CODE)
35 | ZephirLetStatementImpl(LET_STATEMENT)
36 | PsiElement(let)('let')
37 | PsiWhiteSpace(' ')
38 | ZephirAssignmentExprImpl(ASSIGNMENT_EXPR)
39 | ZephirVariableImpl(VARIABLE)
40 | ZephirComplexIdImpl(COMPLEX_ID)
41 | ZephirIdImpl(ID)
42 | PsiElement(IDENTIFIER)('sql')
43 | PsiWhiteSpace(' ')
44 | ZephirAssignmentOperatorImpl(ASSIGNMENT_OPERATOR)
45 | PsiElement(=)('=')
46 | PsiWhiteSpace(' ')
47 | ZephirCallExprImpl(CALL_EXPR)
48 | ZephirLiteralExprImpl(LITERAL_EXPR)
49 | ZephirVariableImpl(VARIABLE)
50 | ZephirComplexIdImpl(COMPLEX_ID)
51 | ZephirIdImpl(ID)
52 | PsiElement(IDENTIFIER)('preg_replace')
53 | PsiElement(()('(')
54 | PsiWhiteSpace('\n ')
55 | ZephirCallArgumentsImpl(CALL_ARGUMENTS)
56 | ZephirLiteralExprImpl(LITERAL_EXPR)
57 | ZephirScalarImpl(SCALAR)
58 | PsiElement(STRING)('"/\?/"')
59 | PsiElement(,)(',')
60 | PsiWhiteSpace('\n ')
61 | ZephirCallExprImpl(CALL_EXPR)
62 | ZephirLiteralExprImpl(LITERAL_EXPR)
63 | ZephirVariableImpl(VARIABLE)
64 | ZephirComplexIdImpl(COMPLEX_ID)
65 | ZephirIdImpl(ID)
66 | PsiElement(IDENTIFIER)('this')
67 | PsiElement(->)('->')
68 | ZephirVariableImpl(VARIABLE)
69 | ZephirComplexIdImpl(COMPLEX_ID)
70 | ZephirIdImpl(ID)
71 | PsiElement(IDENTIFIER)('val')
72 | PsiElement(()('(')
73 | ZephirCallArgumentsImpl(CALL_ARGUMENTS)
74 | ZephirLiteralExprImpl(LITERAL_EXPR)
75 | ZephirVariableImpl(VARIABLE)
76 | ZephirComplexIdImpl(COMPLEX_ID)
77 | ZephirIdImpl(ID)
78 | PsiElement(IDENTIFIER)('value')
79 | PsiElement())(')')
80 | PsiElement(,)(',')
81 | PsiWhiteSpace('\n ')
82 | ZephirLiteralExprImpl(LITERAL_EXPR)
83 | ZephirVariableImpl(VARIABLE)
84 | ZephirComplexIdImpl(COMPLEX_ID)
85 | ZephirIdImpl(ID)
86 | PsiElement(IDENTIFIER)('sql')
87 | PsiElement(,)(',')
88 | PsiWhiteSpace('\n ')
89 | ZephirLiteralExprImpl(LITERAL_EXPR)
90 | ZephirScalarImpl(SCALAR)
91 | PsiElement(INTEGER)('1')
92 | PsiWhiteSpace('\n ')
93 | PsiElement())(')')
94 | PsiElement(;)(';')
95 | PsiWhiteSpace('\n ')
96 | PsiElement(})('}')
97 | PsiWhiteSpace('\n')
98 | PsiElement(})('}')
99 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/src/main/grammar/Lexer.skeleton:
--------------------------------------------------------------------------------
1 |
2 | /** This character denotes the end of file */
3 | public static final int YYEOF = -1;
4 |
5 | /** initial size of the lookahead buffer */
6 | --- private static final int ZZ_BUFFERSIZE = ...;
7 |
8 | /** lexical states */
9 | --- lexical states, charmap
10 |
11 | /* error codes */
12 | private static final int ZZ_UNKNOWN_ERROR = 0;
13 | private static final int ZZ_NO_MATCH = 1;
14 | private static final int ZZ_PUSHBACK_2BIG = 2;
15 |
16 | /* error messages for the codes above */
17 | private static final String[] ZZ_ERROR_MSG = {
18 | "Unknown internal scanner error",
19 | "Error: could not match input",
20 | "Error: pushback value was too large"
21 | };
22 |
23 | --- isFinal list
24 | /** the input device */
25 | private java.io.Reader zzReader;
26 |
27 | /** the current state of the DFA */
28 | private int zzState;
29 |
30 | /** the current lexical state */
31 | private int zzLexicalState = YYINITIAL;
32 |
33 | /** this buffer contains the current text to be matched and is
34 | the source of the yytext() string */
35 | private CharSequence zzBuffer = "";
36 |
37 | /** the textposition at the last accepting state */
38 | private int zzMarkedPos;
39 |
40 | /** the current text position in the buffer */
41 | private int zzCurrentPos;
42 |
43 | /** startRead marks the beginning of the yytext() string in the buffer */
44 | private int zzStartRead;
45 |
46 | /** endRead marks the last character in the buffer, that has been read
47 | from input */
48 | private int zzEndRead;
49 |
50 | /**
51 | * zzAtBOL == true <=> the scanner is currently at the beginning of a line
52 | */
53 | private boolean zzAtBOL = true;
54 |
55 | /** zzAtEOF == true <=> the scanner is at the EOF */
56 | private boolean zzAtEOF;
57 |
58 | /** denotes if the user-EOF-code has already been executed */
59 | private boolean zzEOFDone;
60 |
61 | --- user class code
62 |
63 | --- constructor declaration
64 |
65 | public final int getTokenStart() {
66 | return zzStartRead;
67 | }
68 |
69 | public final int getTokenEnd() {
70 | return getTokenStart() + yylength();
71 | }
72 |
73 | public void reset(CharSequence buffer, int start, int end, int initialState) {
74 | zzBuffer = buffer;
75 | zzCurrentPos = zzMarkedPos = zzStartRead = start;
76 | zzAtEOF = false;
77 | zzAtBOL = true;
78 | zzEndRead = end;
79 | yybegin(initialState);
80 | }
81 |
82 | /**
83 | * Refills the input buffer.
84 | *
85 | * @return {@code false}, iff there was new input.
86 | *
87 | * @exception java.io.IOException if any I/O-Error occurs
88 | */
89 | private boolean zzRefill() throws java.io.IOException {
90 | return true;
91 | }
92 |
93 |
94 | /**
95 | * Returns the current lexical state.
96 | */
97 | public final int yystate() {
98 | return zzLexicalState;
99 | }
100 |
101 |
102 | /**
103 | * Enters a new lexical state
104 | *
105 | * @param newState the new lexical state
106 | */
107 | public final void yybegin(int newState) {
108 | zzLexicalState = newState;
109 | }
110 |
111 |
112 | /**
113 | * Returns the text matched by the current regular expression.
114 | */
115 | public final CharSequence yytext() {
116 | return zzBuffer.subSequence(zzStartRead, zzMarkedPos);
117 | }
118 |
119 |
120 | /**
121 | * Returns the character at position {@code pos} from the
122 | * matched text.
123 | *
124 | * It is equivalent to yytext().charAt(pos), but faster
125 | *
126 | * @param pos the position of the character to fetch.
127 | * A value from 0 to yylength()-1.
128 | *
129 | * @return the character at position pos
130 | */
131 | public final char yycharat(int pos) {
132 | return zzBuffer.charAt(zzStartRead+pos);
133 | }
134 |
135 |
136 | /**
137 | * Returns the length of the matched text region.
138 | */
139 | public final int yylength() {
140 | return zzMarkedPos-zzStartRead;
141 | }
142 |
143 |
144 | /**
145 | * Reports an error that occurred while scanning.
146 | *
147 | * In a wellformed scanner (no or only correct usage of
148 | * yypushback(int) and a match-all fallback rule) this method
149 | * will only be called with things that "Can't Possibly Happen".
150 | * If this method is called, something is seriously wrong
151 | * (e.g. a JFlex bug producing a faulty scanner etc.).
152 | *
153 | * Usual syntax/scanner level error handling should be done
154 | * in error fallback rules.
155 | *
156 | * @param errorCode the code of the errormessage to display
157 | */
158 | --- zzScanError declaration
159 | String message;
160 | try {
161 | message = ZZ_ERROR_MSG[errorCode];
162 | }
163 | catch (ArrayIndexOutOfBoundsException e) {
164 | message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
165 | }
166 |
167 | --- throws clause
168 | }
169 |
170 |
171 | /**
172 | * Pushes the specified amount of characters back into the input stream.
173 | *
174 | * They will be read again by then next call of the scanning method
175 | *
176 | * @param number the number of characters to be read again.
177 | * This number must not be greater than yylength()!
178 | */
179 | --- yypushback decl (contains zzScanError exception)
180 | if ( number > yylength() )
181 | zzScanError(ZZ_PUSHBACK_2BIG);
182 |
183 | zzMarkedPos -= number;
184 | }
185 |
186 |
187 | --- zzDoEOF
188 | /**
189 | * Resumes scanning until the next regular expression is matched,
190 | * the end of input is encountered or an I/O-Error occurs.
191 | *
192 | * @return the next token
193 | * @exception java.io.IOException if any I/O-Error occurs
194 | */
195 | --- yylex declaration
196 | int zzInput;
197 | int zzAction;
198 |
199 | // cached fields:
200 | int zzCurrentPosL;
201 | int zzMarkedPosL;
202 | int zzEndReadL = zzEndRead;
203 | CharSequence zzBufferL = zzBuffer;
204 |
205 | --- local declarations
206 |
207 | while (true) {
208 | zzMarkedPosL = zzMarkedPos;
209 |
210 | --- start admin (line, char, col count)
211 | zzAction = -1;
212 |
213 | zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
214 |
215 | --- start admin (lexstate etc)
216 |
217 | zzForAction: {
218 | while (true) {
219 |
220 | --- next input, line, col, char count, next transition, isFinal action
221 | zzAction = zzState;
222 | zzMarkedPosL = zzCurrentPosL;
223 | --- line count update
224 | }
225 |
226 | }
227 | }
228 |
229 | // store back cached position
230 | zzMarkedPos = zzMarkedPosL;
231 | --- char count update
232 |
233 | if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
234 | zzAtEOF = true;
235 | --- eofvalue
236 | }
237 | else {
238 | --- actions
239 | default:
240 | --- no match
241 | }
242 | }
243 | }
244 | }
245 |
246 | --- main
247 |
248 | }
249 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/zephir/lang/core/completion/suggestors/ZephirMethodScopeCompletionSuggestor.kt:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014-2020 Zephir Team
2 | //
3 | // This source file is subject the MIT license, that is bundled with
4 | // this package in the file LICENSE, and is available through the
5 | // world-wide-web at the following url:
6 | //
7 | // https://github.com/zephir-lang/idea-plugin/blob/master/LICENSE
8 |
9 | package com.zephir.lang.core.completion.suggestors
10 |
11 | import com.intellij.codeInsight.completion.CompletionParameters
12 | import com.intellij.codeInsight.completion.CompletionResultSet
13 | import com.intellij.codeInsight.completion.PrioritizedLookupElement
14 | import com.intellij.codeInsight.lookup.LookupElementBuilder
15 | import com.intellij.psi.PsiElement
16 | import com.zephir.lang.core.completion.ZephirCompletionPriority
17 | import com.zephir.lang.core.completion.ZephirCompletionSuggestor
18 | import com.zephir.lang.core.psi.*
19 | import java.util.*
20 |
21 | object ZephirMethodScopeCompletionSuggestor : ZephirCompletionSuggestor {
22 | private const val MAX_SYNTAX_TREE_DEEP = 256
23 |
24 | private val keywords = arrayOf(
25 | "let", "echo", "const", "if", "else", "elseif", "switch", "case", "default",
26 | "do", "while", "for", "loop", "reverse", "break", "continue", "in", "new", "return",
27 | "require", "clone", "empty", "typeof", "instanceof", "likely", "unlikely", "fetch",
28 | "isset", "unset", "throw", "try", "catch"
29 | )
30 |
31 | private val typeHints = arrayOf(
32 | "var", "array", "object", "callable", "resource", "int", "integer", "uint", "long", "ulong",
33 | "double", "float", "string", "char", "uchar"
34 | )
35 |
36 | override fun addCompletions(parameters: CompletionParameters, result: CompletionResultSet) {
37 | val psiElement = parameters.originalPosition ?: return
38 |
39 | val methodDefinition = (getPsiByCurrentPos(psiElement, "method") ?: return) as ZephirMethodDefinition
40 | val classBody = (getPsiByCurrentPos(psiElement, "class") ?: return) as ZephirClassBody
41 | getPsiByCurrentPos(psiElement, "method_body") ?: return
42 |
43 | processMethodArguments(methodDefinition, result)
44 | processClassMembers(classBody, result)
45 | processClassConstants(classBody, result)
46 | processClassMethods(classBody, result)
47 |
48 | // process keywords
49 | for (keyword in keywords) {
50 | result.addElement(LookupElementBuilder.create(keyword))
51 | }
52 |
53 | // process type hints
54 | for (typeHint in typeHints) {
55 | result.addElement(LookupElementBuilder.create(typeHint))
56 | }
57 | }
58 |
59 | private fun processMethodArguments(methodDefinition: ZephirMethodDefinition, result: CompletionResultSet) {
60 | val methodArgs = LinkedList()
61 | for (args in methodDefinition.argumentsList) {
62 | methodArgs.addAll(args.argumentList)
63 | }
64 |
65 | for (arg in methodArgs) {
66 | val completionElement = arg.id?.text?.let {
67 | LookupElementBuilder
68 | .create(it, arg.id!!.text)
69 | .withTypeText(if (arg.type != null) arg.type!!.text else "", true)
70 | .withBoldness(true)
71 | .withLookupString(arg.id!!.text)
72 | .withTailText(
73 | if (arg.defaultValue != null) " " + arg.defaultValue!!.text else "",
74 | true
75 | )
76 | }
77 | result.addElement(
78 | PrioritizedLookupElement.withPriority(completionElement, ZephirCompletionPriority.METHOD_SCOPE_PRIORITY)
79 | )
80 | }
81 | }
82 |
83 | private fun processClassMembers(classBody: ZephirClassBody, result: CompletionResultSet) {
84 | for (propDef in classBody.propertyDefinitionList) {
85 | val completionElement = LookupElementBuilder
86 | .create(propDef.id.text, "this->" + propDef.id.text)
87 | .withTypeText(propDef.visibility.text, true)
88 | .withLookupString(propDef.id.text)
89 | .withTailText(
90 | if (propDef.defaultValue != null) " " + propDef.defaultValue!!.text else "",
91 | true
92 | )
93 |
94 | result.addElement(
95 | PrioritizedLookupElement.withPriority(
96 | completionElement,
97 | ZephirCompletionPriority.CLASS_PROPERTY_PRIORITY
98 | )
99 | )
100 | }
101 | }
102 |
103 | private fun processClassConstants(classBody: ZephirClassBody, result: CompletionResultSet) {
104 | for (constDef in classBody.constantDefinitionList) {
105 | val completionElement = LookupElementBuilder
106 | .create(constDef.id.text, "self::" + constDef.id.text)
107 | .withTypeText(constDef.defaultValue!!.text)
108 | .withLookupString(constDef.id.text)
109 |
110 | result.addElement(
111 | PrioritizedLookupElement.withPriority(completionElement, ZephirCompletionPriority.CLASS_CONSTS_PRIORITY)
112 | )
113 | }
114 | }
115 |
116 | private fun processClassMethods(classBody: ZephirClassBody, result: CompletionResultSet) {
117 | for (abstractDef in classBody.abstractMethodDefinitionList) {
118 | val interDef = abstractDef.interfaceMethodDefinition
119 |
120 | val completionElement = LookupElementBuilder
121 | .create(interDef.id.text, "this->" + interDef.id.text.toString() + "()")
122 | .withTypeText(if (interDef.returnType != null) interDef.returnType!!.text else "")
123 | .withLookupString(interDef.id.text)
124 |
125 | result.addElement(
126 | PrioritizedLookupElement.withPriority(completionElement, ZephirCompletionPriority.CLASS_METHOD_PRIORITY)
127 | )
128 | }
129 | }
130 |
131 | private fun getPsiByCurrentPos(psiElement: PsiElement, objectType: String): PsiElement? {
132 | var parent = psiElement.parent
133 |
134 | if (parent == null || parent is ZephirFile) {
135 | return null
136 | }
137 |
138 | var findLimitCounter = 0
139 |
140 | do {
141 | parent = parent.parent
142 | if (parent == null || parent is ZephirFile) {
143 | return null
144 | } else if (objectType == "method" && parent is ZephirMethodDefinition) {
145 | return parent
146 | } else if (objectType == "class" && parent is ZephirClassBody) {
147 | return parent
148 | } else if (objectType == "method_body" && parent is ZephirMethodBody) {
149 | return parent
150 | }
151 | ++findLimitCounter
152 | } while (findLimitCounter < MAX_SYNTAX_TREE_DEEP) // to avoid possible infinite cycles
153 |
154 | return null
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/main/grammar/Zephir.flex:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014-2020 Zephir Team
2 | //
3 | // This source file is subject the MIT license, that is bundled with
4 | // this package in the file LICENSE, and is available through the
5 | // world-wide-web at the following url:
6 | //
7 | // https://github.com/zephir-lang/idea-plugin/blob/master/LICENSE
8 |
9 | package com.zephir.lang.core.lexer;
10 |
11 | import com.intellij.lexer.FlexLexer;
12 | import com.intellij.psi.tree.IElementType;
13 | import com.intellij.psi.TokenType;
14 | import static com.zephir.lang.core.psi.ZephirTypes.*;
15 |
16 | %%
17 |
18 | %{
19 | public _ZephirLexer() {
20 | this((java.io.Reader)null);
21 | }
22 | %}
23 |
24 | %class _ZephirLexer
25 | %public
26 | %implements FlexLexer
27 | %unicode
28 | %function advance
29 | %type IElementType
30 | %eof{ return;
31 | %eof}
32 |
33 | //////////////////////////////////////////////////////////////////////////////////////////////////
34 | // Whitespaces
35 | //////////////////////////////////////////////////////////////////////////////////////////////////
36 |
37 | EOL = \n | \r | \r\n
38 | LINE_WS = [\ \t\f]
39 | WHITE_SPACE_CHAR = {EOL} | {LINE_WS}
40 | WHITE_SPACE = {WHITE_SPACE_CHAR}+
41 |
42 | //////////////////////////////////////////////////////////////////////////////////////////////////
43 | // Comments
44 | //////////////////////////////////////////////////////////////////////////////////////////////////
45 |
46 | COMMENT = "//".*
47 | COMMENT_BLOCK = ("/*"([^*]+|[*]+[^/*])*[*]*"*/")
48 |
49 | ///////////////////////////////////////////////////////////////////////////////////////////////////
50 | // Literals
51 | ///////////////////////////////////////////////////////////////////////////////////////////////////
52 |
53 | INTEGER = ([\-]?[0-9]+)|([\-]?[0][x][0-9A-Fa-f]+)
54 | DOUBLE = ([\-]?[0-9]+[\.][0-9]+)
55 | HEX_DIGIT = [a-fA-F0-9]
56 |
57 | COMMON_ESCAPE = ( [.0\n\r\\] | "x" {HEX_DIGIT} {2} | "u" {HEX_DIGIT} {4} | "U" {HEX_DIGIT} {8} )
58 | CHAR_TYPES = [acefntxdAGbBpPrRdDhHsSvVwWzZ]
59 |
60 | SINGLE_QUOTE = \x27
61 | DOUBLE_QUOTE = \x22
62 |
63 | STRING_LITERAL = {DOUBLE_QUOTE} ( [^\"\\] | \\[^] )* {DOUBLE_QUOTE}
64 | CHAR_LITERAL = ( {SINGLE_QUOTE} ( [^'\\] | "\\" ( {SINGLE_QUOTE} | {COMMON_ESCAPE} | {CHAR_TYPES}) ) {SINGLE_QUOTE} )
65 | | ( {SINGLE_QUOTE} [^\x20-\x7E]{1,2} {SINGLE_QUOTE})
66 |
67 | IDENTIFIER = [_a-zA-Z][a-zA-Z0-9_]*
68 | CBLOCK = ("%{"([^}]+|[}]+[^%{])*"}%")
69 |
70 | %%
71 | {
72 | {WHITE_SPACE} { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }
73 |
74 | "namespace" { yybegin(YYINITIAL); return NAMESPACE; }
75 | "use" { yybegin(YYINITIAL); return USE; }
76 | "as" { yybegin(YYINITIAL); return AS; }
77 | "interface" { yybegin(YYINITIAL); return INTEFACE; }
78 | "class" { yybegin(YYINITIAL); return CLASS; }
79 | "function" { yybegin(YYINITIAL); return FUNCTION; }
80 | "fn" { yybegin(YYINITIAL); return FUNCTION; }
81 | "extends" { yybegin(YYINITIAL); return EXTENDS; }
82 | "implements" { yybegin(YYINITIAL); return IMPLEMENTS; }
83 | "abstract" { yybegin(YYINITIAL); return ABSTRACT; }
84 | "final" { yybegin(YYINITIAL); return FINAL; }
85 | "public" { yybegin(YYINITIAL); return PUBLIC; }
86 | "protected" { yybegin(YYINITIAL); return PROTECTED; }
87 | "private" { yybegin(YYINITIAL); return PRIVATE; }
88 | "static" { yybegin(YYINITIAL); return STATIC; }
89 | "inline" { yybegin(YYINITIAL); return INLINE; }
90 | "internal" { yybegin(YYINITIAL); return INTERNAL; }
91 | "deprecated" { yybegin(YYINITIAL); return DEPRECATED; }
92 | "var" { yybegin(YYINITIAL); return TYPE_VAR; }
93 | "void" { yybegin(YYINITIAL); return TYPE_VOID; }
94 | "int" { yybegin(YYINITIAL); return TYPE_INT; }
95 | "integer" { yybegin(YYINITIAL); return TYPE_INT; }
96 | "uint" { yybegin(YYINITIAL); return TYPE_UINT; }
97 | "long" { yybegin(YYINITIAL); return TYPE_LONG; }
98 | "ulong" { yybegin(YYINITIAL); return TYPE_ULONG; }
99 | "char" { yybegin(YYINITIAL); return TYPE_CHAR; }
100 | "uchar" { yybegin(YYINITIAL); return TYPE_UCHAR; }
101 | "double" { yybegin(YYINITIAL); return TYPE_DOUBLE; }
102 | "float" { yybegin(YYINITIAL); return TYPE_DOUBLE; }
103 | "bool" { yybegin(YYINITIAL); return TYPE_BOOL; }
104 | "boolean" { yybegin(YYINITIAL); return TYPE_BOOL; }
105 | "string" { yybegin(YYINITIAL); return TYPE_STRING; }
106 | "array" { yybegin(YYINITIAL); return TYPE_ARRAY; }
107 | "object" { yybegin(YYINITIAL); return TYPE_OBJECT; }
108 | "callable" { yybegin(YYINITIAL); return TYPE_CALLABLE; }
109 | "resource" { yybegin(YYINITIAL); return TYPE_RESOURCE; }
110 | "null" { yybegin(YYINITIAL); return NULL; }
111 | "false" { yybegin(YYINITIAL); return FALSE; }
112 | "true" { yybegin(YYINITIAL); return TRUE; }
113 | "let" { yybegin(YYINITIAL); return LET; }
114 | "echo" { yybegin(YYINITIAL); return ECHO; }
115 | "const" { yybegin(YYINITIAL); return CONST; }
116 | "if" { yybegin(YYINITIAL); return IF; }
117 | "else" { yybegin(YYINITIAL); return ELSE; }
118 | "elseif" { yybegin(YYINITIAL); return ELSEIF; }
119 | "switch" { yybegin(YYINITIAL); return SWITCH; }
120 | "case" { yybegin(YYINITIAL); return CASE; }
121 | "default" { yybegin(YYINITIAL); return DEFAULT; }
122 | "do" { yybegin(YYINITIAL); return DO; }
123 | "while" { yybegin(YYINITIAL); return WHILE; }
124 | "for" { yybegin(YYINITIAL); return FOR; }
125 | "loop" { yybegin(YYINITIAL); return LOOP; }
126 | "reverse" { yybegin(YYINITIAL); return REVERSE; }
127 | "break" { yybegin(YYINITIAL); return BREAK; }
128 | "continue" { yybegin(YYINITIAL); return CONTINUE; }
129 | "in" { yybegin(YYINITIAL); return IN; }
130 | "new" { yybegin(YYINITIAL); return NEW; }
131 | "return" { yybegin(YYINITIAL); return RETURN; }
132 | "require" { yybegin(YYINITIAL); return REQUIRE; }
133 | "clone" { yybegin(YYINITIAL); return CLONE; }
134 | "empty" { yybegin(YYINITIAL); return EMPTY; }
135 | "typeof" { yybegin(YYINITIAL); return TYPEOF; }
136 | "instanceof" { yybegin(YYINITIAL); return INSTANCEOF; }
137 | "likely" { yybegin(YYINITIAL); return LIKELY; }
138 | "unlikely" { yybegin(YYINITIAL); return UNLIKELY; }
139 | "isset" { yybegin(YYINITIAL); return ISSET; }
140 | "unset" { yybegin(YYINITIAL); return UNSET; }
141 | "throw" { yybegin(YYINITIAL); return THROW; }
142 | "fetch" { yybegin(YYINITIAL); return FETCH; }
143 | "try" { yybegin(YYINITIAL); return TRY; }
144 | "catch" { yybegin(YYINITIAL); return CATCH; }
145 | "(" { yybegin(YYINITIAL); return PARENTHESES_OPEN; }
146 | ")" { yybegin(YYINITIAL); return PARENTHESES_CLOSE; }
147 | "{" { yybegin(YYINITIAL); return BRACKET_OPEN; }
148 | "}" { yybegin(YYINITIAL); return BRACKET_CLOSE; }
149 | "[" { yybegin(YYINITIAL); return SBRACKET_OPEN; }
150 | "]" { yybegin(YYINITIAL); return SBRACKET_CLOSE; }
151 | "@" { yybegin(YYINITIAL); return AT; }
152 | "!" { yybegin(YYINITIAL); return NOT; }
153 | "&&" { yybegin(YYINITIAL); return AND; }
154 | "||" { yybegin(YYINITIAL); return OR; }
155 | "&" { yybegin(YYINITIAL); return BITWISE_AND; }
156 | "|" { yybegin(YYINITIAL); return BITWISE_OR; }
157 | "^" { yybegin(YYINITIAL); return BITWISE_XOR; }
158 | "<<" { yybegin(YYINITIAL); return BITWISE_SHIFTLEFT; }
159 | ">>" { yybegin(YYINITIAL); return BITWISE_SHIFTRIGHT; }
160 | "=" { yybegin(YYINITIAL); return ASSIGN; }
161 | "+=" { yybegin(YYINITIAL); return ADDASSIGN; }
162 | "-=" { yybegin(YYINITIAL); return SUBASSIGN; }
163 | "*=" { yybegin(YYINITIAL); return MULASSIGN; }
164 | "**=" { yybegin(YYINITIAL); return EXPASSIGN; }
165 | "/=" { yybegin(YYINITIAL); return DIVASSIGN; }
166 | "%=" { yybegin(YYINITIAL); return MODASSIGN; }
167 | ".=" { yybegin(YYINITIAL); return CONCATASSIGN; }
168 | "==" { yybegin(YYINITIAL); return EQUALS; }
169 | "!=" { yybegin(YYINITIAL); return NOTEQUALS; }
170 | "===" { yybegin(YYINITIAL); return IDENTICAL; }
171 | "!==" { yybegin(YYINITIAL); return NOTIDENTICAL; }
172 | "<=" { yybegin(YYINITIAL); return LESSEQUAL; }
173 | ">=" { yybegin(YYINITIAL); return GREATEREQUAL; }
174 | "<" { yybegin(YYINITIAL); return LESS; }
175 | ">" { yybegin(YYINITIAL); return GREATER; }
176 | "->" { yybegin(YYINITIAL); return ARROW; }
177 | "::" { yybegin(YYINITIAL); return DOUBLECOLON; }
178 | "." { yybegin(YYINITIAL); return DOT; }
179 | "+" { yybegin(YYINITIAL); return ADD; }
180 | "-" { yybegin(YYINITIAL); return SUB; }
181 | "*" { yybegin(YYINITIAL); return MUL; }
182 | "**" { yybegin(YYINITIAL); return EXP; }
183 | "/" { yybegin(YYINITIAL); return DIV; }
184 | "%" { yybegin(YYINITIAL); return MOD; }
185 | "++" { yybegin(YYINITIAL); return INCR; }
186 | "--" { yybegin(YYINITIAL); return DECR; }
187 | ":" { yybegin(YYINITIAL); return COLON; }
188 | ";" { yybegin(YYINITIAL); return DOTCOMMA; }
189 | "," { yybegin(YYINITIAL); return COMMA; }
190 | "?" { yybegin(YYINITIAL); return QUESTION; }
191 |
192 | {COMMENT} { yybegin(YYINITIAL); return COMMENT; }
193 | {COMMENT_BLOCK} { yybegin(YYINITIAL); return COMMENT_BLOCK; }
194 | {IDENTIFIER} { yybegin(YYINITIAL); return IDENTIFIER; }
195 | {INTEGER} { yybegin(YYINITIAL); return INTEGER; }
196 | {DOUBLE} { yybegin(YYINITIAL); return DOUBLE; }
197 | {CHAR_LITERAL} { yybegin(YYINITIAL); return SCHAR; }
198 | {STRING_LITERAL} { yybegin(YYINITIAL); return STRING; }
199 | {CBLOCK} { yybegin(YYINITIAL); return CBLOCK; }
200 | }
201 |
202 | ///////////////////////////////////////////////////////////////////////////////////////////////////
203 | // Catch All
204 | ///////////////////////////////////////////////////////////////////////////////////////////////////
205 | [^] { return TokenType.BAD_CHARACTER; }
206 |
--------------------------------------------------------------------------------
/src/main/grammar/Zephir.bnf:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2014-2020 Zephir Team
2 | //
3 | // This source file is subject the MIT license, that is bundled with
4 | // this package in the file LICENSE, and is available through the
5 | // world-wide-web at the following url:
6 | //
7 | // https://github.com/zephir-lang/idea-plugin/blob/master/LICENSE
8 |
9 | {
10 | parserClass='com.zephir.lang.core.parser.ZephirParser'
11 | parserUtilClass='com.zephir.lang.core.parser.manual.ZephirManualParseRules'
12 |
13 | extends='com.intellij.extapi.psi.ASTWrapperPsiElement'
14 |
15 | psiClassPrefix='Zephir'
16 | psiImplClassSuffix='Impl'
17 | psiPackage='com.zephir.lang.core.psi'
18 | psiImplPackage='com.zephir.lang.core.psi.impl'
19 |
20 | elementTypeHolderClass='com.zephir.lang.core.psi.ZephirTypes'
21 | elementTypeClass='com.zephir.lang.core.psi.ZephirElementType'
22 | tokenTypeClass='com.zephir.lang.core.psi.ZephirTokenType'
23 | // TODO(serghei): Do we need this?
24 | // Also see: https://github.com/JetBrains/gradle-grammar-kit-plugin/issues/3
25 | psiImplUtilClass='com.zephir.lang.core.psi.impl.ZephirPsiImplUtil'
26 |
27 | tokens = [
28 | // regex
29 | COMMENT = 'regexp://.*'
30 | COMMENT_BLOCK = 'regexp:(/\*([^*]+|[*]+[^/*])*[*]*\*/)'
31 | IDENTIFIER = 'regexp:[_a-zA-Z][a-zA-Z0-9_]*'
32 | INTEGER = 'regexp:([\-]?[0-9]+)|([\-]?[0][x][0-9A-Fa-f]+)'
33 | DOUBLE = 'regexp:([\-]?[0-9]+[.][0-9]+)'
34 | SCHAR = "regexp:(['] ([^'\\]|\\.)* ['])"
35 | STRING = 'regexp:(["] ([^"\\]|\\.)* ["])'
36 | CBLOCK = 'regexp:%[{]([^}]+|[}]+[^%{])*[}]%'
37 |
38 | // OOP Keywords
39 | INTERNAL = 'internal'
40 | NAMESPACE = 'namespace'
41 | USE = 'use'
42 | AS = 'as'
43 | INTEFACE = 'interface'
44 | CLASS = 'class'
45 | FUNCTION = 'function'
46 | EXTENDS = 'extends'
47 | IMPLEMENTS = 'implements'
48 | ABSTRACT = 'abstract'
49 | FINAL = 'final'
50 | PUBLIC = 'public'
51 | PROTECTED = 'protected'
52 | PRIVATE = 'private'
53 | STATIC = 'static'
54 | INLINE = 'inline'
55 | DEPRECATED = 'deprecated'
56 |
57 | // Types
58 | TYPE_VAR = 'var'
59 | TYPE_VOID = 'void'
60 | TYPE_INT = 'int'
61 | TYPE_UINT = 'uint'
62 | TYPE_LONG = 'long'
63 | TYPE_ULONG = 'ulong'
64 | TYPE_CHAR = 'char'
65 | TYPE_UCHAR = 'uchar'
66 | TYPE_DOUBLE = 'double'
67 | TYPE_BOOL = 'bool'
68 | TYPE_STRING = 'string'
69 | TYPE_ARRAY = 'array'
70 | TYPE_OBJECT = 'object'
71 | TYPE_CALLABLE = 'callable'
72 | TYPE_RESOURCE = 'resource'
73 |
74 | // Value Keywords
75 | NULL = 'null'
76 | FALSE = 'false'
77 | TRUE = 'true'
78 |
79 | // Keywords
80 | LET = 'let'
81 | ECHO = 'echo'
82 | CONST = 'const'
83 | IF = 'if'
84 | ELSE = 'else'
85 | ELSEIF = 'elseif'
86 | SWITCH = 'switch'
87 | CASE = 'case'
88 | DEFAULT = 'default'
89 | DO = 'do'
90 | WHILE = 'while'
91 | FOR = 'for'
92 | LOOP = 'loop'
93 | REVERSE = 'reverse'
94 | BREAK = 'break'
95 | CONTINUE = 'continue'
96 | IN = 'in'
97 | NEW = 'new'
98 | RETURN = 'return'
99 | REQUIRE = 'require'
100 | CLONE = 'clone'
101 | EMPTY = 'empty'
102 | TYPEOF = 'typeof'
103 | INSTANCEOF = 'instanceof'
104 | LIKELY = 'likely'
105 | UNLIKELY = 'unlikely'
106 | ISSET = 'isset'
107 | UNSET = 'unset'
108 | THROW = 'throw'
109 | FETCH = 'fetch'
110 | TRY = 'try'
111 | CATCH = 'catch'
112 |
113 | // Other
114 | PARENTHESES_OPEN = '('
115 | PARENTHESES_CLOSE = ')'
116 | BRACKET_OPEN = '{'
117 | BRACKET_CLOSE = '}'
118 | SBRACKET_OPEN = '['
119 | SBRACKET_CLOSE = ']'
120 | AT = '@'
121 | NOT = '!'
122 | AND = '&&'
123 | OR = '||'
124 | BITWISE_AND = '&'
125 | BITWISE_OR = '|'
126 | BITWISE_XOR = '^'
127 | BITWISE_SHIFTLEFT = '<<'
128 | BITWISE_SHIFTRIGHT = '>>'
129 | ASSIGN = '='
130 | ADDASSIGN = '+='
131 | SUBASSIGN = '-='
132 | MULASSIGN = '*='
133 | EXPASSIGN = '**='
134 | DIVASSIGN = '/='
135 | MODASSIGN = '%='
136 | CONCATASSIGN = '.='
137 | EQUALS = '=='
138 | NOTEQUALS = '!='
139 | IDENTICAL = '==='
140 | NOTIDENTICAL = '!=='
141 | LESSEQUAL = '<='
142 | GREATEREQUAL = '>='
143 | LESS = '<'
144 | GREATER = '>'
145 | ARROW = '->'
146 | DOUBLECOLON = '::'
147 | DOT = '.'
148 | ADD = '+'
149 | SUB = '-'
150 | MUL = '*'
151 | EXP = '**'
152 | DIV = '/'
153 | MOD = '%'
154 | INCR = '++'
155 | DECR = '--'
156 | COLON = ':'
157 | DOTCOMMA = ';'
158 | COMMA = ','
159 | QUESTION = '?'
160 | ]
161 |
162 | extends(".*Expr") = Expr
163 | }
164 |
165 | // This is the grammar of the Zephir language which is used by Grammar Kit
166 | // to generate the parser and the PSI classes. Rule `FooBar` corresponds
167 | // to `ZephirFooBar` PSI class.
168 | //
169 | // Naming convention:
170 | //
171 | // * tokens are lowercase: for, if, identifier
172 | // * rules are PascalCase: TopStatement, ArrayAccess
173 | // * lexer rules are UPPER_CASE: TYPE_UINT, DOUBLECOLON
174 |
175 | File ::= TopStatement*
176 |
177 | CBlock ::= CBLOCK
178 |
179 | private TopStatement ::= NamespaceStatement ImportStatement* CBlock* (ClassDefinition | InterfaceDefinition)
180 |
181 | PhpReserved ::= '$resource' | '$namespace' | '$internal'
182 |
183 | NamespaceStatement ::= 'namespace' ComplexId ';' {pin=2}
184 |
185 | ImportStatement ::= 'use' ComplexId ('as' Id)? ';' {pin=2}
186 |
187 | ClassDefinition ::= ClassModifier? 'class' Id SuperClass? ImplementsList? ClassBody {pin=3}
188 |
189 | private ClassModifier ::= 'abstract' | 'final'
190 |
191 | SuperClass ::= 'extends' ComplexId {pin=1}
192 | ImplementsList ::= 'implements' ComplexIdList {pin=1}
193 | ClassBody ::= '{' ClassMember* '}' {pin=1}
194 |
195 | private ClassMember ::= ConstantDefinition |
196 | PropertyDefinition |
197 | MethodDefinition |
198 | AbstractMethodDefinition
199 |
200 | InterfaceDefinition ::= 'interface' Id SuperInterfaces? InterfaceBody {pin=2}
201 | SuperInterfaces ::= 'extends' ComplexIdList {pin=1}
202 | InterfaceBody ::= '{' InterfaceMember* '}' {pin=1}
203 |
204 | private InterfaceMember ::= ConstantDefinition |
205 | InterfaceMethodDefinition
206 |
207 | InterfaceMethodDefinition ::= MethodHeader '(' Arguments* ')' ReturnType? ';' {pin=2}
208 | AbstractMethodDefinition ::= 'abstract' InterfaceMethodDefinition
209 |
210 | ConstantDefinition ::= 'const' Id DefaultValue? ';' {pin=2}
211 |
212 | PropertyDefinition ::= 'static'? Visibility 'static'? Id DefaultValue? MemberMetaAccess? ';' {pin=4}
213 |
214 | private MemberMetaAccess ::= '{' MemberMetaModifier (',' MemberMetaModifier)* '}' {pin=1}
215 | private MemberMetaModifier ::= 'get' | 'set' | '__toString'
216 |
217 | MethodDefinition ::= MethodHeader '(' Arguments* ')' ReturnType? MethodBody {pin=2}
218 | MethodModifiers ::= 'static' | 'inline' | 'deprecated' | 'final'
219 | MethodBody ::= CodeBlock
220 |
221 | private MethodHeader ::= (Visibility | MethodModifiers)* FUNCTION Id
222 |
223 | CodeBlock ::= '{' Code* '}' {pin=1}
224 |
225 | ReturnType ::= '->' (Type | 'null') ('|' (Type | 'null'))* {pin(".*")=1}
226 |
227 | Arguments ::= Argument (',' Argument)* {pin(".*")=1}
228 | Argument ::= Type? '!'? (PhpReserved | Id) DefaultValue? {pin=3}
229 |
230 | DefaultValue ::= '=' Expr {pin=1}
231 | Visibility ::= 'public' | 'protected' | 'private'
232 |
233 | Id ::= '$'?IDENTIFIER
234 |
235 | ComplexId ::= '$'? '\'? Id ('\' Id)* {pin(".*")=3}
236 | ComplexIdList ::= ComplexId (',' ComplexId)* {pin(".*")=1}
237 |
238 | Type ::= VoidType | ScalarType | ClassType | ResourceType
239 | ScalarType ::= 'var' | NumberType | StringType | BoolType | 'array' | 'object' | 'callable' | 'resource'
240 |
241 | private StringType ::= 'string' | 'char' | 'uchar'
242 | private BoolType ::= 'bool' | 'boolean'
243 | private NumberType ::= IntType | DoubleType | 'uint' | 'long' | 'ulong'
244 | private IntType ::= 'int' | 'integer'
245 | private DoubleType ::= 'double' | 'float'
246 | private ClassType ::= '<' ComplexId ArrayAppendExpr? '>'
247 | private ResourceType ::= '<' '$'ComplexId ArrayAppendExpr? '>'
248 | private VoidType ::= 'void'
249 |
250 | Code ::= DeclarationStatement |
251 | LetStatement |
252 | CallStatement |
253 | ChainOfCallStatement |
254 | ControlStatement |
255 | LoopStatement |
256 | SwitchStatement |
257 | IfStatement |
258 | TryStatement |
259 | ReturnStatement |
260 | EchoStatement |
261 | ThrowStatement |
262 | RequireStatement |
263 | UnsetStatement |
264 | CBlock
265 |
266 | DeclarationStatement ::= Type DeclarationStatementElement (',' DeclarationStatementElement)* ';' {pin(".*")=1}
267 |
268 | private DeclarationStatementElement ::= (Id | PhpReserved) DefaultValue?
269 |
270 | LetStatement ::= 'let' ChangeVariableExpr (',' ChangeVariableExpr)* ';' {pin(".*")=1}
271 |
272 | ChangeVariableExpr ::= AssignmentExpr | IncrementExpr
273 | AssignmentExpr ::= (Typecast | Type)? (Variable | ExplodedVariable | PhpReserved) ArrayAppendExpr? AssignmentOperator (Typecast | Type)? (PhpReserved | Expr) { rightAssociative=true }
274 |
275 | private ArrayAppendExpr ::= '[' ']'
276 |
277 | AssignmentOperator ::= '=' | '+=' | '-=' | '*=' | '**=' | '/=' | '%=' | '.='
278 | Typecast ::= '(' ScalarType ')' | '<' ComplexId '>'
279 |
280 | IncrementExpr ::= Variable IncrementOperator {rightAssociative=true}
281 | IncrementOperator ::= '++' | '--'
282 |
283 | CallStatement ::= CallExpr ';'
284 |
285 | ControlStatement ::= ('continue' | 'break') ';'
286 |
287 | LoopStatement ::= InfinityLoopStatement |
288 | WhileLoopStatement |
289 | ForeachLoopStatement
290 |
291 | InfinityLoopStatement ::= 'loop' CodeBlock {pin=1}
292 |
293 | WhileLoopStatement ::= 'while' Expr CodeBlock {pin=2}
294 |
295 | ForeachLoopStatement ::= 'for' Id (',' Id)? 'in' 'reverse'? (PhpReserved | Expr) CodeBlock {pin=2}
296 | UnsetStatement ::= 'unset' (Variable | '(' Variable ')') ';'
297 |
298 | SwitchStatement ::= 'switch' Expr '{' CaseExpr* '}' {pin=1}
299 | StaticCallExpr ::= ((('{' Id '}') | 'static') '::') CallExpr {pin=1}
300 |
301 | CaseExpr ::= ('case' Expr | 'default') ':' Code* {pin=1}
302 |
303 | IfStatement ::= 'if' ('likely' | 'unlikely')? Expr CodeBlock ElseifStatements* ElseStatement? {pin=1}
304 | ElseifStatements ::= 'elseif' Expr CodeBlock {pin=1}
305 | ElseStatement ::= 'else' CodeBlock {pin=1}
306 |
307 | TryStatement ::= 'try' CodeBlock CatchBlock* {pin=1}
308 | CatchBlock ::= 'catch' ClassType? ComplexId (',' ComplexId)* CodeBlock {pin=3}
309 |
310 | ReturnStatement ::= 'return' (RequireStatement | (Typecast? Expr? ';'))
311 |
312 | EchoStatement ::= 'echo' Expr (',' Expr)* ';' {pin(".*")=1}
313 |
314 | ThrowStatement ::= 'throw' Expr ';' {pin=1}
315 | RequireStatement ::= RequireExpr ';' {pin=1}
316 |
317 | private RequireExpr ::= 'require' Expr
318 |
319 | Expr ::= UnaryExpr |
320 | BitExpr |
321 | BoolGroupExpr |
322 | MathExpr |
323 | PrimaryGroupExpr |
324 | SpecialGroupExpr
325 |
326 | private BoolGroupExpr ::= BoolExpr | TernaryExpr | EmptyExpr | IssetExpr | FetchExpr | InstanceofExpr
327 | private PrimaryGroupExpr ::= ChainOfCallExpr | StaticCallExpr | LiteralExpr | ParenExpr | PrecastExpr | CallbackExpr | CallExpr | CloneExpr
328 | private SpecialGroupExpr ::= NewExpr | TypeofExpr
329 |
330 | ChainOfCallStatement ::= ChainOfCallExpr ;
331 | ChainOfCallExpr ::= (ParenExpr '->') Expr
332 |
333 | BitExpr ::= Expr BitOperator Expr
334 | BitOperator ::= '&' | '|' | '^' | '>>' | '<<'
335 |
336 | MathExpr ::= Expr MathOperator Expr
337 | MathOperator ::= '+' | '-' | '*' | '**' | '/' | '%' | '.'
338 |
339 | UnaryExpr ::= ('+' | '-' | '!') Expr
340 | BoolExpr ::= Expr BoolOperator Expr
341 | BoolOperator ::= '&&' | '||' | '>' | '<' | '==' | '>=' | '<=' | '===' | '!=' | '!=='
342 |
343 | TernaryExpr ::= Expr '?' Expr ':' Expr {pin=1}
344 | LiteralExpr ::= Typecast? (Variable | scalar)
345 | ParenExpr ::= '(' Expr ')' {pin=1}
346 | PrecastExpr ::= '{' Expr '}' {pin=1}
347 |
348 | EmptyExpr ::= 'empty' Expr {pin=1}
349 | IssetExpr ::= 'isset' Expr {pin=1}
350 | FetchExpr ::= 'fetch' Id ',' Expr {pin=2}
351 | InstanceofExpr ::= Variable 'instanceof' Expr {pin=2}
352 |
353 | CallExpr ::= Expr '(' CallArguments? ')' ('->' Id '(' CallArguments? ')')* ArrayAccess? {pin=3}
354 | MagicCallExpr ::= '$'('clone' | 'fetch') '(' Arguments* ')'
355 | CallbackExpr ::= 'function' '(' Arguments* ')' CodeBlock {pin=1}
356 | CloneExpr ::= 'clone' Variable
357 |
358 | NewExpr ::= NewExprClassic | NewExprDynamic
359 |
360 | private NewExprClassic ::= 'new' ComplexId ('(' CallArguments? ')')? {pin=2}
361 | private NewExprDynamic ::= 'new' '{' Expr '}' ('(' CallArguments? ')')? {pin=2}
362 |
363 | TypeofExpr ::= 'typeof' Expr {pin=1}
364 |
365 | CallArguments ::= CallArgument (',' CallArgument)* {pin(".*")=1}
366 |
367 | private CallArgument ::= 'require'? Typecast? (PhpReserved | Expr)
368 | private ScalarShort ::= STRING | SCHAR | DOUBLE | INTEGER | ScalarValue
369 |
370 | scalar ::= ScalarShort | ArrayValue
371 | ScalarValue ::= 'null' | 'true' | 'false'
372 |
373 | ArrayValue ::= '[' ArrayBody? ']' {pin=1}
374 |
375 | private ArrayBody ::= ArrayItem (',' ArrayItem)* {pin(".*")=1}
376 |
377 | ArrayItem ::= ArrayKeyValue | Expr
378 | ArrayKeyValue ::= (ScalarShort | Expr) ':' Expr
379 |
380 | Variable ::= ComplexId (PropertyAccess | ArrayAppendExpr | ArrayAccess)*
381 | ExplodedVariable ::= '{' Variable '}'
382 |
383 | private PropertyAccess ::= ('::' | '->') (Variable | '{' (STRING | Id) '}' | MagicCallExpr) {pin=2}
384 | private ArrayAccess ::= '[' (Expr | PhpReserved) ']' {pin=1}
385 |
--------------------------------------------------------------------------------