From 0b345ff6329e783de6285a3934e6fa060354773a Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Sun, 4 Feb 2024 20:53:59 +0100 Subject: [PATCH 01/15] WIP --- Config/metadata.php | 19 +++++ Docs/A-languages.md | 1 + Language/Batch.php | 94 +++++++++++++++++++++++++ Tests/Expected/Test/batch/small.bat.tkn | 6 ++ Tests/Samples/batch/small.bat | 10 +++ 5 files changed, 130 insertions(+) create mode 100644 Language/Batch.php create mode 100644 Tests/Expected/Test/batch/small.bat.tkn create mode 100644 Tests/Samples/batch/small.bat diff --git a/Config/metadata.php b/Config/metadata.php index 7c05e4f..6c1121d 100644 --- a/Config/metadata.php +++ b/Config/metadata.php @@ -31,6 +31,25 @@ 'standalone' => true, 'injectable' => false, ], + [ + 'Kadet\\Highlighter\\Language\\Batch', + 'name' => [ + 'bat', + 'batch', + 'dos', + ], + 'mime' => [ + 'application/bat', + 'application/x-bat', + 'application/x-msdos-program', + ], + 'extension' => [ + '*.bat', + '*.cmd', + ], + 'standalone' => true, + 'injectable' => false, + ], [ 'Kadet\\Highlighter\\Language\\C', 'name' => [ diff --git a/Docs/A-languages.md b/Docs/A-languages.md index 92c56da..bb12630 100644 --- a/Docs/A-languages.md +++ b/Docs/A-languages.md @@ -38,6 +38,7 @@ Class | Name | MIME | Extension ------|------|------|---------- `Kadet\Highlighter\Language\Apache` | `apache` | none | `.htaccess` `Kadet\Highlighter\Language\Assembler` | `asm`, `assembler` | `text/x-asm` | `*.asm` +`Kadet\Highlighter\Language\Batch` | `bat`, `batch`, `dos` | `application/bat`, `application/x-bat`, `application/x-msdos-program` | `*.bat`, `*.cmd` `Kadet\Highlighter\Language\C` | `c` | `text/x-csrc`, `text/x-chdr` | `*.c`, `*.h`, `*.idc` `Kadet\Highlighter\Language\CSharp` | `CSharp`, `C#` | `text/x-csharp` | `*.cs` `Kadet\Highlighter\Language\Cobol` | `cobol` | `text/x-cobol` | `*.cbl` diff --git a/Language/Batch.php b/Language/Batch.php new file mode 100644 index 0000000..0853b62 --- /dev/null +++ b/Language/Batch.php @@ -0,0 +1,94 @@ + + * + * Contact with author: + * Xmpp: me@kadet.net + * E-mail: contact@kadet.net + * + * From Kadet with love. + */ + +namespace Kadet\Highlighter\Language; + +use Kadet\Highlighter\Matcher\RegexMatcher; +use Kadet\Highlighter\Matcher\WordMatcher; +use Kadet\Highlighter\Parser\Rule; +use Kadet\Highlighter\Parser\Token\LanguageToken; +use Kadet\Highlighter\Parser\Token\Token; +use Kadet\Highlighter\Parser\TokenFactory; +use Kadet\Highlighter\Parser\Validator\Validator; + +class Batch extends GreedyLanguage +{ + public function setupRules() + { + $this->rules->addMany([ +// 'comment' => new Rule(new RegexMatcher('/^[ ]*(rem[^\r\n\w]*)/mi')), + 'comment' => new Rule(new RegexMatcher('/^[ ]*(rem)( [ \w]*)?$/mi')), + 'string' => CommonFeatures::strings(['single' => '\'', 'double' => '"']), + + 'keyword' => new Rule(new WordMatcher([ + 'ASSOC', 'ATTRIB', 'BREAK', 'BCDEDIT', 'CACLS', 'CD', 'CHCP', 'CHDIR', 'CHKDSK', 'CHKNTFS', + 'CLS', 'CMD', 'COLOR', 'COMP', 'COMPACT', 'CONVERT', 'COPY', 'DATE', 'DEL', 'DIR', 'DISKCOMP', + 'DISKCOPY', 'DISKPART', 'DOSKEY', 'DRIVERQUERY', 'ECHO', 'ENDLOCAL', 'ERASE', 'EXIT', 'FC', + 'FIND', 'FINDSTR', 'FOR', 'FORMAT', 'FSUTIL', 'FTYPE', 'GPRESULT', 'GRAFTABL', 'HELP', 'ICACLS', + 'IF', 'LABEL', 'MD', 'MKDIR', 'MKLINK', 'MODE', 'MORE', 'MOVE', 'OPENFILES', 'PATH', 'PAUSE', + 'POPD', 'PRINT', 'PROMPT', 'PUSHD', 'RD', 'RECOVER', 'REN', 'RENAME', 'REPLACE', 'RMDIR', + 'ROBOCOPY', 'SET', 'SETLOCAL', 'SC', 'SCHTASKS', 'SHIFT', 'SHUTDOWN', 'SORT', 'START', + 'SUBST', 'SYSTEMINFO', 'TASKLIST', 'TASKKILL', 'TIME', 'TITLE', 'TREE', 'TYPE', 'VER', + 'VERIFY', 'VOL', 'XCOPY', 'WMIC', 'CSCRIPT', + 'echo', 'set', 'for', 'if', 'exit', 'else', 'do', 'not', 'defined', 'exist', + ]), ['priority' => 3]), + + 'variable' => [ + 'assign' => new Rule(new RegexMatcher('/(\w+)[+-]?=/')), + new Rule(new RegexMatcher('/(\$\w+)/i'), ['context' => ['*none', '*string.double']]), + 'special' => new Rule(new RegexMatcher('/(\$[#@_])/i'), ['context' => ['*none', '*string.double']]), + 'argument' => new Rule(new RegexMatcher('/(\$\d+)/i'), ['context' => ['*none', '*string.double']]), + new Rule(new RegexMatcher('/\$\{(\w+)(.*?)\}/i', [ 1 => Token::NAME, 2 => 'string' ]), ['context' => ['*none', '*string.double']]) + ], + + 'number' => new Rule(new RegexMatcher('/(-?(?:0[0-7]+|0[xX][0-9a-fA-F]+|0b[01]+|\d+))/')), + 'delimiter' => new Rule(new RegexMatcher('/^(\$)/m')), + + 'expression' => [ + new Rule(new RegexMatcher('/(?=(\$\(((?>[^$()]+|(?1))+)\)))/x'), [ + 'context' => Validator::everywhere(), + 'factory' => new TokenFactory(LanguageToken::class), + 'inject' => $this + ]), + ], + + 'operator.escape' => new Rule(new RegexMatcher('/(\\\(?:x[0-9a-fA-F]{1,2}|u\{[0-9a-fA-F]{1,6}\}|[0-7]{1,3}|.))/i'), [ + 'context' => ['*'] + ]), + ]); + } + + /** + * Unique language identifier, for example 'php' + * + * @return string + */ + public function getIdentifier() + { + return 'batch'; + } + + public static function getMetadata() + { + return [ + 'name' => ['bat', 'batch', 'dos'], + 'mime' => ['application/bat', 'application/x-bat', 'application/x-msdos-program'], + 'extension' => ['*.bat', '*.cmd'] + ]; + } +} diff --git a/Tests/Expected/Test/batch/small.bat.tkn b/Tests/Expected/Test/batch/small.bat.tkn new file mode 100644 index 0000000..f7f782d --- /dev/null +++ b/Tests/Expected/Test/batch/small.bat.tkn @@ -0,0 +1,6 @@ +{language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}@{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} off +{keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} /p {variable.assign:Kadet\Highlighter\Parser\Token\Token}imie{/variable.assign:Kadet\Highlighter\Parser\Token\Token}=Jak masz na imię? +rem To jest komentarz i nie ma wpływu na działanie programu +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Witaj, %imie%. +{keyword:Kadet\Highlighter\Parser\Token\Token}pause{/keyword:Kadet\Highlighter\Parser\Token\Token} +{/language.batch:Kadet\Highlighter\Parser\Token\LanguageToken} \ No newline at end of file diff --git a/Tests/Samples/batch/small.bat b/Tests/Samples/batch/small.bat new file mode 100644 index 0000000..6f9a002 --- /dev/null +++ b/Tests/Samples/batch/small.bat @@ -0,0 +1,10 @@ +@echo +set /p imie=Jak masz na imię? +rem To jest komentarz i nie ma wpływu na działanie programu +removeme To jest komentarz i nie ma wpływu na działanie programu +rem Żaden nie wie iże jożech psem +autoremove Żaden nie wie iże jożech psem +rem +remąt +echo Witaj, %imie%. +pause From fdd43e96d62a1acd99711c85c29e6c0e7469621e Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Mon, 5 Feb 2024 05:05:26 +0100 Subject: [PATCH 02/15] WIP 2 --- Language/Batch.php | 11 ++++++++--- Tests/Expected/Test/batch/small.bat.tkn | 11 ++++++++--- Tests/Samples/batch/small.bat | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Language/Batch.php b/Language/Batch.php index 0853b62..49837e8 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -31,10 +31,15 @@ class Batch extends GreedyLanguage public function setupRules() { $this->rules->addMany([ -// 'comment' => new Rule(new RegexMatcher('/^[ ]*(rem[^\r\n\w]*)/mi')), - 'comment' => new Rule(new RegexMatcher('/^[ ]*(rem)( [ \w]*)?$/mi')), + 'comment' => [ + new Rule(new RegexMatcher('/^\s*(rem)[\t\n\r]+/mi')), + new Rule(new RegexMatcher('/^\s*(rem\s+.+)/mi')), + ], + 'string' => CommonFeatures::strings(['single' => '\'', 'double' => '"']), + 'keyword.special' => new Rule(new RegexMatcher('/^\s*(@?echo(\s+(on|off))?)\b/mi'), ['priority' => 3]), + 'keyword' => new Rule(new WordMatcher([ 'ASSOC', 'ATTRIB', 'BREAK', 'BCDEDIT', 'CACLS', 'CD', 'CHCP', 'CHDIR', 'CHKDSK', 'CHKNTFS', 'CLS', 'CMD', 'COLOR', 'COMP', 'COMPACT', 'CONVERT', 'COPY', 'DATE', 'DEL', 'DIR', 'DISKCOMP', @@ -45,7 +50,7 @@ public function setupRules() 'ROBOCOPY', 'SET', 'SETLOCAL', 'SC', 'SCHTASKS', 'SHIFT', 'SHUTDOWN', 'SORT', 'START', 'SUBST', 'SYSTEMINFO', 'TASKLIST', 'TASKKILL', 'TIME', 'TITLE', 'TREE', 'TYPE', 'VER', 'VERIFY', 'VOL', 'XCOPY', 'WMIC', 'CSCRIPT', - 'echo', 'set', 'for', 'if', 'exit', 'else', 'do', 'not', 'defined', 'exist', + 'set', 'for', 'if', 'exit', 'else', 'do', 'not', 'defined', 'exist', ]), ['priority' => 3]), 'variable' => [ diff --git a/Tests/Expected/Test/batch/small.bat.tkn b/Tests/Expected/Test/batch/small.bat.tkn index f7f782d..38b6a19 100644 --- a/Tests/Expected/Test/batch/small.bat.tkn +++ b/Tests/Expected/Test/batch/small.bat.tkn @@ -1,6 +1,11 @@ -{language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}@{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} off +{language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}{keyword.special:Kadet\Highlighter\Parser\Token\Token}@echo off{/keyword.special:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} /p {variable.assign:Kadet\Highlighter\Parser\Token\Token}imie{/variable.assign:Kadet\Highlighter\Parser\Token\Token}=Jak masz na imię? -rem To jest komentarz i nie ma wpływu na działanie programu -{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Witaj, %imie%. +{comment:Kadet\Highlighter\Parser\Token\Token}rem To jest komentarz i nie ma wpływu na działanie programu{/comment:Kadet\Highlighter\Parser\Token\Token} +removeme To jest komentarz i nie ma wpływu na działanie programu +{comment:Kadet\Highlighter\Parser\Token\Token}rem Żaden nie wie iże jożech psem{/comment:Kadet\Highlighter\Parser\Token\Token} +autoremove Żaden nie wie iże jożech psem +{comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token} +remąt +{keyword.special:Kadet\Highlighter\Parser\Token\Token}echo{/keyword.special:Kadet\Highlighter\Parser\Token\Token} Witaj, %imie%. {keyword:Kadet\Highlighter\Parser\Token\Token}pause{/keyword:Kadet\Highlighter\Parser\Token\Token} {/language.batch:Kadet\Highlighter\Parser\Token\LanguageToken} \ No newline at end of file diff --git a/Tests/Samples/batch/small.bat b/Tests/Samples/batch/small.bat index 6f9a002..b981e60 100644 --- a/Tests/Samples/batch/small.bat +++ b/Tests/Samples/batch/small.bat @@ -1,4 +1,4 @@ -@echo +@echo off set /p imie=Jak masz na imię? rem To jest komentarz i nie ma wpływu na działanie programu removeme To jest komentarz i nie ma wpływu na działanie programu From 02db28e6dee0460fa80982aaa07351e33e02ec69 Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Mon, 5 Feb 2024 05:08:54 +0100 Subject: [PATCH 03/15] WIP 2.2 --- Language/Batch.php | 4 ++-- Tests/Expected/Test/batch/small.bat.tkn | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Language/Batch.php b/Language/Batch.php index 49837e8..c2b90b4 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -38,7 +38,7 @@ public function setupRules() 'string' => CommonFeatures::strings(['single' => '\'', 'double' => '"']), - 'keyword.special' => new Rule(new RegexMatcher('/^\s*(@?echo(\s+(on|off))?)\b/mi'), ['priority' => 3]), + 'keyword.special' => new Rule(new RegexMatcher('/^\s*(@?echo(\s+(on|off))?)\b/mi'), ['priority' => 2]), 'keyword' => new Rule(new WordMatcher([ 'ASSOC', 'ATTRIB', 'BREAK', 'BCDEDIT', 'CACLS', 'CD', 'CHCP', 'CHDIR', 'CHKDSK', 'CHKNTFS', @@ -50,7 +50,7 @@ public function setupRules() 'ROBOCOPY', 'SET', 'SETLOCAL', 'SC', 'SCHTASKS', 'SHIFT', 'SHUTDOWN', 'SORT', 'START', 'SUBST', 'SYSTEMINFO', 'TASKLIST', 'TASKKILL', 'TIME', 'TITLE', 'TREE', 'TYPE', 'VER', 'VERIFY', 'VOL', 'XCOPY', 'WMIC', 'CSCRIPT', - 'set', 'for', 'if', 'exit', 'else', 'do', 'not', 'defined', 'exist', + 'echo', 'set', 'for', 'if', 'exit', 'else', 'do', 'not', 'defined', 'exist', ]), ['priority' => 3]), 'variable' => [ diff --git a/Tests/Expected/Test/batch/small.bat.tkn b/Tests/Expected/Test/batch/small.bat.tkn index 38b6a19..3eb140f 100644 --- a/Tests/Expected/Test/batch/small.bat.tkn +++ b/Tests/Expected/Test/batch/small.bat.tkn @@ -6,6 +6,6 @@ removeme To jest komentarz i nie ma wpływu na działanie programu autoremove Żaden nie wie iże jożech psem {comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token} remąt -{keyword.special:Kadet\Highlighter\Parser\Token\Token}echo{/keyword.special:Kadet\Highlighter\Parser\Token\Token} Witaj, %imie%. +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Witaj, %imie%. {keyword:Kadet\Highlighter\Parser\Token\Token}pause{/keyword:Kadet\Highlighter\Parser\Token\Token} {/language.batch:Kadet\Highlighter\Parser\Token\LanguageToken} \ No newline at end of file From 9098611bb3a6bee749cd1954b3e7f422015ee500 Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Mon, 5 Feb 2024 05:20:30 +0100 Subject: [PATCH 04/15] Update batch sample --- Tests/Expected/Test/batch/small.bat.tkn | 13 ++++++++----- Tests/Samples/batch/small.bat | 13 ++++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Tests/Expected/Test/batch/small.bat.tkn b/Tests/Expected/Test/batch/small.bat.tkn index 3eb140f..1aa46c2 100644 --- a/Tests/Expected/Test/batch/small.bat.tkn +++ b/Tests/Expected/Test/batch/small.bat.tkn @@ -1,11 +1,14 @@ {language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}{keyword.special:Kadet\Highlighter\Parser\Token\Token}@echo off{/keyword.special:Kadet\Highlighter\Parser\Token\Token} -{keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} /p {variable.assign:Kadet\Highlighter\Parser\Token\Token}imie{/variable.assign:Kadet\Highlighter\Parser\Token\Token}=Jak masz na imię? + +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Wartość dwóch parametrów przekazanych {keyword:Kadet\Highlighter\Parser\Token\Token}do{/keyword:Kadet\Highlighter\Parser\Token\Token} skryptu +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} %{number:Kadet\Highlighter\Parser\Token\Token}1{/number:Kadet\Highlighter\Parser\Token\Token} +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} %{number:Kadet\Highlighter\Parser\Token\Token}2{/number:Kadet\Highlighter\Parser\Token\Token} + {comment:Kadet\Highlighter\Parser\Token\Token}rem To jest komentarz i nie ma wpływu na działanie programu{/comment:Kadet\Highlighter\Parser\Token\Token} -removeme To jest komentarz i nie ma wpływu na działanie programu -{comment:Kadet\Highlighter\Parser\Token\Token}rem Żaden nie wie iże jożech psem{/comment:Kadet\Highlighter\Parser\Token\Token} -autoremove Żaden nie wie iże jożech psem {comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token} -remąt +{keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} /p {variable.assign:Kadet\Highlighter\Parser\Token\Token}imie{/variable.assign:Kadet\Highlighter\Parser\Token\Token}=Jak masz na imię? + +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Witaj, %imie%. {keyword:Kadet\Highlighter\Parser\Token\Token}pause{/keyword:Kadet\Highlighter\Parser\Token\Token} {/language.batch:Kadet\Highlighter\Parser\Token\LanguageToken} \ No newline at end of file diff --git a/Tests/Samples/batch/small.bat b/Tests/Samples/batch/small.bat index b981e60..d14e89f 100644 --- a/Tests/Samples/batch/small.bat +++ b/Tests/Samples/batch/small.bat @@ -1,10 +1,13 @@ @echo off -set /p imie=Jak masz na imię? + +echo Wartość dwóch parametrów przekazanych do skryptu +echo %1 +echo %2 + rem To jest komentarz i nie ma wpływu na działanie programu -removeme To jest komentarz i nie ma wpływu na działanie programu -rem Żaden nie wie iże jożech psem -autoremove Żaden nie wie iże jożech psem rem -remąt +set /p imie=Jak masz na imię? + +echo echo Witaj, %imie%. pause From 2380e0919abfa78e1bcc69c075447ff59bd21573 Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Mon, 5 Feb 2024 05:25:05 +0100 Subject: [PATCH 05/15] Variables --- Language/Batch.php | 7 ++----- Tests/Expected/Test/batch/small.bat.tkn | 6 +++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Language/Batch.php b/Language/Batch.php index c2b90b4..4f408c2 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -22,7 +22,6 @@ use Kadet\Highlighter\Matcher\WordMatcher; use Kadet\Highlighter\Parser\Rule; use Kadet\Highlighter\Parser\Token\LanguageToken; -use Kadet\Highlighter\Parser\Token\Token; use Kadet\Highlighter\Parser\TokenFactory; use Kadet\Highlighter\Parser\Validator\Validator; @@ -55,10 +54,8 @@ public function setupRules() 'variable' => [ 'assign' => new Rule(new RegexMatcher('/(\w+)[+-]?=/')), - new Rule(new RegexMatcher('/(\$\w+)/i'), ['context' => ['*none', '*string.double']]), - 'special' => new Rule(new RegexMatcher('/(\$[#@_])/i'), ['context' => ['*none', '*string.double']]), - 'argument' => new Rule(new RegexMatcher('/(\$\d+)/i'), ['context' => ['*none', '*string.double']]), - new Rule(new RegexMatcher('/\$\{(\w+)(.*?)\}/i', [ 1 => Token::NAME, 2 => 'string' ]), ['context' => ['*none', '*string.double']]) + new Rule(new RegexMatcher('/(%\w+%)/i'), ['context' => ['*none', '*string.double']]), + new Rule(new RegexMatcher('/(%\w+)/i'), ['context' => ['*none', '*string.double']]), ], 'number' => new Rule(new RegexMatcher('/(-?(?:0[0-7]+|0[xX][0-9a-fA-F]+|0b[01]+|\d+))/')), diff --git a/Tests/Expected/Test/batch/small.bat.tkn b/Tests/Expected/Test/batch/small.bat.tkn index 1aa46c2..07b0071 100644 --- a/Tests/Expected/Test/batch/small.bat.tkn +++ b/Tests/Expected/Test/batch/small.bat.tkn @@ -1,14 +1,14 @@ {language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}{keyword.special:Kadet\Highlighter\Parser\Token\Token}@echo off{/keyword.special:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Wartość dwóch parametrów przekazanych {keyword:Kadet\Highlighter\Parser\Token\Token}do{/keyword:Kadet\Highlighter\Parser\Token\Token} skryptu -{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} %{number:Kadet\Highlighter\Parser\Token\Token}1{/number:Kadet\Highlighter\Parser\Token\Token} -{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} %{number:Kadet\Highlighter\Parser\Token\Token}2{/number:Kadet\Highlighter\Parser\Token\Token} +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%1{/variable:Kadet\Highlighter\Parser\Token\Token} +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%2{/variable:Kadet\Highlighter\Parser\Token\Token} {comment:Kadet\Highlighter\Parser\Token\Token}rem To jest komentarz i nie ma wpływu na działanie programu{/comment:Kadet\Highlighter\Parser\Token\Token} {comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} /p {variable.assign:Kadet\Highlighter\Parser\Token\Token}imie{/variable.assign:Kadet\Highlighter\Parser\Token\Token}=Jak masz na imię? {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} -{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Witaj, %imie%. +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Witaj, {variable:Kadet\Highlighter\Parser\Token\Token}%imie%{/variable:Kadet\Highlighter\Parser\Token\Token}. {keyword:Kadet\Highlighter\Parser\Token\Token}pause{/keyword:Kadet\Highlighter\Parser\Token\Token} {/language.batch:Kadet\Highlighter\Parser\Token\LanguageToken} \ No newline at end of file From 23faad5ba2bd75c6475f6fb0725a7d2d94ee101b Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Mon, 5 Feb 2024 05:25:57 +0100 Subject: [PATCH 06/15] No explicit strings in batch files --- Language/Batch.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Language/Batch.php b/Language/Batch.php index 4f408c2..f4b2bd1 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -35,8 +35,6 @@ public function setupRules() new Rule(new RegexMatcher('/^\s*(rem\s+.+)/mi')), ], - 'string' => CommonFeatures::strings(['single' => '\'', 'double' => '"']), - 'keyword.special' => new Rule(new RegexMatcher('/^\s*(@?echo(\s+(on|off))?)\b/mi'), ['priority' => 2]), 'keyword' => new Rule(new WordMatcher([ @@ -54,8 +52,8 @@ public function setupRules() 'variable' => [ 'assign' => new Rule(new RegexMatcher('/(\w+)[+-]?=/')), - new Rule(new RegexMatcher('/(%\w+%)/i'), ['context' => ['*none', '*string.double']]), - new Rule(new RegexMatcher('/(%\w+)/i'), ['context' => ['*none', '*string.double']]), + new Rule(new RegexMatcher('/(%\w+%)/i'), ['context' => ['*none']]), + new Rule(new RegexMatcher('/(%\w+)/i'), ['context' => ['*none']]), ], 'number' => new Rule(new RegexMatcher('/(-?(?:0[0-7]+|0[xX][0-9a-fA-F]+|0b[01]+|\d+))/')), From 37cc4e8149d95acb93ff112af73ebceac84683e9 Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Mon, 5 Feb 2024 06:00:09 +0100 Subject: [PATCH 07/15] Alternative comments --- Language/Batch.php | 2 ++ Tests/Expected/Test/batch/small.bat.tkn | 1 + Tests/Samples/batch/small.bat | 1 + 3 files changed, 4 insertions(+) diff --git a/Language/Batch.php b/Language/Batch.php index f4b2bd1..74aea08 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -18,6 +18,7 @@ namespace Kadet\Highlighter\Language; +use Kadet\Highlighter\Matcher\CommentMatcher; use Kadet\Highlighter\Matcher\RegexMatcher; use Kadet\Highlighter\Matcher\WordMatcher; use Kadet\Highlighter\Parser\Rule; @@ -33,6 +34,7 @@ public function setupRules() 'comment' => [ new Rule(new RegexMatcher('/^\s*(rem)[\t\n\r]+/mi')), new Rule(new RegexMatcher('/^\s*(rem\s+.+)/mi')), + new Rule(new CommentMatcher(['::'])), ], 'keyword.special' => new Rule(new RegexMatcher('/^\s*(@?echo(\s+(on|off))?)\b/mi'), ['priority' => 2]), diff --git a/Tests/Expected/Test/batch/small.bat.tkn b/Tests/Expected/Test/batch/small.bat.tkn index 07b0071..02db972 100644 --- a/Tests/Expected/Test/batch/small.bat.tkn +++ b/Tests/Expected/Test/batch/small.bat.tkn @@ -9,6 +9,7 @@ {keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} /p {variable.assign:Kadet\Highlighter\Parser\Token\Token}imie{/variable.assign:Kadet\Highlighter\Parser\Token\Token}=Jak masz na imię? {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} +{comment:Kadet\Highlighter\Parser\Token\Token}:: Wyświetl odpowiedź użytkownika{/comment:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Witaj, {variable:Kadet\Highlighter\Parser\Token\Token}%imie%{/variable:Kadet\Highlighter\Parser\Token\Token}. {keyword:Kadet\Highlighter\Parser\Token\Token}pause{/keyword:Kadet\Highlighter\Parser\Token\Token} {/language.batch:Kadet\Highlighter\Parser\Token\LanguageToken} \ No newline at end of file diff --git a/Tests/Samples/batch/small.bat b/Tests/Samples/batch/small.bat index d14e89f..dc45d41 100644 --- a/Tests/Samples/batch/small.bat +++ b/Tests/Samples/batch/small.bat @@ -9,5 +9,6 @@ rem set /p imie=Jak masz na imię? echo +:: Wyświetl odpowiedź użytkownika echo Witaj, %imie%. pause From 6fe693283e782871c5ce777d5c6312b36ac4181f Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Mon, 5 Feb 2024 06:08:35 +0100 Subject: [PATCH 08/15] Parameters --- Language/Batch.php | 5 +++++ Tests/Expected/Test/batch/small.bat.tkn | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Language/Batch.php b/Language/Batch.php index 74aea08..6f14386 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -61,6 +61,11 @@ public function setupRules() 'number' => new Rule(new RegexMatcher('/(-?(?:0[0-7]+|0[xX][0-9a-fA-F]+|0b[01]+|\d+))/')), 'delimiter' => new Rule(new RegexMatcher('/^(\$)/m')), + 'symbol.parameter' => new Rule(new RegexMatcher('/(\/[a-z])\b/i'), [ + 'priority' => 0, + 'context' => ['!comment'], + ]), + 'expression' => [ new Rule(new RegexMatcher('/(?=(\$\(((?>[^$()]+|(?1))+)\)))/x'), [ 'context' => Validator::everywhere(), diff --git a/Tests/Expected/Test/batch/small.bat.tkn b/Tests/Expected/Test/batch/small.bat.tkn index 02db972..1f70e75 100644 --- a/Tests/Expected/Test/batch/small.bat.tkn +++ b/Tests/Expected/Test/batch/small.bat.tkn @@ -6,7 +6,7 @@ {comment:Kadet\Highlighter\Parser\Token\Token}rem To jest komentarz i nie ma wpływu na działanie programu{/comment:Kadet\Highlighter\Parser\Token\Token} {comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token} -{keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} /p {variable.assign:Kadet\Highlighter\Parser\Token\Token}imie{/variable.assign:Kadet\Highlighter\Parser\Token\Token}=Jak masz na imię? +{keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} {symbol.parameter:Kadet\Highlighter\Parser\Token\Token}/p{/symbol.parameter:Kadet\Highlighter\Parser\Token\Token} {variable.assign:Kadet\Highlighter\Parser\Token\Token}imie{/variable.assign:Kadet\Highlighter\Parser\Token\Token}=Jak masz na imię? {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {comment:Kadet\Highlighter\Parser\Token\Token}:: Wyświetl odpowiedź użytkownika{/comment:Kadet\Highlighter\Parser\Token\Token} From c4ce90b3f8cc86a45ab30b7aa322ce80d5efe294 Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Mon, 5 Feb 2024 06:10:00 +0100 Subject: [PATCH 09/15] Move away from the keyword.special token --- Language/Batch.php | 29 +++++++++++++------------ Tests/Expected/Test/batch/small.bat.tkn | 2 +- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Language/Batch.php b/Language/Batch.php index 6f14386..c3dfa5c 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -37,20 +37,21 @@ public function setupRules() new Rule(new CommentMatcher(['::'])), ], - 'keyword.special' => new Rule(new RegexMatcher('/^\s*(@?echo(\s+(on|off))?)\b/mi'), ['priority' => 2]), - - 'keyword' => new Rule(new WordMatcher([ - 'ASSOC', 'ATTRIB', 'BREAK', 'BCDEDIT', 'CACLS', 'CD', 'CHCP', 'CHDIR', 'CHKDSK', 'CHKNTFS', - 'CLS', 'CMD', 'COLOR', 'COMP', 'COMPACT', 'CONVERT', 'COPY', 'DATE', 'DEL', 'DIR', 'DISKCOMP', - 'DISKCOPY', 'DISKPART', 'DOSKEY', 'DRIVERQUERY', 'ECHO', 'ENDLOCAL', 'ERASE', 'EXIT', 'FC', - 'FIND', 'FINDSTR', 'FOR', 'FORMAT', 'FSUTIL', 'FTYPE', 'GPRESULT', 'GRAFTABL', 'HELP', 'ICACLS', - 'IF', 'LABEL', 'MD', 'MKDIR', 'MKLINK', 'MODE', 'MORE', 'MOVE', 'OPENFILES', 'PATH', 'PAUSE', - 'POPD', 'PRINT', 'PROMPT', 'PUSHD', 'RD', 'RECOVER', 'REN', 'RENAME', 'REPLACE', 'RMDIR', - 'ROBOCOPY', 'SET', 'SETLOCAL', 'SC', 'SCHTASKS', 'SHIFT', 'SHUTDOWN', 'SORT', 'START', - 'SUBST', 'SYSTEMINFO', 'TASKLIST', 'TASKKILL', 'TIME', 'TITLE', 'TREE', 'TYPE', 'VER', - 'VERIFY', 'VOL', 'XCOPY', 'WMIC', 'CSCRIPT', - 'echo', 'set', 'for', 'if', 'exit', 'else', 'do', 'not', 'defined', 'exist', - ]), ['priority' => 3]), + 'keyword' => [ + new Rule(new RegexMatcher('/^\s*(@?echo(\s+(on|off))?)\b/mi'), ['priority' => 3]), + new Rule(new WordMatcher([ + 'ASSOC', 'ATTRIB', 'BREAK', 'BCDEDIT', 'CACLS', 'CD', 'CHCP', 'CHDIR', 'CHKDSK', 'CHKNTFS', + 'CLS', 'CMD', 'COLOR', 'COMP', 'COMPACT', 'CONVERT', 'COPY', 'DATE', 'DEL', 'DIR', 'DISKCOMP', + 'DISKCOPY', 'DISKPART', 'DOSKEY', 'DRIVERQUERY', 'ECHO', 'ENDLOCAL', 'ERASE', 'EXIT', 'FC', + 'FIND', 'FINDSTR', 'FOR', 'FORMAT', 'FSUTIL', 'FTYPE', 'GPRESULT', 'GRAFTABL', 'HELP', 'ICACLS', + 'IF', 'LABEL', 'MD', 'MKDIR', 'MKLINK', 'MODE', 'MORE', 'MOVE', 'OPENFILES', 'PATH', 'PAUSE', + 'POPD', 'PRINT', 'PROMPT', 'PUSHD', 'RD', 'RECOVER', 'REN', 'RENAME', 'REPLACE', 'RMDIR', + 'ROBOCOPY', 'SET', 'SETLOCAL', 'SC', 'SCHTASKS', 'SHIFT', 'SHUTDOWN', 'SORT', 'START', + 'SUBST', 'SYSTEMINFO', 'TASKLIST', 'TASKKILL', 'TIME', 'TITLE', 'TREE', 'TYPE', 'VER', + 'VERIFY', 'VOL', 'XCOPY', 'WMIC', 'CSCRIPT', + 'echo', 'set', 'for', 'if', 'exit', 'else', 'do', 'not', 'defined', 'exist', + ]), ['priority' => 3]), + ], 'variable' => [ 'assign' => new Rule(new RegexMatcher('/(\w+)[+-]?=/')), diff --git a/Tests/Expected/Test/batch/small.bat.tkn b/Tests/Expected/Test/batch/small.bat.tkn index 1f70e75..9434f50 100644 --- a/Tests/Expected/Test/batch/small.bat.tkn +++ b/Tests/Expected/Test/batch/small.bat.tkn @@ -1,4 +1,4 @@ -{language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}{keyword.special:Kadet\Highlighter\Parser\Token\Token}@echo off{/keyword.special:Kadet\Highlighter\Parser\Token\Token} +{language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}{keyword:Kadet\Highlighter\Parser\Token\Token}@echo off{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Wartość dwóch parametrów przekazanych {keyword:Kadet\Highlighter\Parser\Token\Token}do{/keyword:Kadet\Highlighter\Parser\Token\Token} skryptu {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%1{/variable:Kadet\Highlighter\Parser\Token\Token} From 517abeda4faee19c732d3326f10532bd4f577823 Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Mon, 5 Feb 2024 07:30:00 +0100 Subject: [PATCH 10/15] Recognize strings implicitly after "echo" This stops us from improperly marking keywords inside strings --- Language/Batch.php | 6 ++++-- Tests/Expected/Test/batch/small.bat.tkn | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Language/Batch.php b/Language/Batch.php index c3dfa5c..6595105 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -37,6 +37,8 @@ public function setupRules() new Rule(new CommentMatcher(['::'])), ], + 'string' => new Rule(new RegexMatcher('/^\s*@?echo[ \t]+(.+)\s/mi'), ['priority' => 2]), + 'keyword' => [ new Rule(new RegexMatcher('/^\s*(@?echo(\s+(on|off))?)\b/mi'), ['priority' => 3]), new Rule(new WordMatcher([ @@ -55,8 +57,8 @@ public function setupRules() 'variable' => [ 'assign' => new Rule(new RegexMatcher('/(\w+)[+-]?=/')), - new Rule(new RegexMatcher('/(%\w+%)/i'), ['context' => ['*none']]), - new Rule(new RegexMatcher('/(%\w+)/i'), ['context' => ['*none']]), + new Rule(new RegexMatcher('/(%\w+%)/i'), ['context' => ['*none', '*string'], 'priority' => 4]), + new Rule(new RegexMatcher('/(%\w+)/i'), ['context' => ['*none', '*string'], 'priority' => 4]), ], 'number' => new Rule(new RegexMatcher('/(-?(?:0[0-7]+|0[xX][0-9a-fA-F]+|0b[01]+|\d+))/')), diff --git a/Tests/Expected/Test/batch/small.bat.tkn b/Tests/Expected/Test/batch/small.bat.tkn index 9434f50..0c6e316 100644 --- a/Tests/Expected/Test/batch/small.bat.tkn +++ b/Tests/Expected/Test/batch/small.bat.tkn @@ -1,6 +1,6 @@ {language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}{keyword:Kadet\Highlighter\Parser\Token\Token}@echo off{/keyword:Kadet\Highlighter\Parser\Token\Token} -{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Wartość dwóch parametrów przekazanych {keyword:Kadet\Highlighter\Parser\Token\Token}do{/keyword:Kadet\Highlighter\Parser\Token\Token} skryptu +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}Wartość dwóch parametrów przekazanych do skryptu{/string:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%1{/variable:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%2{/variable:Kadet\Highlighter\Parser\Token\Token} @@ -10,6 +10,6 @@ {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {comment:Kadet\Highlighter\Parser\Token\Token}:: Wyświetl odpowiedź użytkownika{/comment:Kadet\Highlighter\Parser\Token\Token} -{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} Witaj, {variable:Kadet\Highlighter\Parser\Token\Token}%imie%{/variable:Kadet\Highlighter\Parser\Token\Token}. +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}Witaj, {variable:Kadet\Highlighter\Parser\Token\Token}{variable:Kadet\Highlighter\Parser\Token\Token}%imie{/variable:Kadet\Highlighter\Parser\Token\Token}%{/variable:Kadet\Highlighter\Parser\Token\Token}.{/string:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}pause{/keyword:Kadet\Highlighter\Parser\Token\Token} {/language.batch:Kadet\Highlighter\Parser\Token\LanguageToken} \ No newline at end of file From b3bdfb45096b98d8e43195feddeb7e202446de05 Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Mon, 5 Feb 2024 07:32:27 +0100 Subject: [PATCH 11/15] Remove unused rules for Batch files --- Language/Batch.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/Language/Batch.php b/Language/Batch.php index 6595105..55498a3 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -22,9 +22,6 @@ use Kadet\Highlighter\Matcher\RegexMatcher; use Kadet\Highlighter\Matcher\WordMatcher; use Kadet\Highlighter\Parser\Rule; -use Kadet\Highlighter\Parser\Token\LanguageToken; -use Kadet\Highlighter\Parser\TokenFactory; -use Kadet\Highlighter\Parser\Validator\Validator; class Batch extends GreedyLanguage { @@ -68,18 +65,6 @@ public function setupRules() 'priority' => 0, 'context' => ['!comment'], ]), - - 'expression' => [ - new Rule(new RegexMatcher('/(?=(\$\(((?>[^$()]+|(?1))+)\)))/x'), [ - 'context' => Validator::everywhere(), - 'factory' => new TokenFactory(LanguageToken::class), - 'inject' => $this - ]), - ], - - 'operator.escape' => new Rule(new RegexMatcher('/(\\\(?:x[0-9a-fA-F]{1,2}|u\{[0-9a-fA-F]{1,6}\}|[0-7]{1,3}|.))/i'), [ - 'context' => ['*'] - ]), ]); } From ffc847744ebcd9f509a80e93d29af7f73f8cb5bf Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Sun, 11 Feb 2024 10:12:49 +0100 Subject: [PATCH 12/15] Add another batch sample file --- Tests/Expected/Test/batch/big.bat.tkn | 73 +++++++++++++++++++++++++++ Tests/Samples/batch/big.bat | 72 ++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 Tests/Expected/Test/batch/big.bat.tkn create mode 100644 Tests/Samples/batch/big.bat diff --git a/Tests/Expected/Test/batch/big.bat.tkn b/Tests/Expected/Test/batch/big.bat.tkn new file mode 100644 index 0000000..b8af572 --- /dev/null +++ b/Tests/Expected/Test/batch/big.bat.tkn @@ -0,0 +1,73 @@ +{language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}{keyword:Kadet\Highlighter\Parser\Token\Token}@echo off{/keyword:Kadet\Highlighter\Parser\Token\Token} +{comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token} +rem backbat.bat -- Backup batch files (Windows NT/{number:Kadet\Highlighter\Parser\Token\Token}2000{/number:Kadet\Highlighter\Parser\Token\Token} version) +{comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token} +rem usage: backbat backupdir +{comment:Kadet\Highlighter\Parser\Token\Token}rem where: backupdir is the directory to copy batch files{/comment:Kadet\Highlighter\Parser\Token\Token} +{comment:Kadet\Highlighter\Parser\Token\Token}rem all batch files in the current directory will{/comment:Kadet\Highlighter\Parser\Token\Token} +{comment:Kadet\Highlighter\Parser\Token\Token}rem be backed up{/comment:Kadet\Highlighter\Parser\Token\Token} +{comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token} + +rem Make sure that there is at least one argument + +{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} "{variable:Kadet\Highlighter\Parser\Token\Token}%1{/variable:Kadet\Highlighter\Parser\Token\Token}"=="" goto argsok + +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}usage: {variable:Kadet\Highlighter\Parser\Token\Token}%0{/variable:Kadet\Highlighter\Parser\Token\Token} backupdir{/string:Kadet\Highlighter\Parser\Token\Token} +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}where: backupdir is the directory to copy batch files{/string:Kadet\Highlighter\Parser\Token\Token} +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}all batch files in the current directory will{/string:Kadet\Highlighter\Parser\Token\Token} +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}be backed up{/string:Kadet\Highlighter\Parser\Token\Token} + +goto end + + +:argsok + + +{keyword:Kadet\Highlighter\Parser\Token\Token}setlocal{/keyword:Kadet\Highlighter\Parser\Token\Token} + + +{comment:Kadet\Highlighter\Parser\Token\Token}rem Save the backup directory{/comment:Kadet\Highlighter\Parser\Token\Token} + +{keyword:Kadet\Highlighter\Parser\Token\Token}set{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable.assign:Kadet\Highlighter\Parser\Token\Token}backupdir{/variable.assign:Kadet\Highlighter\Parser\Token\Token}={variable:Kadet\Highlighter\Parser\Token\Token}%1{/variable:Kadet\Highlighter\Parser\Token\Token} + + +{comment:Kadet\Highlighter\Parser\Token\Token}rem Check to make sure that the backupdir exists and isn't a file{/comment:Kadet\Highlighter\Parser\Token\Token} + +{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} goto notfile + +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} is a file +goto end + + +:notfile + +{comment:Kadet\Highlighter\Parser\Token\Token}rem If the directory does not exist, create it.{/comment:Kadet\Highlighter\Parser\Token\Token} + +{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token}\nul goto skipdir + +{keyword:Kadet\Highlighter\Parser\Token\Token}md{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} +{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} "{variable:Kadet\Highlighter\Parser\Token\Token}%errorlevel%{/variable:Kadet\Highlighter\Parser\Token\Token}"=="{number:Kadet\Highlighter\Parser\Token\Token}0{/number:Kadet\Highlighter\Parser\Token\Token}" goto skipdir + +{keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}Error creating backup directory{/string:Kadet\Highlighter\Parser\Token\Token} +goto end + + +:skipdir + +{comment:Kadet\Highlighter\Parser\Token\Token}rem Copy each batch file one at a time.{/comment:Kadet\Highlighter\Parser\Token\Token} +{comment:Kadet\Highlighter\Parser\Token\Token}rem Note: the for loop variable (%%b) must be contain only one letter.{/comment:Kadet\Highlighter\Parser\Token\Token} + +{keyword:Kadet\Highlighter\Parser\Token\Token}for{/keyword:Kadet\Highlighter\Parser\Token\Token} %{variable:Kadet\Highlighter\Parser\Token\Token}%b{/variable:Kadet\Highlighter\Parser\Token\Token} in ( *.bat ) {keyword:Kadet\Highlighter\Parser\Token\Token}do{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}copy{/keyword:Kadet\Highlighter\Parser\Token\Token} %{variable:Kadet\Highlighter\Parser\Token\Token}%b{/variable:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} > nul + + +{comment:Kadet\Highlighter\Parser\Token\Token}rem Use the for loop again to check if each file was copied (since it is{/comment:Kadet\Highlighter\Parser\Token\Token} +{comment:Kadet\Highlighter\Parser\Token\Token}rem difficult to run multiple commands in a for loop).{/comment:Kadet\Highlighter\Parser\Token\Token} + +{keyword:Kadet\Highlighter\Parser\Token\Token}for{/keyword:Kadet\Highlighter\Parser\Token\Token} %{variable:Kadet\Highlighter\Parser\Token\Token}%b{/variable:Kadet\Highlighter\Parser\Token\Token} in ( *.bat ) {keyword:Kadet\Highlighter\Parser\Token\Token}do{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token}\%{variable:Kadet\Highlighter\Parser\Token\Token}%b{/variable:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} %{variable:Kadet\Highlighter\Parser\Token\Token}%b{/variable:Kadet\Highlighter\Parser\Token\Token} was {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} copied + +:end + +{comment:Kadet\Highlighter\Parser\Token\Token}rem Clean up{/comment:Kadet\Highlighter\Parser\Token\Token} + +{keyword:Kadet\Highlighter\Parser\Token\Token}endlocal{/keyword:Kadet\Highlighter\Parser\Token\Token} +{/language.batch:Kadet\Highlighter\Parser\Token\LanguageToken} \ No newline at end of file diff --git a/Tests/Samples/batch/big.bat b/Tests/Samples/batch/big.bat new file mode 100644 index 0000000..3e967db --- /dev/null +++ b/Tests/Samples/batch/big.bat @@ -0,0 +1,72 @@ +@echo off +rem +rem backbat.bat -- Backup batch files (Windows NT/2000 version) +rem +rem usage: backbat backupdir +rem where: backupdir is the directory to copy batch files +rem all batch files in the current directory will +rem be backed up +rem + +rem Make sure that there is at least one argument + +if not "%1"=="" goto argsok + +echo usage: %0 backupdir +echo where: backupdir is the directory to copy batch files +echo all batch files in the current directory will +echo be backed up + +goto end + + +:argsok + + +setlocal + + +rem Save the backup directory + +set backupdir=%1 + + +rem Check to make sure that the backupdir exists and isn't a file + +if not exist %backupdir% goto notfile + +echo %backupdir% is a file +goto end + + +:notfile + +rem If the directory does not exist, create it. + +if exist %backupdir%\nul goto skipdir + +md %backupdir% +if "%errorlevel%"=="0" goto skipdir + +echo Error creating backup directory +goto end + + +:skipdir + +rem Copy each batch file one at a time. +rem Note: the for loop variable (%%b) must be contain only one letter. + +for %%b in ( *.bat ) do copy %%b %backupdir% > nul + + +rem Use the for loop again to check if each file was copied (since it is +rem difficult to run multiple commands in a for loop). + +for %%b in ( *.bat ) do if not exist %backupdir%\%%b echo %%b was not copied + +:end + +rem Clean up + +endlocal From 7c7652b9b761c3ab49ed14c412f25f0574c458a7 Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Sun, 11 Feb 2024 10:15:57 +0100 Subject: [PATCH 13/15] Don't higlight numbers inside comments --- Language/Batch.php | 2 +- Tests/Expected/Test/batch/big.bat.tkn | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Language/Batch.php b/Language/Batch.php index 55498a3..c4c8e5d 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -58,7 +58,7 @@ public function setupRules() new Rule(new RegexMatcher('/(%\w+)/i'), ['context' => ['*none', '*string'], 'priority' => 4]), ], - 'number' => new Rule(new RegexMatcher('/(-?(?:0[0-7]+|0[xX][0-9a-fA-F]+|0b[01]+|\d+))/')), + 'number' => new Rule(new RegexMatcher('/(-?(?:0[0-7]+|0[xX][0-9a-fA-F]+|0b[01]+|\d+))/', ['context' => '!comment'])), 'delimiter' => new Rule(new RegexMatcher('/^(\$)/m')), 'symbol.parameter' => new Rule(new RegexMatcher('/(\/[a-z])\b/i'), [ diff --git a/Tests/Expected/Test/batch/big.bat.tkn b/Tests/Expected/Test/batch/big.bat.tkn index b8af572..abc982f 100644 --- a/Tests/Expected/Test/batch/big.bat.tkn +++ b/Tests/Expected/Test/batch/big.bat.tkn @@ -1,6 +1,6 @@ {language.batch:Kadet\Highlighter\Parser\Token\LanguageToken}{keyword:Kadet\Highlighter\Parser\Token\Token}@echo off{/keyword:Kadet\Highlighter\Parser\Token\Token} {comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token} -rem backbat.bat -- Backup batch files (Windows NT/{number:Kadet\Highlighter\Parser\Token\Token}2000{/number:Kadet\Highlighter\Parser\Token\Token} version) +rem backbat.bat -- Backup batch files (Windows NT/2000 version) {comment:Kadet\Highlighter\Parser\Token\Token}rem{/comment:Kadet\Highlighter\Parser\Token\Token} rem usage: backbat backupdir {comment:Kadet\Highlighter\Parser\Token\Token}rem where: backupdir is the directory to copy batch files{/comment:Kadet\Highlighter\Parser\Token\Token} @@ -46,7 +46,7 @@ goto end {keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token}\nul goto skipdir {keyword:Kadet\Highlighter\Parser\Token\Token}md{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} -{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} "{variable:Kadet\Highlighter\Parser\Token\Token}%errorlevel%{/variable:Kadet\Highlighter\Parser\Token\Token}"=="{number:Kadet\Highlighter\Parser\Token\Token}0{/number:Kadet\Highlighter\Parser\Token\Token}" goto skipdir +{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} "{variable:Kadet\Highlighter\Parser\Token\Token}%errorlevel%{/variable:Kadet\Highlighter\Parser\Token\Token}"=="0" goto skipdir {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}Error creating backup directory{/string:Kadet\Highlighter\Parser\Token\Token} goto end From fe9fcb35334e60bb8e26f45d16ef33cb5fce18df Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Sun, 11 Feb 2024 10:16:28 +0100 Subject: [PATCH 14/15] Drop unused "delimiter" rule I don't even know what that is xD but it was carried over from Shell and it's clearly unused so far. --- Language/Batch.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Language/Batch.php b/Language/Batch.php index c4c8e5d..badbe45 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -59,7 +59,6 @@ public function setupRules() ], 'number' => new Rule(new RegexMatcher('/(-?(?:0[0-7]+|0[xX][0-9a-fA-F]+|0b[01]+|\d+))/', ['context' => '!comment'])), - 'delimiter' => new Rule(new RegexMatcher('/^(\$)/m')), 'symbol.parameter' => new Rule(new RegexMatcher('/(\/[a-z])\b/i'), [ 'priority' => 0, From 07c9dd6e0b92e119a475ddcfd9c2eb38606b571f Mon Sep 17 00:00:00 2001 From: Maciej Sobaczewski Date: Sun, 11 Feb 2024 10:27:29 +0100 Subject: [PATCH 15/15] Batch: highlight "goto" keyword --- Language/Batch.php | 2 +- Tests/Expected/Test/batch/big.bat.tkn | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Language/Batch.php b/Language/Batch.php index badbe45..8f43d2c 100644 --- a/Language/Batch.php +++ b/Language/Batch.php @@ -48,7 +48,7 @@ public function setupRules() 'ROBOCOPY', 'SET', 'SETLOCAL', 'SC', 'SCHTASKS', 'SHIFT', 'SHUTDOWN', 'SORT', 'START', 'SUBST', 'SYSTEMINFO', 'TASKLIST', 'TASKKILL', 'TIME', 'TITLE', 'TREE', 'TYPE', 'VER', 'VERIFY', 'VOL', 'XCOPY', 'WMIC', 'CSCRIPT', - 'echo', 'set', 'for', 'if', 'exit', 'else', 'do', 'not', 'defined', 'exist', + 'echo', 'set', 'for', 'if', 'exit', 'else', 'do', 'not', 'defined', 'exist', 'goto', ]), ['priority' => 3]), ], diff --git a/Tests/Expected/Test/batch/big.bat.tkn b/Tests/Expected/Test/batch/big.bat.tkn index abc982f..7d5ab73 100644 --- a/Tests/Expected/Test/batch/big.bat.tkn +++ b/Tests/Expected/Test/batch/big.bat.tkn @@ -10,14 +10,14 @@ rem usage: backbat backupdir rem Make sure that there is at least one argument -{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} "{variable:Kadet\Highlighter\Parser\Token\Token}%1{/variable:Kadet\Highlighter\Parser\Token\Token}"=="" goto argsok +{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} "{variable:Kadet\Highlighter\Parser\Token\Token}%1{/variable:Kadet\Highlighter\Parser\Token\Token}"=="" {keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} argsok {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}usage: {variable:Kadet\Highlighter\Parser\Token\Token}%0{/variable:Kadet\Highlighter\Parser\Token\Token} backupdir{/string:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}where: backupdir is the directory to copy batch files{/string:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}all batch files in the current directory will{/string:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}be backed up{/string:Kadet\Highlighter\Parser\Token\Token} -goto end +{keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} end :argsok @@ -33,23 +33,23 @@ goto end {comment:Kadet\Highlighter\Parser\Token\Token}rem Check to make sure that the backupdir exists and isn't a file{/comment:Kadet\Highlighter\Parser\Token\Token} -{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} goto notfile +{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}not{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} notfile {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} is a file -goto end +{keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} end :notfile {comment:Kadet\Highlighter\Parser\Token\Token}rem If the directory does not exist, create it.{/comment:Kadet\Highlighter\Parser\Token\Token} -{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token}\nul goto skipdir +{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} {keyword:Kadet\Highlighter\Parser\Token\Token}exist{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token}\nul {keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} skipdir {keyword:Kadet\Highlighter\Parser\Token\Token}md{/keyword:Kadet\Highlighter\Parser\Token\Token} {variable:Kadet\Highlighter\Parser\Token\Token}%backupdir%{/variable:Kadet\Highlighter\Parser\Token\Token} -{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} "{variable:Kadet\Highlighter\Parser\Token\Token}%errorlevel%{/variable:Kadet\Highlighter\Parser\Token\Token}"=="0" goto skipdir +{keyword:Kadet\Highlighter\Parser\Token\Token}if{/keyword:Kadet\Highlighter\Parser\Token\Token} "{variable:Kadet\Highlighter\Parser\Token\Token}%errorlevel%{/variable:Kadet\Highlighter\Parser\Token\Token}"=="0" {keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} skipdir {keyword:Kadet\Highlighter\Parser\Token\Token}echo{/keyword:Kadet\Highlighter\Parser\Token\Token} {string:Kadet\Highlighter\Parser\Token\Token}Error creating backup directory{/string:Kadet\Highlighter\Parser\Token\Token} -goto end +{keyword:Kadet\Highlighter\Parser\Token\Token}goto{/keyword:Kadet\Highlighter\Parser\Token\Token} end :skipdir