├── .gitignore ├── .travis.yml ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── README.md ├── coffeelint.json ├── grammars ├── meta-info.cson ├── p6-regexp.cson └── perl6fe.cson ├── images ├── example1.png ├── example2.png ├── example3.png └── example_comments.png ├── lib └── main.js ├── lp6iym.p6 ├── package.json ├── settings └── language-perl6fe.cson └── spec └── grammar-perl6fe-spec.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | .tags 2 | node_modules 3 | tests 4 | .precomp 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | ### Project specific config ### 2 | language: generic 3 | 4 | env: 5 | global: 6 | - APM_TEST_PACKAGES="" 7 | - ATOM_LINT_WITH_BUNDLED_NODE="false" 8 | 9 | matrix: 10 | - ATOM_CHANNEL=stable 11 | - ATOM_CHANNEL=beta 12 | 13 | os: 14 | - linux 15 | - osx 16 | 17 | ### Generic setup follows ### 18 | script: 19 | - curl -s -O https://raw.githubusercontent.com/atom/ci/master/build-package.sh 20 | - chmod u+x build-package.sh 21 | - travis_retry ./build-package.sh 22 | 23 | notifications: 24 | email: 25 | on_success: never 26 | on_failure: change 27 | 28 | branches: 29 | only: 30 | - master 31 | - deprecate 32 | 33 | git: 34 | depth: 10 35 | 36 | sudo: false 37 | 38 | addons: 39 | apt: 40 | packages: 41 | - build-essential 42 | - git 43 | - libgnome-keyring-dev 44 | - fakeroot 45 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Issue Description 2 | 3 | > Describe what you see, what you want to see, and perhaps some linkage to docs, synopses, or irclog chatter. 4 | 5 | 6 | 7 | ### Example Code 8 | 9 | ```perl6 10 | # Please provide code so I can copy and paste it into Atom 11 | ``` 12 | 13 | ### Picture [optional] 14 | 15 | > Providing a picture means that if the issue is fixed and linguist updates to include the fix (linguist uses this package to highlight Perl 6 on GitHub), your issue will remain historically viewable. 16 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Jacob Russo 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------- 23 | 24 | This package was derived from a TextMate bundle located at 25 | https://github.com/textmate/perl.tmbundle and distributed under the following 26 | license, located in `README.mdown`: 27 | 28 | Permission to copy, use, modify, sell and distribute this 29 | software is granted. This software is provided "as is" without 30 | express or implied warranty, and with no claim as to its 31 | suitability for any purpose. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Atom Perl 6 Support - Forgotten Edition! 2 | 3 | [![apm package][apm-ver-link]][releases] 4 | [![][dl-badge]][apm-pkg-link] 5 | [![][mit-badge]][mit] 6 | 7 | This used to be my attempt at improving the Perl 6 highlighter over the builtin one for Atom. I have since lost almost all of my time for programming. Thankfully the Perl 6 community has taken it upon themselves to continue where I left off and make it an [official] project. **Please use the official [atom-language-perl6][official] highlighter going forward and not my own as this package is not maintained.** 8 | 9 | Derived from the builtin [language-perl](https://github.com/atom/language-perl) package but with many bugfixes and additions. You might ask why I didn't just add a PR there but I feel that this package adds quite a bit more that it might not be everyone's cup of tea. ~~However, I do plan on adding support for autocomplete+, linter, atom-build, and atom-runner. Maybe even integrating a perl6 REPL would be fun!~~ 10 | 11 | ![A screenshot of an funnified Perl 6 file](https://raw.githubusercontent.com/MadcapJake/language-perl6fe/master/images/example3.png) 12 | 13 | ## How do I use this? 14 | 15 | You have three options: 16 | 17 | 1. Click the language name in the status-bar (`Ctrl+Shift+L`) and select `Perl 6 FE` 18 | 2. Disable or uninstall the `language-perl` package 19 | 3. Add this to your `config.cson` (*Application: Open Your Config*): 20 | 21 | ```coffee 22 | '*': 23 | core: 24 | customFileTypes: 25 | 'source.perl6fe': [ 26 | # Any extensions you'd like to override 27 | 'p6' 28 | 'pm6' 29 | 't' 30 | ] 31 | ``` 32 | 33 | > Please be aware that if you do not include the `t` extension 34 | above, your `t` files will be highlighted with the `language-perl` highlighter (using either P5 or P6 grammar depending on if you have the `use v6;` pragma). 35 | 36 | ## What Makes This The Fun Edition™? 37 | 38 | > Perl 6 is *optimized for fun* -Audrey Tang 39 | 40 | * This package was developed to work with [Fira Code](https://github.com/tonsky/FiraCode) ligatures 41 | 42 | * More syntax highlighted (numbers, operators, interpolation, traits, better strings) 43 | 44 | * ~~This package will also soon contain support for many popular atom packages that have service hooks like autocomplete+ and linter~~ 45 | 46 | * ~~I'd like to add a builtin REPL eventually~~ 47 | 48 | Here's a few more examples: 49 | 50 | ![Another screenshot of a funnified Perl 6 file](https://raw.githubusercontent.com/MadcapJake/language-perl6fe/master/images/example1.png) 51 | 52 | ![Yet another screenshot of a funnified Perl 6 file](https://raw.githubusercontent.com/MadcapJake/language-perl6fe/master/images/example2.png) 53 | 54 | # License 55 | 56 | [MIT][mit] © [Jake Russo][author] et [al][contributors] 57 | 58 | 59 | [mit]: http://opensource.org/licenses/MIT 60 | [author]: http://github.com/MadcapJake 61 | [contributors]: https://github.com/MadcapJake/language-perl6fe/graphs/contributors 62 | [releases]: https://github.com/MadcapJake/language-perl6fe/releases 63 | [mit-badge]: https://img.shields.io/apm/l/language-perl6fe.svg 64 | [apm-pkg-link]: https://atom.io/packages/language-perl6fe 65 | [apm-ver-link]: https://img.shields.io/apm/v/language-perl6fe.svg 66 | [dl-badge]: http://img.shields.io/apm/dm/language-perl6fe.svg 67 | [official]: https://github.com/perl6/atom-language-perl6 68 | -------------------------------------------------------------------------------- /coffeelint.json: -------------------------------------------------------------------------------- 1 | { 2 | "max_line_length": { 3 | "level": "warn" 4 | }, 5 | "no_empty_param_list": { 6 | "level": "error" 7 | }, 8 | "arrow_spacing": { 9 | "level": "error" 10 | }, 11 | "no_interpolation_in_single_quotes": { 12 | "level": "error" 13 | }, 14 | "no_debugger": { 15 | "level": "error" 16 | }, 17 | "prefer_english_operator": { 18 | "level": "error" 19 | }, 20 | "colon_assignment_spacing": { 21 | "spacing": { 22 | "left": 0, 23 | "right": 1 24 | }, 25 | "level": "error" 26 | }, 27 | "braces_spacing": { 28 | "spaces": 0, 29 | "level": "error" 30 | }, 31 | "spacing_after_comma": { 32 | "level": "error" 33 | }, 34 | "no_stand_alone_at": { 35 | "level": "error" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /grammars/meta-info.cson: -------------------------------------------------------------------------------- 1 | 'scopeName': 'source.meta-info' 2 | 'name': 'META.info' 3 | 'fileTypes': [ 4 | 'META.info' 5 | 'META6.json' 6 | ] 7 | 'patterns': [ 8 | { 9 | 'include': '#value' 10 | } 11 | ] 12 | 'repository': 13 | array: 14 | 'begin': '\\[' 15 | 'beginCaptures': 16 | '0': 17 | 'name': 'punctuation.definition.array.begin.json' 18 | 'end': '\\]' 19 | 'endCaptures': 20 | '0': 21 | 'name': 'punctuation.definition.array.end.json' 22 | 'name': 'meta.structure.array.json' 23 | 'patterns': [ 24 | { 25 | 'include': '#value' 26 | } 27 | { 28 | 'match': ',' 29 | 'name': 'punctuation.separator.array.json' 30 | } 31 | { 32 | 'match': '[^\\s\\]]' 33 | 'name': 'invalid.illegal.expected-array-separator.json' 34 | } 35 | ] 36 | constant: 37 | 'match': '\\b(?:true|false|null)\\b' 38 | 'name': 'constant.language.json' 39 | number: 40 | 'comment': 'handles integer and decimal numbers' 41 | 'match': '-?(?=[1-9]|0(?!\\d))\\d+(\\.\\d+)?([eE][+-]?\\d+)?' 42 | 'name': 'constant.numeric.json' 43 | object: 44 | 'begin': '\\{' 45 | 'beginCaptures': 46 | '0': 47 | 'name': 'punctuation.definition.dictionary.begin.json' 48 | 'comment': 'a JSON object' 49 | 'end': '\\}' 50 | 'endCaptures': 51 | '0': 52 | 'name': 'punctuation.definition.dictionary.end.json' 53 | 'name': 'meta.structure.dictionary.json' 54 | 'patterns': [ 55 | { 56 | 'comment': 'special META.info keys' 57 | 'include': '#fields' 58 | } 59 | { 60 | 'comment': 'the JSON object key' 61 | 'include': '#string' 62 | } 63 | { 64 | 'begin': ':' 65 | 'beginCaptures': 66 | '0': 67 | 'name': 'punctuation.separator.dictionary.key-value.json' 68 | 'end': '(,)|(?=\\})' 69 | 'endCaptures': 70 | '1': 71 | 'name': 'punctuation.separator.dictionary.pair.json' 72 | 'name': 'meta.structure.dictionary.value.json' 73 | 'patterns': [ 74 | { 75 | 'comment': 'the JSON object value' 76 | 'include': '#value' 77 | } 78 | { 79 | 'match': '[^\\s,]' 80 | 'name': 'invalid.illegal.expected-dictionary-separator.json' 81 | } 82 | ] 83 | } 84 | { 85 | 'match': '[^\\s\\}]' 86 | 'name': 'invalid.illegal.expected-dictionary-separator.json' 87 | } 88 | ] 89 | fields: 90 | 'match': '(?x) 91 | "(?: 92 | perl|name|version|description|author(?:s)?|provides|depends|emulates| 93 | supersedes|superseded-by|excludes|build-depends|test-depends|resource| 94 | support|email|mailinglist|bugtracker|source|source-url|source-type| 95 | irc|phone|production|license|tags|auth 96 | )"' 97 | 'name': 'entity.name.function.field.meta-info' 98 | string: 99 | 'begin': '"' 100 | 'beginCaptures': 101 | '0': 102 | 'name': 'punctuation.definition.string.begin.json' 103 | 'end': '"' 104 | 'endCaptures': 105 | '0': 106 | 'name': 'punctuation.definition.string.end.json' 107 | 'name': 'string.quoted.double.json' 108 | 'patterns': [ 109 | { 110 | 'match': '(?x)\\\\(?:["\\\\/bfnrt]|u[0-9a-fA-F]{4})' 111 | 'name': 'constant.character.escape.json' 112 | } 113 | { 114 | 'match': '\\\\.' 115 | 'name': 'invalid.illegal.unrecognized-string-escape.json' 116 | } 117 | ] 118 | value: 119 | 'comment': 'the \'value\' diagram at http://json.org' 120 | 'patterns': [ 121 | { 122 | 'include': '#constant' 123 | } 124 | { 125 | 'include': '#number' 126 | } 127 | { 128 | 'include': '#string' 129 | } 130 | { 131 | 'include': '#array' 132 | } 133 | { 134 | 'include': '#object' 135 | } 136 | ] 137 | -------------------------------------------------------------------------------- /grammars/p6-regexp.cson: -------------------------------------------------------------------------------- 1 | 'scopeName': 'source.regexp.perl6fe' 2 | 'name': 'Regular Expressions (Perl 6)' 3 | 'fileTypes': [] 4 | 'patterns': [ 5 | 'include': '#regexp' 6 | ] 7 | 'repository': 8 | 'regexp': 9 | 'patterns': [ 10 | { 11 | 'begin': '(^[ \\t]+)?(?=#)' 12 | 'beginCaptures': 13 | '1': 14 | 'name': 'punctuation.whitespace.comment.leading.perl6fe' 15 | 'end': '(?!\\G)' 16 | 'patterns': [ 17 | { 18 | 'begin': '#' 19 | 'beginCaptures': 20 | '0': 21 | 'name': 'punctuation.definition.comment.perl6fe' 22 | 'end': '\\n' 23 | 'name': 'comment.line.number-sign.perl6fe' 24 | } 25 | ] 26 | } 27 | { 28 | 'include': '#re_strings' 29 | } 30 | { 31 | 'match': '\\\\[dDhHnNsStTvVwW]' 32 | 'name': 'constant.character.escape.class.regexp.perl6fe' 33 | } 34 | { 35 | 'match': ':\\w+' 36 | 'name': 'entity.name.section.adverb.perl6fe' 37 | } 38 | { 39 | 'match': '\\^\\^|(?>' 40 | 'name': 'entity.name.section.boundary.regexp.perl6fe' 41 | } 42 | { 43 | 'match': '(?)\\s*(=)' 48 | 'captures': 49 | '1': 50 | 'name': 'variable.other.identifier.sigil.regexp.perl6' 51 | '2': 52 | 'name': 'support.class.match.name.delimiter.regexp.perl6fe' 53 | '3': 54 | 'name': 'variable.other.identifier.regexp.perl6' 55 | '4': 56 | 'name': 'support.class.match.name.delimiter.regexp.perl6fe' 57 | '5': 58 | 'name': 'storage.modifier.match.assignment.regexp.perl6fe' 59 | 'name': 'meta.match.variable.perl6fe' 60 | } 61 | { 62 | 'begin': '(\\<(?:\\?|\\!)\\{)' 63 | 'beginCaptures': 64 | '1': 65 | 'name': 'punctuation.section.embedded.begin.perl6fe' 66 | 'end': '(\\}\\>)' 67 | 'endCaptures': 68 | '1': 69 | 'name': 'punctuation.section.embedded.end.perl6fe' 70 | 'patterns': [ 71 | 'include': 'source.perl6fe' 72 | ] 73 | 'name': 'meta.interpolation.perl6fe' 74 | } 75 | { 76 | 'begin': '(?!\\\\)<' 77 | 'beginCaptures': 78 | '0': 79 | 'name': 'punctuation.delimiter.property.regexp.perl6fe' 80 | 'end': '>' 81 | 'endCaptures': 82 | '0': 83 | 'name': 'punctuation.delimiter.property.regexp.perl6fe' 84 | 'name': 'meta.property.regexp.perl6fe' 85 | 'patterns': [ 86 | { 87 | 'include': '#re_strings' 88 | } 89 | { 90 | 'begin': '(\\?|\\!)(before|after)\\s+' 91 | 'beginCaptures': 92 | '1': 93 | 'name': 'keyword.operator.negativity.perl6fe' 94 | '2': 95 | 'name': 'entity.name.section.assertion.perl6fe' 96 | 'end': '(?=>)' 97 | 'name': 'meta.assertion.lookaround.perl6fe' 98 | 'patterns': [ 99 | { 100 | 'include': '#regexp' 101 | } 102 | ] 103 | } 104 | { 105 | 'match': '(\\w+)(=)' 106 | 'captures': 107 | '1': 108 | 'name': 'entity.name.function.capturename.perl6fe' 109 | '2': 110 | 'name': 'storage.modifier.capture.assignment.perl6fe' 111 | 'name': 'meta.capture.assignment.perl6fe' 112 | } 113 | { 114 | 'match': '(:)(\\w+)' 115 | 'captures': 116 | '1': 117 | 'name': 'punctuation.definition.property.regexp.perl6fe' 118 | '2': 119 | 'name': 'variable.other.identifier.property.regexp.perl6fe' 120 | 'name': 'meta.property.name.regexp.perl6fe' 121 | } 122 | { 123 | 'match': '[+|&\\-^]' 124 | 'name': 'keyword.operator.property.regexp.perl6fe' 125 | } 126 | { 127 | 'begin': '\\[' 128 | 'end': '\\]' 129 | 'contentName': 'constant.character.custom.property.regexp.perl6fe' 130 | 'patterns': [ 131 | { 132 | 'match': '(?)' 147 | 'end': '(?)' 148 | 'name': 'string.array.words.perl6fe' 149 | } 150 | { 151 | 'begin': '(^[ \\t]+)?(?=#)' 152 | 'beginCaptures': 153 | '1': 154 | 'name': 'punctuation.whitespace.comment.leading.perl6fe' 155 | 'end': '(?!\\G)' 156 | 'patterns': [ 157 | { 158 | 'begin': '#' 159 | 'beginCaptures': 160 | '0': 161 | 'name': 'punctuation.definition.comment.perl6fe' 162 | 'end': '\\n' 163 | 'name': 'comment.line.number-sign.perl6fe' 164 | } 165 | ] 166 | } 167 | { 168 | 'match': '(?x) 169 | \\x{2208}|\\(elem\\)|\\x{2209}|\\!\\(elem\\)| 170 | \\x{220B}|\\(cont\\)|\\x{220C}|\\!\\(cont\\)| 171 | \\x{2286}|\\(<=\\) |\\x{2288}|\\!\\(<=\\) | 172 | \\x{2282}|\\(<\\) |\\x{2284}|\\!\\(<\\) | 173 | \\x{2287}|\\(>=\\) |\\x{2289}|\\!\\(>=\\) | 174 | \\x{2283}|\\(>\\) |\\x{2285}|\\!\\(>\\) | 175 | \\x{227C}|\\(<\\+\\)|\\x{227D}|\\(>\\+\\) | 176 | \\x{222A}|\\(\\|\\) |\\x{2229}|\\(&\\) | 177 | \\x{2216}|\\(\\-\\) |\\x{2296}|\\(\\^\\) | 178 | \\x{228D}|\\(\\.\\) |\\x{228E}|\\(\\+\\)' 179 | 'name': 'keyword.operator.setbagmix.perl6fe' 180 | } 181 | { 182 | 'captures': 183 | '1': 184 | 'name': 'storage.type.class.perl6fe' 185 | '3': 186 | 'name': 'entity.name.type.class.perl6fe' 187 | 'match': '(?x) 188 | ( 189 | class|enum|grammar|knowhow|module| 190 | package|role|slang|subset|monitor|actor 191 | ) 192 | (\\s+) 193 | ( 194 | ( 195 | (?:::|\')? 196 | (?: 197 | ([a-zA-Z_\xc0-\xff\\$]) 198 | ([a-zA-Z0-9_\xc0-\xff\\$]|[\\-\'][a-zA-Z0-9_\xc0-\xff\\$])* 199 | ) 200 | )+ 201 | )' 202 | 'name': 'meta.class.perl6fe' 203 | } 204 | { 205 | 'include': '#p5_regex' 206 | } 207 | { 208 | 'begin': '(?x) 209 | (?<=^|[\\=,\\(\\[\\~]|when) \\s* 210 | (?:(m|rx)((?:(?>' 506 | 'endCaptures': 507 | '0': 508 | 'name': 'punctuation.definition.string.perl6fe' 509 | 'contentName': 'string.quoted.q.double.angle.perl6fe' 510 | 'patterns': [ 511 | { 512 | 'include': '#q_angle_string_content' 513 | } 514 | ] 515 | } 516 | { 517 | 'begin': '(?x) 518 | (q{1,2}(?:x|w|ww|v|s|a|h|f|c|b|p)?|Q(?:x|w|ww|v|s|a|h|f|c|b|p)?) 519 | ((?: 520 | \\s*:(?: 521 | x|exec|w|words|ww|quotewords|v|val|q|single|double| 522 | s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash| 523 | regexp|substr|trans|codes|p|path 524 | ) 525 | )*) 526 | \\s*(\\(\\()' 527 | 'beginCaptures': 528 | '1': 529 | 'name': 'string.quoted.q.operator.perl6fe' 530 | '2': 531 | 'name': 'support.function.quote.adverb.perl6fe' 532 | '3': 533 | 'name': 'punctuation.definition.string.perl6fe' 534 | 'end': '\\)\\)' 535 | 'endCaptures': 536 | '0': 537 | 'name': 'punctuation.definition.string.perl6fe' 538 | 'contentName': 'string.quoted.q.double.paren.perl6fe' 539 | 'patterns': [ 540 | { 541 | 'include': '#q_paren_string_content' 542 | } 543 | ] 544 | } 545 | { 546 | 'begin': '(?x) 547 | (q{1,2}(?:x|w|ww|v|s|a|h|f|c|b|p)?|Q(?:x|w|ww|v|s|a|h|f|c|b|p)?) 548 | ((?: 549 | \\s*:(?: 550 | x|exec|w|words|ww|quotewords|v|val|q|single|double| 551 | s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash| 552 | regexp|substr|trans|codes|p|path 553 | ) 554 | )*) 555 | \\s*(\\[\\[)' 556 | 'beginCaptures': 557 | '1': 558 | 'name': 'string.quoted.q.operator.perl6fe' 559 | '2': 560 | 'name': 'support.function.quote.adverb.perl6fe' 561 | '3': 562 | 'name': 'punctuation.definition.string.perl6fe' 563 | 'end': '\\]\\]' 564 | 'endCaptures': 565 | '0': 566 | 'name': 'punctuation.definition.string.perl6fe' 567 | 'contentName': 'string.quoted.q.double.bracket.perl6fe' 568 | 'patterns': [ 569 | { 570 | 'include': '#q_bracket_string_content' 571 | } 572 | ] 573 | } 574 | { 575 | 'begin': '(?x) 576 | (q{1,2}(?:x|w|ww|v|s|a|h|f|c|b|p)?|Q(?:x|w|ww|v|s|a|h|f|c|b|p)?) 577 | ((?: 578 | \\s*:(?: 579 | x|exec|w|words|ww|quotewords|v|val|q|single|double| 580 | s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash| 581 | regexp|substr|trans|codes|p|path 582 | ) 583 | )*) 584 | \\s*({)' 585 | 'beginCaptures': 586 | '1': 587 | 'name': 'string.quoted.q.operator.perl6fe' 588 | '2': 589 | 'name': 'support.function.quote.adverb.perl6fe' 590 | '3': 591 | 'name': 'punctuation.definition.string.perl6fe' 592 | 'end': '}' 593 | 'endCaptures': 594 | '0': 595 | 'name': 'punctuation.definition.string.perl6fe' 596 | 'contentName': 'string.quoted.q.single.brace.perl6fe' 597 | 'patterns': [ 598 | { 599 | 'include': '#q_brace_string_content' 600 | } 601 | ] 602 | } 603 | { 604 | 'begin': '(?x) 605 | (q{1,2}(?:x|w|ww|v|s|a|h|f|c|b|p)?|Q(?:x|w|ww|v|s|a|h|f|c|b|p)?) 606 | ((?: 607 | \\s*:(?: 608 | x|exec|w|words|ww|quotewords|v|val|q|single|double| 609 | s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash| 610 | regexp|substr|trans|codes|p|path 611 | ) 612 | )*) 613 | \\s*(<)' 614 | 'beginCaptures': 615 | '1': 616 | 'name': 'string.quoted.q.operator.perl6fe' 617 | '2': 618 | 'name': 'support.function.quote.adverb.perl6fe' 619 | '3': 620 | 'name': 'punctuation.definition.string.perl6fe' 621 | 'end': '>' 622 | 'endCaptures': 623 | '0': 624 | 'name': 'punctuation.definition.string.perl6fe' 625 | 'contentName': 'string.quoted.q.single.angle.perl6fe' 626 | 'patterns': [ 627 | { 628 | 'include': '#q_angle_string_content' 629 | } 630 | ] 631 | } 632 | { 633 | 'begin': '(?x) 634 | (q{1,2}(?:x|w|ww|v|s|a|h|f|c|b|p)?|Q(?:x|w|ww|v|s|a|h|f|c|b|p)?) 635 | ((?: 636 | \\s*:(?: 637 | x|exec|w|words|ww|quotewords|v|val|q|single|double| 638 | s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash| 639 | regexp|substr|trans|codes|p|path 640 | ) 641 | )*) 642 | \\s*(/)' 643 | 'beginCaptures': 644 | '1': 645 | 'name': 'string.quoted.q.operator.perl6fe' 646 | '2': 647 | 'name': 'support.function.quote.adverb.perl6fe' 648 | '3': 649 | 'name': 'punctuation.definition.string.perl6fe' 650 | 'end': '/' 651 | 'endCaptures': 652 | '0': 653 | 'name': 'punctuation.definition.string.perl6fe' 654 | 'contentName': 'string.quoted.q.single.slash.perl6fe' 655 | 'patterns': [ 656 | { 657 | 'include': '#q_slash_string_content' 658 | } 659 | ] 660 | } 661 | { 662 | 'begin': '(?x) 663 | (q{1,2}(?:x|w|ww|v|s|a|h|f|c|b|p)?|Q(?:x|w|ww|v|s|a|h|f|c|b|p)?) 664 | ((?: 665 | \\s*:(?: 666 | x|exec|w|words|ww|quotewords|v|val|q|single|double| 667 | s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash| 668 | regexp|substr|trans|codes|p|path 669 | ) 670 | )*) 671 | \\s*(\\()' 672 | 'beginCaptures': 673 | '1': 674 | 'name': 'string.quoted.q.operator.perl6fe' 675 | '2': 676 | 'name': 'support.function.quote.adverb.perl6fe' 677 | '3': 678 | 'name': 'punctuation.definition.string.perl6fe' 679 | 'end': '\\)' 680 | 'endCaptures': 681 | '0': 682 | 'name': 'punctuation.definition.string.perl6fe' 683 | 'contentName': 'string.quoted.q.single.paren.perl6fe' 684 | 'patterns': [ 685 | { 686 | 'include': '#q_paren_string_content' 687 | } 688 | ] 689 | } 690 | { 691 | 'begin': '(?x) 692 | (q{1,2}(?:x|w|ww|v|s|a|h|f|c|b|p)?|Q(?:x|w|ww|v|s|a|h|f|c|b|p)?) 693 | ((?: 694 | \\s*:(?: 695 | x|exec|w|words|ww|quotewords|v|val|q|single|double| 696 | s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash| 697 | regexp|substr|trans|codes|p|path 698 | ) 699 | )*) 700 | \\s*(\\[)' 701 | 'beginCaptures': 702 | '1': 703 | 'name': 'string.quoted.q.operator.perl6fe' 704 | '2': 705 | 'name': 'support.function.quote.adverb.perl6fe' 706 | '3': 707 | 'name': 'punctuation.definition.string.perl6fe' 708 | 'end': '\\]' 709 | 'endCaptures': 710 | '0': 711 | 'name': 'punctuation.definition.string.perl6fe' 712 | 'contentName': 'string.quoted.q.single.bracket.perl6fe' 713 | 'patterns': [ 714 | { 715 | 'include': '#q_bracket_string_content' 716 | } 717 | ] 718 | } 719 | { 720 | 'begin': '(?x) 721 | (q{1,2}(?:x|w|ww|v|s|a|h|f|c|b|p)?|Q(?:x|w|ww|v|s|a|h|f|c|b|p)?) 722 | ((?: 723 | \\s*:(?: 724 | x|exec|w|words|ww|quotewords|v|val|q|single|double| 725 | s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash| 726 | regexp|substr|trans|codes|p|path 727 | ) 728 | )*) 729 | \\s*(\')' 730 | 'beginCaptures': 731 | '1': 732 | 'name': 'string.quoted.q.operator.perl6fe' 733 | '2': 734 | 'name': 'support.function.quote.adverb.perl6fe' 735 | '3': 736 | 'name': 'punctuation.definition.string.perl6fe' 737 | 'end': '\'' 738 | 'endCaptures': 739 | '0': 740 | 'name': 'punctuation.definition.string.perl6fe' 741 | 'contentName': 'string.quoted.q.single.apostrophe.perl6fe' 742 | 'patterns': [ 743 | { 744 | 'include': '#q_single_string_content' 745 | } 746 | ] 747 | } 748 | { 749 | 'begin': '(?x) 750 | (q{1,2}(?:x|w|ww|v|s|a|h|f|c|b|p)?|Q(?:x|w|ww|v|s|a|h|f|c|b|p)?) 751 | ((?: 752 | \\s*:(?: 753 | x|exec|w|words|ww|quotewords|v|val|q|single|double| 754 | s|scalar|a|array|h|hash|f|function|c|closure|b|blackslash| 755 | regexp|substr|trans|codes|p|path 756 | ) 757 | )*) 758 | \\s*(")' 759 | 'beginCaptures': 760 | '1': 761 | 'name': 'string.quoted.q.operator.perl6fe' 762 | '2': 763 | 'name': 'support.function.quote.adverb.perl6fe' 764 | '3': 765 | 'name': 'punctuation.definition.string.perl6fe' 766 | 'end': '"' 767 | 'endCaptures': 768 | '0': 769 | 'name': 'punctuation.definition.string.perl6fe' 770 | 'contentName': 'string.quoted.q.single.quote.perl6fe' 771 | 'patterns': [ 772 | { 773 | 'include': '#q_double_string_content' 774 | } 775 | ] 776 | } 777 | { 778 | 'match': '\\b\\$\\w+\\b' 779 | 'name': 'variable.other.perl6fe' 780 | } 781 | { 782 | 'begin': '(?x)(?)' 798 | 'beginCaptures': 799 | '1': 800 | 'name': 'storage.type.declare.regexp.named.perl6fe' 801 | 'end': '(?)(?=[\\s\\{])' 823 | 'contentName': 'string.array.words.perl6fe' 824 | } 825 | { 826 | 'begin': '\\(' 827 | 'end': '(?\\=\\~])' 876 | 'name': 'storage.modifier.assignment.perl6fe' 877 | } 878 | { 879 | 'match': '\\b(for|loop|repeat|while|until|gather|given)(?!\\-)\\b' 880 | 'name': 'keyword.control.repeat.perl6fe' 881 | } 882 | { 883 | 'match': '(?x)\\b(? | => | --> | -> | \\+\\| | \\+\\+ | -- | 1006 | \\*\\* | \\?\\?\\? | \\?\\? | \\!\\!\\! | \\!\\! | && | 1007 | \\+\\^ | \\?\\^ | %% | \\+& | \\+< | \\+> | \\+\\^ | 1008 | \\.\\.(?!\\.) | \\.\\.\\^ | \\^\\.\\. | \\^\\.\\.\\^ | 1009 | \\?\\| | !=(?!\\=) | !==(?!\\=) | <=(?!>) | >= | === | == | 1010 | =:= | ~~ | \\x{2245} | \\|\\| | \\^\\^ | \\/\\/ | := | ::= | 1011 | \\.\\.\\.' 1012 | 'name': 'keyword.operator.multi-symbol.perl6fe' 1013 | } 1014 | { 1015 | 'include': '#special_variables' 1016 | } 1017 | { 1018 | 'match': '(?x)(?<=\\[) 1019 | \\s* (\\*) \\s* 1020 | ([\\-\\*%\\^\\+\\/]|div|mod|gcd|lcm) 1021 | \\s* (\\d+) \\s* 1022 | (?=\\])' 1023 | 'name': 'meta.subscript.whatever.perl6fe' 1024 | 'captures': 1025 | '1': 1026 | 'name': 'constant.language.whatever.perl6fe' 1027 | '2': 1028 | 'name': 'keyword.operator.minus.back-from.perl6fe' 1029 | '3': 1030 | 'name': 'constant.numeric.back-from.perl6fe' 1031 | } 1032 | { 1033 | 'match': '\\*\\s*(?=\\])' 1034 | 'name': 'constant.language.whatever.hack.perl6fe' 1035 | } 1036 | { 1037 | 'include': '#variables' 1038 | } 1039 | { 1040 | 'match': '(?x)\\b(?)' 1071 | 'name': 'support.function.perl6fe' 1072 | } 1073 | { 1074 | 'match': '(?x) 1075 | (?<\\*\\!\\?~\\/\\|]| 1077 | (?' 1103 | 'endCaptures': 1104 | '0': 1105 | 'name': 'punctuation.definition.radix.perl6fe' 1106 | 'contentName': 'constant.numeric.perl6fe' 1107 | 1108 | } 1109 | { 1110 | 'begin': '\\{' 1111 | 'beginCaptures': 1112 | '0': 1113 | 'name': 'punctuation.definition.block.perl6fe' 1114 | 'end': '\\}' 1115 | 'endCaptures': 1116 | '0': 1117 | 'name': 'punctuation.definition.block.perl6fe' 1118 | 'name': 'meta.block.perl6fe' 1119 | 'patterns': [ 1120 | { 1121 | 'include': '$self' 1122 | } 1123 | ] 1124 | } 1125 | ] 1126 | 'repository': 1127 | 'numbers': 1128 | 'patterns': [ 1129 | { 1130 | 'match': '(?<=[=,;\\^\\s\\{\\[\\(\\/]|\\.\\.)0[bodx]\\w+' 1131 | 'name': 'constant.numeric.radix.perl6fe' 1132 | } 1133 | { 1134 | 'match': '(?x) 1135 | (?<=[=,:;\\^\\s\\{\\[\\(\\/]|\\.\\.) 1136 | (?:[\\+\\-])? 1137 | (?: \\d+ (?:[\\_\\d]+\\d)? ) 1138 | (?: \\. \\d+ (?:[\\_\\d]+\\d)? )? 1139 | (?: e \\d+ (?:[\\_\\d]+\\d)? )?' 1140 | 'name': 'constant.numeric.perl6fe' 1141 | } 1142 | ] 1143 | 'comment-block-delimited': 1144 | 'patterns': [ 1145 | { 1146 | 'begin': '^(=)(begin)\\s+(\\w+)' 1147 | 'end': '^(=)(end)\\s+(\\w+)' 1148 | 'captures': 1149 | '1': 1150 | 'name': 'storage.modifier.block.delimited.perl6fe' 1151 | '2': 1152 | 'name': 'keyword.operator.block.delimited.perl6fe' 1153 | '3': 1154 | 'name': 'entity.other.attribute-name.block.delimited.perl6fe' 1155 | 'contentName': 'comment.block.delimited.perl6fe' 1156 | 'patterns': [ 1157 | { 1158 | 'include': '#comment-block-syntax' 1159 | } 1160 | ] 1161 | } 1162 | ] 1163 | 'comment-block-abbreviated': 1164 | 'patterns': [ 1165 | { 1166 | 'match': '^(=)(\\w+)\\s+(.+)$' 1167 | 'captures': 1168 | '1': 1169 | 'name': 'storage.modifier.block.abbreviated.perl6fe' 1170 | '2': 1171 | 'name': 'entity.other.attribute-name.block.abbreviated.perl6fe' 1172 | '3': 1173 | 'name': 'entity.name.section.abbreviated.perl6fe' 1174 | 'name': 'meta.block.abbreviated.perl6fe' 1175 | } 1176 | ] 1177 | 'shellquotes': 1178 | 'patterns': [ 1179 | { 1180 | 'begin': '([qQ]x)\\s*({{)' 1181 | 'beginCaptures': 1182 | '1': 1183 | 'name': 'string.quoted.q.shell.operator.perl6fe' 1184 | '2': 1185 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1186 | 'end': '}}' 1187 | 'endCaptures': 1188 | '0': 1189 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1190 | 'name': 'meta.shell.quote.single.perl6fe' 1191 | 'patterns': [ 1192 | { 1193 | 'include': 'source.shell' 1194 | 'include': '#q_single_string_content' 1195 | } 1196 | ] 1197 | } 1198 | { 1199 | 'begin': '([qQ]x)\\s*({)' 1200 | 'beginCaptures': 1201 | '1': 1202 | 'name': 'string.quoted.q.shell.operator.perl6fe' 1203 | '2': 1204 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1205 | 'end': '}' 1206 | 'endCaptures': 1207 | '0': 1208 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1209 | 'name': 'meta.shell.quote.single.perl6fe' 1210 | 'patterns': [ 1211 | { 1212 | 'include': 'source.shell' 1213 | 'include': '#q_single_string_content' 1214 | 1215 | } 1216 | ] 1217 | } 1218 | { 1219 | 'begin': '([qQ]x)\\s*(\\[\\[)' 1220 | 'beginCaptures': 1221 | '1': 1222 | 'name': 'string.quoted.q.shell.operator.perl6fe' 1223 | '2': 1224 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1225 | 'end': '\\]\\]' 1226 | 'endCaptures': 1227 | '0': 1228 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1229 | 'name': 'meta.shell.quote.single.perl6fe' 1230 | 'patterns': [ 1231 | { 1232 | 'include': 'source.shell' 1233 | 'include': '#q_single_string_content' 1234 | } 1235 | ] 1236 | } 1237 | { 1238 | 'begin': '([Qq]x)\\s*(\\[)' 1239 | 'beginCaptures': 1240 | '1': 1241 | 'name': 'string.quoted.q.shell.operator.perl6fe' 1242 | '2': 1243 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1244 | 'end': '\\]' 1245 | 'endCaptures': 1246 | '0': 1247 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1248 | 'name': 'meta.shell.quote.single.perl6fe' 1249 | 'patterns': [ 1250 | { 1251 | 'include': 'source.shell' 1252 | 'include': '#q_single_string_content' 1253 | } 1254 | ] 1255 | } 1256 | { 1257 | 'begin': '([Qq]x)\\s*(\\|)' 1258 | 'beginCaptures': 1259 | '1': 1260 | 'name': 'string.quoted.q.shell.operator.perl6fe' 1261 | '2': 1262 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1263 | 'end': '\\|' 1264 | 'endCaptures': 1265 | '0': 1266 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1267 | 'name': 'meta.shell.quote.single.perl6fe' 1268 | 'patterns': [ 1269 | { 1270 | 'include': 'source.shell' 1271 | 'include': '#q_single_string_content' 1272 | } 1273 | ] 1274 | } 1275 | { 1276 | 'begin': '([Qq]x)\\s*(\\/)' 1277 | 'beginCaptures': 1278 | '1': 1279 | 'name': 'string.quoted.q.shell.operator.perl6fe' 1280 | '2': 1281 | 'name': 'punctuation.section.embedded.shell.begin.perl6fe' 1282 | 'end': '(?)' 1439 | 'captures': 1440 | '1': 1441 | 'name': 'support.function.pod.link.perl6fe' 1442 | '2': 1443 | 'name': 'punctuation.section.embedded.pod.link.perl6fe' 1444 | '3': 1445 | 'name': 'entity.name.type.pod.link.perl6fe' 1446 | '4': 1447 | 'name': 'punctuation.section.embedded.pod.link.perl6fe' 1448 | '5': 1449 | 'name': 'markup.underline.link.pod.perl6fe' 1450 | '6': 1451 | 'name': 'punctuation.section.embedded.pod.link.perl6fe' 1452 | 'name': 'meta.pod.l.perl6fe' 1453 | } 1454 | { 1455 | 'match': '([CKT])(?:(\\<\\<)(.+?)(\\>\\>)|(\\<)(.+?)(\\>))' 1456 | 'captures': 1457 | '1': 1458 | 'name': 'support.function.pod.code.perl6fe' 1459 | '2': 1460 | 'name': 'punctuation.section.embedded.pod.code.perl6fe' 1461 | '3': 1462 | 'name': 'markup.raw.code.perl6fe' 1463 | '4': 1464 | 'name': 'punctuation.section.embedded.pod.code.perl6fe' 1465 | '5': 1466 | 'name': 'punctuation.section.embedded.pod.code.perl6fe' 1467 | '6': 1468 | 'name': 'markup.raw.code.perl6fe' 1469 | '7': 1470 | 'name': 'punctuation.section.embedded.pod.code.perl6fe' 1471 | 'name': 'meta.pod.c.perl6fe' 1472 | } 1473 | { 1474 | 'match': '(U)(\\<)(.+?)(\\>)' 1475 | 'captures': 1476 | '1': 1477 | 'name': 'support.function.pod.code.perl6fe' 1478 | '2': 1479 | 'name': 'punctuation.section.embedded.pod.code.perl6fe' 1480 | '3': 1481 | 'name': 'markup.underline.perl6fe' 1482 | '4': 1483 | 'name': 'punctuation.section.embedded.pod.code.perl6fe' 1484 | 'name': 'meta.pod.c.perl6fe' 1485 | } 1486 | { 1487 | 'match': '(I)(\\<)(.+?)(\\>)' 1488 | 'captures': 1489 | '1': 1490 | 'name': 'support.function.pod.code.perl6fe' 1491 | '2': 1492 | 'name': 'punctuation.section.embedded.pod.code.perl6fe' 1493 | '3': 1494 | 'name': 'markup.italic.perl6fe' 1495 | '4': 1496 | 'name': 'punctuation.section.embedded.pod.code.perl6fe' 1497 | 'name': 'meta.pod.c.perl6fe' 1498 | } 1499 | { 1500 | 'match': '(B)(\\<)(.+?)(\\>)' 1501 | 'captures': 1502 | '1': 1503 | 'name': 'support.function.pod.code.perl6fe' 1504 | '2': 1505 | 'name': 'punctuation.section.embedded.pod.code.perl6fe' 1506 | '3': 1507 | 'name': 'markup.bold.perl6fe' 1508 | '4': 1509 | 'name': 'punctuation.section.embedded.pod.code.perl6fe' 1510 | 'name': 'meta.pod.c.perl6fe' 1511 | } 1512 | ] 1513 | 'heredocs': 1514 | 'patterns': [ 1515 | { 1516 | 'begin': '(?x) 1517 | (?: 1518 | ([qQ](?!/)|qq|qw|qww|qx|qqx) 1519 | \\s* 1520 | ((?:\\s*:\\w+)*\\s*:(?:to|heredoc))\\s* 1521 | | 1522 | (qto|qqto|Qto) 1523 | \\s* 1524 | ((?:\\s*:\\w+)*)\\s* 1525 | ) 1526 | /(\\w+)/' 1527 | 'beginCaptures': 1528 | '1': 1529 | 'name': 'string.quoted.construct.perl6fe' 1530 | '2': 1531 | 'name': 'support.function.adverb.perl6fe' 1532 | '3': 1533 | 'name': 'string.quoted.construct.perl6fe' 1534 | '4': 1535 | 'name': 'support.function.adverb.perl6fe' 1536 | '5': 1537 | 'name': 'entity.other.attribute-name.heredoc.delimiter.perl6fe' 1538 | 'end': '\\s*\\5' 1539 | 'endCaptures': 1540 | '0': 1541 | 'name': 'entity.other.attribute-name.heredoc.delimiter.perl6fe' 1542 | 'patterns': [ 1543 | { 1544 | 'begin': '(?<=/)' 1545 | 'end': '\\n' 1546 | 'patterns': [ 1547 | { 1548 | 'include': '$self' 1549 | } 1550 | ] 1551 | 'name': 'meta.heredoc.continuation.perl6fe' 1552 | } 1553 | { 1554 | 'match': '^(?:.|\\n)*$' 1555 | 'name': 'string.quoted.heredoc.perl6fe' 1556 | } 1557 | ] 1558 | 'name': 'meta.heredoc.perl6fe' 1559 | } 1560 | ] 1561 | 'p5_regex': 1562 | 'patterns': [ 1563 | { 1564 | 'begin': '(?x)(?|\'\\w*\')' 1673 | 'name': 'constant.character.escape.perl' 1674 | } 1675 | { 1676 | 'match': '\\\\N\\{[^\\}]*\\}' 1677 | 'name': 'constant.character.escape.perl' 1678 | } 1679 | { 1680 | 'match': '\\\\o\\{\\d*\\}' 1681 | 'name': 'constant.character.escape.perl' 1682 | } 1683 | { 1684 | 'match': '\\\\(?:p|P)(?:\\{\\w*\\}|P)' 1685 | 'name': 'constant.character.escape.perl' 1686 | } 1687 | { 1688 | 'match': '\\\\x(?:[0-9a-zA-Z]{2}|\\{\\w*\\})?' 1689 | 'name': 'constant.character.escape.perl' 1690 | } 1691 | { 1692 | 'match': '\\\\.' 1693 | 'name': 'constant.character.escape.perl' 1694 | } 1695 | ] 1696 | 'special_variables': 1697 | 'patterns': [ 1698 | { 1699 | 'match': '(?x) 1700 | [\\$\\@](?=[\\s,;\\{\\[\\(])| 1701 | (?<=[\\(\\,])\\s*%(?![\\w\\*\\!\\?\\.\\^:=~])| 1702 | \\$_| 1703 | \\$\\/| 1704 | \\$\\!(?!\\w)| 1705 | \\$\\d(?!\\w)' 1706 | 'name': 'keyword.other.special-method.perl6fe' 1707 | } 1708 | ] 1709 | 'variables': 1710 | 'patterns': [ 1711 | { 1712 | 'begin': '\\$(?=\\<)' 1713 | 'beginCaptures': 1714 | '0': 1715 | 'name': 'variable.other.identifier.sigil.regexp.perl6' 1716 | 'end': '(?![\\w\\<\\>])' 1717 | 'name': 'meta.match.variable.perl6fe' 1718 | 'patterns': [ 1719 | { 1720 | 'match': '(\\<)([\\w\\-]+)(\\>)' 1721 | 'captures': 1722 | '1': 1723 | 'name': 'support.class.match.name.delimiter.regexp.perl6fe' 1724 | '2': 1725 | 'name': 'variable.other.identifier.regexp.perl6' 1726 | '3': 1727 | 'name': 'support.class.match.name.delimiter.regexp.perl6fe' 1728 | } 1729 | ] 1730 | } 1731 | { 1732 | 'match': '(?x) 1733 | (\\$|@|%|&) 1734 | (\\.|\\*|:|!|\\^|~|=|\\?)? 1735 | ( 1736 | (?:[a-zA-Z]) 1737 | (?: 1738 | [a-zA-Z0-9_\xc0-\xff\\$]| 1739 | [\\-\'][a-zA-Z_\xc0-\xff\\$] 1740 | )* 1741 | )' 1742 | 'captures': 1743 | '1': 1744 | 'name': 'variable.other.identifier.sigil.perl6fe' 1745 | '2': 1746 | 'name': 'support.class.twigil.perl6fe' 1747 | '3': 1748 | 'name': 'variable.other.identifier.perl6fe' 1749 | 'name': 'meta.variable.container.perl6fe' 1750 | } 1751 | ] 1752 | 'interpolation': 1753 | 'patterns': [ 1754 | { 1755 | 'match': '(?x)(?' 1783 | 'patterns': [ 1784 | { 1785 | 'include': '#q_angle_string_content' 1786 | } 1787 | ] 1788 | 'q_brace_string_content': 1789 | 'begin': '{' 1790 | 'end': '}' 1791 | 'patterns': [ 1792 | { 1793 | 'include': '#q_brace_string_content' 1794 | } 1795 | ] 1796 | 'q_bracket_string_content': 1797 | 'begin': '\\[' 1798 | 'end': '\\]' 1799 | 'patterns': [ 1800 | { 1801 | 'include': '#q_bracket_string_content' 1802 | } 1803 | ] 1804 | 'q_double_string_content': 1805 | 'begin': '\"' 1806 | 'end': '\"' 1807 | 'patterns': [ 1808 | { 1809 | 'include': '#q_double_string_content' 1810 | } 1811 | ] 1812 | 'q_paren_string_content': 1813 | 'begin': '\\(' 1814 | 'end': '\\)' 1815 | 'patterns': [ 1816 | { 1817 | 'include': '#q_paren_string_content' 1818 | } 1819 | ] 1820 | 'q_single_string_content': 1821 | 'begin': '\'' 1822 | 'end': '\'' 1823 | 'patterns': [ 1824 | { 1825 | 'include': '#q_single_string_content' 1826 | } 1827 | ] 1828 | 'q_slash_string_content': 1829 | 'begin': '\\\\/' 1830 | 'end': '\\\\/' 1831 | 'patterns': [ 1832 | { 1833 | 'include': '#q_slash_string_content' 1834 | } 1835 | ] 1836 | -------------------------------------------------------------------------------- /images/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MadcapJake/language-perl6fe/83c16039c8120d1eff46a450a21893f5620ec25f/images/example1.png -------------------------------------------------------------------------------- /images/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MadcapJake/language-perl6fe/83c16039c8120d1eff46a450a21893f5620ec25f/images/example2.png -------------------------------------------------------------------------------- /images/example3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MadcapJake/language-perl6fe/83c16039c8120d1eff46a450a21893f5620ec25f/images/example3.png -------------------------------------------------------------------------------- /images/example_comments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MadcapJake/language-perl6fe/83c16039c8120d1eff46a450a21893f5620ec25f/images/example_comments.png -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | "use babel"; 2 | module.exports = { 3 | // This is called on plugin activation by the Atom environment 4 | activate(state) { 5 | // Install package-deps section in package.json without user intervention 6 | require('atom-package-deps') 7 | .install(null, false) 8 | .then( () => { 9 | // All dependencies are now installed, let's roll 10 | this.activateAfterDepsCheck() 11 | }) 12 | }, 13 | 14 | // This is called once the dependencies are properly installed 15 | activateAfterDepsCheck() { 16 | 17 | // Disable language-perl if it is enabled! 18 | if (! atom.packages.isPackageDisabled("language-perl6fe")) { 19 | atom.packages.disablePackage("language-perl6fe") 20 | atom.notifications.addInfo("language-perlfe has been disabled, and language-perl6 (the package which supersedes it) has been installed and activated for a more Perl 6 fun editing experience") 21 | } 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lp6iym.p6: -------------------------------------------------------------------------------- 1 | # Single line comment start with a pound 2 | 3 | #`( 4 | Multiline comments use #` and a quoting construct. 5 | (), [], {}, 「」, etc, will work. 6 | ) 7 | 8 | ### Variables 9 | 10 | # In Perl 6, you declare a lexical variable using `my` 11 | my $variable; 12 | # Perl 6 has 4 kinds of variables: 13 | 14 | ## * Scalars. They represent a single value. They start with a `$` 15 | 16 | my $str = 'String'; 17 | # double quotes allow for interpolation (which we'll see later): 18 | my $str2 = "String"; 19 | 20 | # variable names can contain but not end with simple quotes and dashes, 21 | # and can contain (and end with) underscores : 22 | # my $weird'variable-name_ = 5; # works ! 23 | 24 | my $bool = True; # `True` and `False` are Perl 6's boolean 25 | my $inverse = !$bool; # You can invert a bool with the prefix `!` operator 26 | my $forced-bool = so $str; # And you can use the prefix `so` operator 27 | # which turns its operand into a Bool 28 | 29 | ## * Lists. They represent multiple values. Their name start with `@`. 30 | 31 | my @array = 'a', 'b', 'c'; 32 | # equivalent to : 33 | my @letters = ; # array of words, delimited by space. 34 | # Similar to perl5's qw, or Ruby's %w. 35 | my @array = 1, 2, 3; 36 | 37 | say @array[2]; # Array indices start at 0 -- This is the third element 38 | 39 | say "Interpolate an array using [] : @array[]"; 40 | #=> Interpolate an array using [] : 1 2 3 41 | 42 | @array[0] = -1; # Assign a new value to an array index 43 | @array[0, 1] = 5, 6; # Assign multiple values 44 | 45 | my @keys = 0, 2; 46 | @array[@keys] = @letters; # Assign using an array 47 | say @array; #=> a 6 b 48 | 49 | ## * Hashes, or key-value Pairs. 50 | # Hashes are actually arrays of Pairs 51 | # (you can construct a Pair object using the syntax `Key => Value`), 52 | # except they get "flattened" (hash context), removing duplicated keys. 53 | my %hash = 1 => 2, 54 | 3 => 4; 55 | my %hash = foo => "bar", # keys get auto-quoted 56 | "some other" => "value", # trailing commas are okay 57 | ; 58 | my %hash = ; # you can also create a hash 59 | # from an even-numbered array 60 | my %hash = key1 => 'value1', key2 => 'value2'; # same as this 61 | 62 | # You can also use the "colon pair" syntax: 63 | # (especially handy for named parameters that you'll see later) 64 | my %hash = :w(1), # equivalent to `w => 1` 65 | # this is useful for the `True` shortcut: 66 | :truey, # equivalent to `:truey(True)`, or `truey => True` 67 | # and for the `False` one: 68 | :!falsey, # equivalent to `:falsey(False)`, or `falsey => False` 69 | ; 70 | 71 | say %hash{'key1'}; # You can use {} to get the value from a key 72 | say %hash; # If it's a string, you can actually use <> 73 | # (`{key1}` doesn't work, as Perl6 doesn't have barewords) 74 | 75 | ## * Subs (subroutines, or functions in most other languages). 76 | sub say-hello { say "Hello, world" } 77 | 78 | sub say-hello-to(Str $name) { # You can provide the type of an argument 79 | # and it'll be checked at compile-time. 80 | 81 | say "Hello, $name !"; 82 | } 83 | 84 | ## It can also have optional arguments: 85 | sub with-optional($arg?) { # the "?" marks the argument optional 86 | say "I might return `(Any)` (Perl's "null"-like value) if I don't have 87 | an argument passed, or I'll return my argument"; 88 | $arg; 89 | } 90 | with-optional; # returns Any 91 | with-optional(); # returns Any 92 | with-optional(1); # returns 1 93 | 94 | ## You can also give them a default value when they're not passed: 95 | sub hello-to($name = "World") { 96 | say "Hello, $name !"; 97 | } 98 | hello-to; #=> Hello, World ! 99 | hello-to(); #=> Hello, World ! 100 | hello-to('You'); #=> Hello, You ! 101 | 102 | ## You can also, by using a syntax akin to the one of hashes (yay unified syntax !), 103 | ## pass *named* arguments to a `sub`. 104 | # They're optional, and will default to "Any". 105 | sub with-named($normal-arg, :$named) { 106 | say $normal-arg + $named; 107 | } 108 | with-named(1, named => 6); #=> 7 109 | # There's one gotcha to be aware of, here: 110 | # If you quote your key, Perl 6 won't be able to see it at compile time, 111 | # and you'll have a single Pair object as a positional parameter, 112 | # which means this fails: 113 | with-named(1, 'named' => 6); 114 | 115 | with-named(2, :named(5)); #=> 7 116 | 117 | # To make a named argument mandatory, you can use `?`'s inverse, `!` 118 | sub with-mandatory-named(:$str!) { 119 | say "$str !"; 120 | } 121 | with-mandatory-named(str => "My String"); #=> My String ! 122 | with-mandatory-named; # run time error: "Required named parameter not passed" 123 | with-mandatory-named(3); # run time error: "Too many positional parameters passed" 124 | 125 | ## If a sub takes a named boolean argument ... 126 | sub takes-a-bool($name, :$bool) { 127 | say "$name takes $bool"; 128 | } 129 | # ... you can use the same "short boolean" hash syntax: 130 | takes-a-bool('config', :bool); # config takes True 131 | takes-a-bool('config', :!bool); # config takes False 132 | 133 | ## You can also provide your named arguments with defaults: 134 | sub named-def(:$def = 5) { 135 | say $def; 136 | } 137 | named-def; #=> 5 138 | named-def(def => 15); #=> 15 139 | 140 | # Since you can omit parenthesis to call a function with no arguments, 141 | # you need "&" in the name to store `say-hello` in a variable. 142 | my &s = &say-hello; 143 | my &other-s = sub { say "Anonymous function !" } 144 | 145 | # A sub can have a "slurpy" parameter, or "doesn't-matter-how-many" 146 | sub as-many($head, *@rest) { # `*@` (slurpy) will basically "take everything else". 147 | # Note: you can have parameters *before* (like here) 148 | # a slurpy one, but not *after*. 149 | say @rest.join(' / ') ~ " !"; 150 | } 151 | say as-many('Happy', 'Happy', 'Birthday'); #=> Happy / Birthday ! 152 | # Note that the splat (the *) did not 153 | # consume the parameter before. 154 | 155 | ## You can call a function with an array using the 156 | # "argument list flattening" operator `|` 157 | # (it's not actually the only role of this operator, but it's one of them) 158 | sub concat3($a, $b, $c) { 159 | say "$a, $b, $c"; 160 | } 161 | concat3(|@array); #=> a, b, c 162 | # `@array` got "flattened" as a part of the argument list 163 | 164 | ### Containers 165 | # In Perl 6, values are actually stored in "containers". 166 | # The assignment operator asks the container on the left to store the value on 167 | # its right. When passed around, containers are marked as immutable. 168 | # Which means that, in a function, you'll get an error if you try to 169 | # mutate one of your arguments. 170 | # If you really need to, you can ask for a mutable container using `is rw`: 171 | sub mutate($n is rw) { 172 | $n++; 173 | say "\$n is now $n !"; 174 | } 175 | 176 | # If what you want a copy instead, use `is copy`. 177 | 178 | # A sub itself returns a container, which means it can be marked as rw: 179 | my $x = 42; 180 | sub x-store() is rw { $x } 181 | x-store() = 52; # in this case, the parentheses are mandatory 182 | # (else Perl 6 thinks `x-store` is an identifier) 183 | say $x; #=> 52 184 | 185 | 186 | ### Control Flow Structures 187 | ## Conditionals 188 | 189 | # - `if` 190 | # Before talking about `if`, we need to know which values are "Truthy" 191 | # (represent True), and which are "Falsey" (or "Falsy") -- represent False. 192 | # Only these values are Falsey: 0, (), {}, "", Nil, A type (like `Str` or `Int`), 193 | # and of course False itself. 194 | # Every other value is Truthy. 195 | if True { 196 | say "It's true !"; 197 | } 198 | 199 | unless False { 200 | say "It's not false !"; 201 | } 202 | 203 | # As you can see, you don't need parentheses around conditions. 204 | # However, you do need the brackets around the "body" block: 205 | # if (true) say; # This doesn't work ! 206 | 207 | # You can also use their postfix versions, with the keyword after: 208 | say "Quite truthy" if True; 209 | 210 | # - Ternary conditional, "?? !!" (like `x ? y : z` in some other languages) 211 | my $a = $condition ?? $value-if-true !! $value-if-false; 212 | 213 | # - `given`-`when` looks like other languages' `switch`, but much more 214 | # powerful thanks to smart matching and thanks to Perl 6's "topic variable", $_. 215 | # 216 | # This variable contains the default argument of a block, 217 | # a loop's current iteration (unless explicitly named), etc. 218 | # 219 | # `given` simply puts its argument into `$_` (like a block would do), 220 | # and `when` compares it using the "smart matching" (`~~`) operator. 221 | # 222 | # Since other Perl 6 constructs use this variable (as said before, like `for`, 223 | # blocks, etc), this means the powerful `when` is not only applicable along with 224 | # a `given`, but instead anywhere a `$_` exists. 225 | given "foo bar" { 226 | say $_; #=> foo bar 227 | when /foo/ { # Don't worry about smart matching yet – just know `when` uses it. 228 | # This is equivalent to `if $_ ~~ /foo/`. 229 | say "Yay !"; 230 | } 231 | when $_.chars > 50 { # smart matching anything with True (`$a ~~ True`) is True, 232 | # so you can also put "normal" conditionals. 233 | # This when is equivalent to this `if`: 234 | # if $_ ~~ ($_.chars > 50) {...} 235 | # Which means: 236 | # if $_.chars > 50 {...} 237 | say "Quite a long string !"; 238 | } 239 | default { # same as `when *` (using the Whatever Star) 240 | say "Something else" 241 | } 242 | } 243 | 244 | ## Looping constructs 245 | 246 | # - `loop` is an infinite loop if you don't pass it arguments, 247 | # but can also be a C-style `for` loop: 248 | loop { 249 | say "This is an infinite loop !"; 250 | last; # last breaks out of the loop, like the `break` keyword in other languages 251 | } 252 | 253 | loop (my $i = 0; $i < 5; $i++) { 254 | next if $i == 3; # `next` skips to the next iteration, like `continue` 255 | # in other languages. Note that you can also use postfix 256 | # conditionals, loops, etc. 257 | say "This is a C-style for loop !"; 258 | } 259 | 260 | # - `for` - Passes through an array 261 | for @array -> $variable { 262 | say "I've got $variable !"; 263 | } 264 | 265 | # As we saw with given, for's default "current iteration" variable is `$_`. 266 | # That means you can use `when` in a `for` just like you were in a `given`. 267 | for @array { 268 | say "I've got $_"; 269 | 270 | .say; # This is also allowed. 271 | # A dot call with no "topic" (receiver) is sent to `$_` by default 272 | $_.say; # the above and this are equivalent. 273 | } 274 | 275 | for @array { 276 | # You can... 277 | next if $_ == 3; # Skip to the next iteration (`continue` in C-like languages). 278 | redo if $_ == 4; # Re-do the iteration, keeping the same topic variable (`$_`). 279 | last if $_ == 5; # Or break out of a loop (like `break` in C-like languages). 280 | } 281 | 282 | # The "pointy block" syntax isn't specific to for. 283 | # It's just a way to express a block in Perl6. 284 | if long-computation() -> $result { 285 | say "The result is $result"; 286 | } 287 | 288 | ### Operators 289 | 290 | ## Since Perl languages are very much operator-based languages, 291 | ## Perl 6 operators are actually just funny-looking subroutines, in syntactic 292 | ## categories, like infix:<+> (addition) or prefix: (bool not). 293 | 294 | ## The categories are: 295 | # - "prefix": before (like `!` in `!True`). 296 | # - "postfix": after (like `++` in `$a++`). 297 | # - "infix": in between (like `*` in `4 * 3`). 298 | # - "circumfix": around (like `[`-`]` in `[1, 2]`). 299 | # - "post-circumfix": around, after another term (like `{`-`}` in `%hash{'key'}`) 300 | 301 | ## The associativity and precedence list are explained below. 302 | 303 | # Alright, you're set to go ! 304 | 305 | ## * Equality Checking 306 | 307 | # - `==` is numeric comparison 308 | 3 == 4; # False 309 | 3 != 4; # True 310 | 311 | # - `eq` is string comparison 312 | 'a' eq 'b'; 313 | 'a' ne 'b'; # not equal 314 | 'a' !eq 'b'; # same as above 315 | 316 | # - `eqv` is canonical equivalence (or "deep equality") 317 | (1, 2) eqv (1, 3); 318 | 319 | # - `~~` is smart matching 320 | # For a complete list of combinations, use this table: 321 | # http://perlcabal.org/syn/S03.html#Smart_matching 322 | 'a' ~~ /a/; # true if matches regexp 323 | 'key' ~~ %hash; # true if key exists in hash 324 | $arg ~~ &bool-returning-function; # `True` if the function, passed `$arg` 325 | # as an argument, returns `True`. 326 | 1 ~~ Int; # "has type" (check superclasses and roles) 327 | 1 ~~ True; # smart-matching against a boolean always returns that boolean 328 | # (and will warn). 329 | 330 | # You also, of course, have `<`, `<=`, `>`, `>=`. 331 | # Their string equivalent are also avaiable : `lt`, `le`, `gt`, `ge`. 332 | 3 > 4; 333 | 334 | ## * Range constructors 335 | 3 .. 7; # 3 to 7, both included 336 | # `^` on either side them exclusive on that side : 337 | 3 ^..^ 7; # 3 to 7, not included (basically `4 .. 6`) 338 | # This also works as a shortcut for `0..^N`: 339 | ^10; # means 0..^10 340 | 341 | # This also allows us to demonstrate that Perl 6 has lazy/infinite arrays, 342 | # using the Whatever Star: 343 | my @array = 1..*; # 1 to Infinite ! `1..Inf` is the same. 344 | say @array[^10]; # you can pass arrays as subscripts and it'll return 345 | # an array of results. This will print 346 | # "1 2 3 4 5 6 7 8 9 10" (and not run out of memory !) 347 | # Note : when reading an infinite list, Perl 6 will "reify" the elements 348 | # it needs, then keep them in memory. They won't be calculated more than once. 349 | # It also will never calculate more elements that are needed. 350 | 351 | # An array subscript can also be a closure. 352 | # It'll be called with the length as the argument 353 | say join(' ', @array[15..*]); #=> 15 16 17 18 19 354 | # which is equivalent to: 355 | say join(' ', @array[-> $n { 15..$n }]); 356 | # Note: if you try to do either of those with an infinite loop, 357 | # you'll trigger an infinite loop (your program won't finish) 358 | 359 | # You can use that in most places you'd expect, even assigning to an array 360 | my @numbers = ^20; 361 | 362 | # Here numbers increase by "6"; more on `...` operator later. 363 | my @seq = 3, 9 ... * > 95; # 3 9 15 21 27 [...] 81 87 93 99; 364 | @numbers[5..*] = 3, 9 ... *; # even though the sequence is infinite, 365 | # only the 15 needed values will be calculated. 366 | say @numbers; #=> 0 1 2 3 4 3 9 15 21 [...] 81 87 367 | # (only 20 values) 368 | 369 | ## * And, Or 370 | 3 && 4; # 4, which is Truthy. Calls `.Bool` on `4` and gets `True`. 371 | 0 || False; # False. Calls `.Bool` on `0` 372 | 373 | ## * Short-circuit (and tight) versions of the above 374 | $a && $b && $c; # Returns the first argument that evaluates to False, 375 | # or the last argument. 376 | $a || $b; 377 | 378 | # And because you're going to want them, 379 | # you also have compound assignment operators: 380 | $a *= 2; # multiply and assignment 381 | $b %%= 5; # divisible by and assignment 382 | @array .= sort; # calls the `sort` method and assigns the result back 383 | 384 | ### More on subs ! 385 | # As we said before, Perl 6 has *really* powerful subs. We're going to see 386 | # a few more key concepts that make them better than in any other language :-). 387 | 388 | ## Unpacking ! 389 | # It's the ability to "extract" arrays and keys (AKA "destructuring"). 390 | # It'll work in `my`s and in parameter lists. 391 | my ($a, $b) = 1, 2; 392 | say $a; #=> 1 393 | my ($, $, $c) = 1, 2, 3; # keep the non-interesting anonymous 394 | say $c; #=> 3 395 | 396 | my ($head, *@tail) = 1, 2, 3; # Yes, it's the same as with "slurpy subs" 397 | my (*@small) = 1; 398 | 399 | sub foo(@array [$fst, $snd]) { 400 | say "My first is $fst, my second is $snd ! All in all, I'm @array[]."; 401 | # (^ remember the `[]` to interpolate the array) 402 | } 403 | foo(@tail); #=> My first is 2, my second is 3 ! All in all, I'm 2 3 404 | 405 | 406 | # If you're not using the array itself, you can also keep it anonymous, 407 | # much like a scalar: 408 | sub first-of-array(@ [$fst]) { $fst } 409 | first-of-array(@small); #=> 1 410 | first-of-array(@tail); # Throws an error "Too many positional parameters passed" 411 | # (which means the array is too big). 412 | 413 | # You can also use a slurp ... 414 | sub slurp-in-array(@ [$fst, *@rest]) { # You could keep `*@rest` anonymous 415 | say $fst + @rest.elems; # `.elems` returns a list's length. 416 | # Here, `@rest` is `(3,)`, since `$fst` holds the `2`. 417 | } 418 | slurp-in-array(@tail); #=> 3 419 | 420 | # You could even extract on a slurpy (but it's pretty useless ;-).) 421 | sub fst(*@ [$fst]) { # or simply : `sub fst($fst) { ... }` 422 | say $fst; 423 | } 424 | fst(1); #=> 1 425 | fst(1, 2); # errors with "Too many positional parameters passed" 426 | 427 | # You can also destructure hashes (and classes, which you'll learn about later !) 428 | # The syntax is basically `%hash-name (:key($variable-to-store-value-in))`. 429 | # The hash can stay anonymous if you only need the values you extracted. 430 | sub key-of(% (:value($val), :qua($qua))) { 431 | say "Got val $val, $qua times."; 432 | } 433 | 434 | # Then call it with a hash: (you need to keep the brackets for it to be a hash) 435 | key-of({value => 'foo', qua => 1}); 436 | #key-of(%hash); # the same (for an equivalent `%hash`) 437 | 438 | ## The last expression of a sub is returned automatically 439 | # (though you may use the `return` keyword, of course): 440 | sub next-index($n) { 441 | $n + 1; 442 | } 443 | my $new-n = next-index(3); # $new-n is now 4 444 | 445 | # This is true for everything, except for the looping constructs 446 | # (due to performance reasons): there's reason to build a list 447 | # if we're just going to discard all the results. 448 | # If you still want to build one, you can use the `do` statement prefix: 449 | # (or the `gather` prefix, which we'll see later) 450 | sub list-of($n) { 451 | do for ^$n { # note the use of the range-to prefix operator `^` (`0..^N`) 452 | $_ # current loop iteration 453 | } 454 | } 455 | my @list3 = list-of(3); #=> (0, 1, 2) 456 | 457 | ## You can create a lambda with `-> {}` ("pointy block") or `{}` ("block") 458 | my &lambda = -> $argument { "The argument passed to this lambda is $argument" } 459 | # `-> {}` and `{}` are pretty much the same thing, except that the former can 460 | # take arguments, and that the latter can be mistaken as a hash by the parser. 461 | 462 | # We can, for example, add 3 to each value of an array using map: 463 | my @arrayplus3 = map({ $_ + 3 }, @array); # $_ is the implicit argument 464 | 465 | # A sub (`sub {}`) has different semantics than a block (`{}` or `-> {}`): 466 | # A block doesn't have a "function context" (though it can have arguments), 467 | # which means that if you return from it, 468 | # you're going to return from the parent function. Compare: 469 | sub is-in(@array, $elem) { 470 | # this will `return` out of the `is-in` sub 471 | # once the condition evaluated to True, the loop won't be run anymore 472 | map({ return True if $_ == $elem }, @array); 473 | } 474 | sub truthy-array(@array) { 475 | # this will produce an array of `True` and `False`: 476 | # (you can also say `anon sub` for "anonymous subroutine") 477 | map(sub ($i) { if $i { return True } else { return False } }, @array); 478 | # ^ the `return` only returns from the anonymous `sub` 479 | } 480 | 481 | # You can also use the "whatever star" to create an anonymous function 482 | # (it'll stop at the furthest operator in the current expression) 483 | my @arrayplus3 = map(*+3, @array); # `*+3` is the same as `{ $_ + 3 }` 484 | my @arrayplus3 = map(*+*+3, @array); # Same as `-> $a, $b { $a + $b + 3 }` 485 | # also `sub ($a, $b) { $a + $b + 3 }` 486 | say (*/2)(4); #=> 2 487 | # Immediatly execute the function Whatever created. 488 | say ((*+3)/5)(5); #=> 1.6 489 | # works even in parens ! 490 | 491 | # But if you need to have more than one argument (`$_`) 492 | # in a block (without wanting to resort to `-> {}`), 493 | # you can also use the implicit argument syntax, `$^` : 494 | map({ $^a + $^b + 3 }, @array); # equivalent to following: 495 | map(sub ($a, $b) { $a + $b + 3 }, @array); # (here with `sub`) 496 | 497 | # Note : those are sorted lexicographically. 498 | # `{ $^b / $^a }` is like `-> $a, $b { $b / $a }` 499 | 500 | ## About types... 501 | # Perl6 is gradually typed. This means you can specify the type 502 | # of your variables/arguments/return types, or you can omit them 503 | # and they'll default to "Any". 504 | # You obviously get access to a few base types, like Int and Str. 505 | # The constructs for declaring types are "class", "role", 506 | # which you'll see later. 507 | 508 | # For now, let us examine "subset": 509 | # a "subset" is a "sub-type" with additional checks. 510 | # For example: "a very big integer is an Int that's greater than 500" 511 | # You can specify the type you're subtyping (by default, Any), 512 | # and add additional checks with the "where" keyword: 513 | subset VeryBigInteger of Int where * > 500; 514 | 515 | ## Multiple Dispatch 516 | # Perl 6 can decide which variant of a `sub` to call based on the type of the 517 | # arguments, or on arbitrary preconditions, like with a type or a `where`: 518 | 519 | # with types 520 | multi sub sayit(Int $n) { # note the `multi` keyword here 521 | say "Number: $n"; 522 | } 523 | multi sayit(Str $s) { # a multi is a `sub` by default 524 | say "String: $s"; 525 | } 526 | sayit("foo"); # prints "String: foo" 527 | sayit(True); # fails at *compile time* with 528 | # "calling 'sayit' will never work with arguments of types ..." 529 | 530 | # with arbitrary precondition (remember subsets?): 531 | multi is-big(Int $n where * > 50) { "Yes !" } # using a closure 532 | multi is-big(Int $ where 10..50) { "Quite." } # Using smart-matching 533 | # (could use a regexp, etc) 534 | multi is-big(Int $) { "No" } 535 | 536 | subset Even of Int where * %% 2; 537 | 538 | multi odd-or-even(Even) { "Even" } # The main case using the type. 539 | # We don't name the argument. 540 | multi odd-or-even($) { "Odd" } # "else" 541 | 542 | # You can even dispatch based on a positional's argument presence ! 543 | multi with-or-without-you(:$with!) { # You need make it mandatory to 544 | # be able to dispatch against it. 545 | say "I can live ! Actually, I can't."; 546 | } 547 | multi with-or-without-you { 548 | say "Definitely can't live."; 549 | } 550 | # This is very, very useful for many purposes, like `MAIN` subs (covered later), 551 | # and even the language itself is using it in several places. 552 | # 553 | # - `is`, for example, is actually a `multi sub` named `trait_mod:`, 554 | # and it works off that. 555 | # - `is rw`, is simply a dispatch to a function with this signature: 556 | # sub trait_mod:(Routine $r, :$rw!) {} 557 | # 558 | # (commented because running this would be a terrible idea !) 559 | 560 | 561 | ### Scoping 562 | # In Perl 6, contrarily to many scripting languages (like Python, Ruby, PHP), 563 | # you are to declare your variables before using them. You know `my`. 564 | # (there are other declarators, `our`, `state`, ..., which we'll see later). 565 | # This is called "lexical scoping", where in inner blocks, 566 | # you can access variables from outer blocks. 567 | my $foo = 'Foo'; 568 | sub foo { 569 | my $bar = 'Bar'; 570 | sub bar { 571 | say "$foo $bar"; 572 | } 573 | &bar; # return the function 574 | } 575 | foo()(); #=> 'Foo Bar' 576 | 577 | # As you can see, `$foo` and `$bar` were captured. 578 | # But if we were to try and use `$bar` outside of `foo`, 579 | # the variable would be undefined (and you'd get a compile time error). 580 | 581 | # Perl 6 has another kind of scope : dynamic scope. 582 | # They use the twigil (composed sigil) `*` to mark dynamically-scoped variables: 583 | my $*a = 1; 584 | # Dyamically-scoped variables depend on the current call stack, 585 | # instead of the current block depth. 586 | sub foo { 587 | my $*foo = 1; 588 | bar(); # call `bar` in-place 589 | } 590 | sub bar { 591 | say $*foo; # `$*foo` will be looked in the call stack, and find `foo`'s, 592 | # even though the blocks aren't nested (they're call-nested). 593 | #=> 1 594 | } 595 | 596 | ### Object Model 597 | 598 | # You declare a class with the keyword `class`, fields with `has`, 599 | # methods with `method`. Every attribute that is private is named `$!attr`. 600 | # Immutable public attributes are named `$.attr` 601 | # (you can make them mutable with `is rw`) 602 | 603 | # Perl 6's object model ("SixModel") is very flexible, 604 | # and allows you to dynamically add methods, change semantics, etc ... 605 | # (this will not be covered here, and you should refer to the Synopsis). 606 | 607 | class A { 608 | has $.field; # `$.field` is immutable. 609 | # From inside the class, use `$!field` to modify it. 610 | has $.other-field is rw; # You can mark a public attribute `rw`. 611 | has Int $!private-field = 10; 612 | 613 | method get-value { 614 | $.field + $!private-field; 615 | } 616 | 617 | method set-value($n) { 618 | # $.field = $n; # As stated before, you can't use the `$.` immutable version. 619 | $!field = $n; # This works, because `$!` is always mutable. 620 | 621 | $.other-field = 5; # This works, because `$.other-field` is `rw`. 622 | } 623 | 624 | method !private-method { 625 | say "This method is private to the class !"; 626 | } 627 | }; 628 | 629 | # Create a new instance of A with $.field set to 5 : 630 | # Note: you can't set private-field from here (more later on). 631 | my $a = A.new(field => 5); 632 | $a.get-value; #=> 15 633 | #$a.field = 5; # This fails, because the `has $.field` is immutable 634 | $a.other-field = 10; # This, however, works, because the public field 635 | # is mutable (`rw`). 636 | 637 | ## Perl 6 also has inheritance (along with multiple inheritance) 638 | 639 | class A { 640 | has $.val; 641 | 642 | submethod not-inherited { 643 | say "This method won't be available on B."; 644 | say "This is most useful for BUILD, which we'll see later"; 645 | } 646 | 647 | method bar { $.val * 5 } 648 | } 649 | class B is A { # inheritance uses `is` 650 | method foo { 651 | say $.val; 652 | } 653 | 654 | method bar { $.val * 10 } # this shadows A's `bar` 655 | } 656 | 657 | # When you use `my T $var`, `$var` starts off with `T` itself in it, 658 | # so you can call `new` on it. 659 | # (`.=` is just the dot-call and the assignment operator: 660 | # `$a .= b` is the same as `$a = $a.b`) 661 | # Also note that `BUILD` (the method called inside `new`) 662 | # will set parent properties too, so you can pass `val => 5`. 663 | my B $b .= new(val => 5); 664 | 665 | # $b.not-inherited; # This won't work, for reasons explained above 666 | $b.foo; # prints 5 667 | $b.bar; #=> 50, since it calls B's `bar` 668 | 669 | ## Roles are supported too (also called Mixins in other languages) 670 | role PrintableVal { 671 | has $!counter = 0; 672 | method print { 673 | say $.val; 674 | } 675 | } 676 | 677 | # you "import" a mixin (a "role") with "does": 678 | class Item does PrintableVal { 679 | has $.val; 680 | 681 | # When `does`-ed, a `role` literally "mixes in" the class: 682 | # the methods and fields are put together, which means a class can access 683 | # the private fields/methods of its roles (but not the inverse !): 684 | method access { 685 | say $!counter++; 686 | } 687 | 688 | # However, this: 689 | # method print {} 690 | # is ONLY valid when `print` isn't a `multi` with the same dispatch. 691 | # (this means a parent class can shadow a child class's `multi print() {}`, 692 | # but it's an error if a role does) 693 | 694 | # NOTE: You can use a role as a class (with `is ROLE`). In this case, methods 695 | # will be shadowed, since the compiler will consider `ROLE` to be a class. 696 | } 697 | 698 | ### Exceptions 699 | # Exceptions are built on top of classes, in the package `X` (like `X::IO`). 700 | # Unlike many other languages, in Perl 6, you put the `CATCH` block *within* the 701 | # block to `try`. By default, a `try` has a `CATCH` block that catches 702 | # any exception (`CATCH { default {} }`). 703 | # You can redefine it using `when`s (and `default`) 704 | # to handle the exceptions you want: 705 | try { 706 | open 'foo'; 707 | CATCH { 708 | when X::AdHoc { say "unable to open file !" } 709 | # Any other exception will be re-raised, since we don't have a `default` 710 | # Basically, if a `when` matches (or there's a `default`) marks the exception as 711 | # "handled" so that it doesn't get re-thrown from the `CATCH`. 712 | # You still can re-throw the exception (see below) by hand. 713 | } 714 | } 715 | 716 | # You can throw an exception using `die`: 717 | die X::AdHoc.new(payload => 'Error !'); 718 | 719 | # You can access the last exception with `$!` (usually used in a `CATCH` block) 720 | 721 | # There are also some subtelties to exceptions. Some Perl 6 subs return a `Failure`, 722 | # which is a kind of "unthrown exception". They're not thrown until you tried to look 723 | # at their content, unless you call `.Bool`/`.defined` on them - then they're handled. 724 | # (the `.handled` method is `rw`, so you can mark it as `False` back yourself) 725 | # 726 | # You can throw a `Failure` using `fail`. Note that if the pragma `use fatal` is on, 727 | # `fail` will throw an exception (like `die`). 728 | fail "foo"; # We're not trying to access the value, so no problem. 729 | try { 730 | fail "foo"; 731 | CATCH { 732 | default { say "It threw because we tried to get the fail's value!" } 733 | } 734 | } 735 | 736 | # There is also another kind of exception: Control exceptions. 737 | # Those are "good" exceptions, which happen when you change your program's flow, 738 | # using operators like `return`, `next` or `last`. 739 | # You can "catch" those with `CONTROL` (not 100% working in Rakudo yet). 740 | 741 | ### Packages 742 | # Packages are a way to reuse code. Packages are like "namespaces", and any 743 | # element of the six model (`module`, `role`, `class`, `grammar`, `subset` 744 | # and `enum`) are actually packages. (Packages are the lowest common denominator) 745 | # Packages are important - especially as Perl is well-known for CPAN, 746 | # the Comprehensive Perl Archive Network. 747 | # You're not supposed to use the package keyword, usually: 748 | # you use `class Package::Name::Here;` to declare a class, 749 | # or if you only want to export variables/subs, you can use `module`: 750 | module Hello::World { # Bracketed form 751 | # If `Hello` doesn't exist yet, it'll just be a "stub", 752 | # that can be redeclared as something else later. 753 | # ... declarations here ... 754 | } 755 | unit module Parse::Text; # file-scoped form 756 | grammar Parse::Text::Grammar { # A grammar is a package, which you could `use` 757 | } 758 | 759 | # You can use a module (bring its declarations into scope) with `use` 760 | use JSON::Tiny; # if you installed Rakudo* or Panda, you'll have this module 761 | say from-json('[1]').perl; #=> [1] 762 | 763 | # As said before, any part of the six model is also a package. 764 | # Since `JSON::Tiny` uses (its own) `JSON::Tiny::Actions` class, you can use it: 765 | my $actions = JSON::Tiny::Actions.new; 766 | 767 | # We'll see how to export variables and subs in the next part: 768 | 769 | ### Declarators 770 | # In Perl 6, you get different behaviors based on how you declare a variable. 771 | # You've already seen `my` and `has`, we'll now explore the others. 772 | 773 | ## * `our` (happens at `INIT` time -- see "Phasers" below) 774 | # It's like `my`, but it also creates a package variable. 775 | # (All packagish things (`class`, `role`, etc) are `our` by default) 776 | module Foo::Bar { 777 | our $n = 1; # note: you can't put a type constraint on an `our` variable 778 | our sub inc { 779 | our sub available { # If you try to make inner `sub`s `our`... 780 | # Better know what you're doing (Don't !). 781 | say "Don't do that. Seriously. You'd get burned."; 782 | } 783 | my sub unavailable { # `my sub` is the default 784 | say "Can't access me from outside, I'm my !"; 785 | } 786 | } 787 | 788 | say ++$n; # lexically-scoped variables are still available 789 | } 790 | say $Foo::Bar::n; #=> 1 791 | Foo::Bar::inc; #=> 2 792 | Foo::Bar::inc; #=> 3 793 | 794 | ## * `constant` (happens at `BEGIN` time) 795 | # You can use the `constant` keyword to declare a compile-time variable/symbol: 796 | constant Pi = 3.14; 797 | constant $var = 1; 798 | 799 | # And if you're wondering, yes, it can also contain infinite lists. 800 | constant why-not = 5, 15 ... *; 801 | say why-not[^5]; #=> 5 15 25 35 45 802 | 803 | ## * `state` (happens at run time, but only once) 804 | # State variables are only initialized one time 805 | # (they exist in other langages such as C as `static`) 806 | sub fixed-rand { 807 | state $val = rand; 808 | say $rand; 809 | } 810 | fixed-rand for ^10; # will print the same number 10 times 811 | 812 | # Note, however, that they exist separately in different enclosing contexts. 813 | # If you declare a function with a `state` within a loop, it'll re-create the 814 | # variable for each iteration of the loop. See: 815 | for ^5 -> $a { 816 | sub foo { 817 | state $val = rand; # This will be a different value for every value of `$a` 818 | } 819 | for ^5 -> $b { 820 | say foo; # This will print the same value 5 times, but only 5. 821 | # Next iteration will re-run `rand`. 822 | } 823 | } 824 | 825 | 826 | 827 | ### Phasers 828 | # Phasers in Perl 6 are blocks that happen at determined points of time in your 829 | # program. When the program is compiled, when a for loop runs, when you leave a 830 | # block, when an exception gets thrown ... (`CATCH` is actually a phaser !) 831 | # Some of them can be used for their return values, some of them can't 832 | # (those that can have a "[*]" in the beginning of their explanation text). 833 | # Let's have a look ! 834 | 835 | ## * Compile-time phasers 836 | BEGIN { say "[*] Runs at compile time, as soon as possible, only once" } 837 | CHECK { say "[*] Runs at compile time, as late as possible, only once" } 838 | 839 | ## * Run-time phasers 840 | INIT { say "[*] Runs at run time, as soon as possible, only once" } 841 | END { say "Runs at run time, as late as possible, only once" } 842 | 843 | ## * Block phasers 844 | ENTER { say "[*] Runs everytime you enter a block, repeats on loop blocks" } 845 | LEAVE { say "Runs everytime you leave a block, even when an exception 846 | happened. Repeats on loop blocks." } 847 | 848 | PRE { say "Asserts a precondition at every block entry, 849 | before ENTER (especially useful for loops)" } 850 | # exemple: 851 | for 0..2 { 852 | PRE { $_ > 1 } # This is going to blow up with "Precondition failed" 853 | } 854 | 855 | POST { say "Asserts a postcondition at every block exit, 856 | after LEAVE (especially useful for loops)" } 857 | for 0..2 { 858 | POST { $_ < 2 } # This is going to blow up with "Postcondition failed" 859 | } 860 | 861 | ## * Block/exceptions phasers 862 | sub { 863 | KEEP { say "Runs when you exit a block successfully (without throwing an exception)" } 864 | UNDO { say "Runs when you exit a block unsuccessfully (by throwing an exception)" } 865 | } 866 | 867 | ## * Loop phasers 868 | for ^5 { 869 | FIRST { say "[*] The first time the loop is run, before ENTER" } 870 | NEXT { say "At loop continuation time, before LEAVE" } 871 | LAST { say "At loop termination time, after LEAVE" } 872 | } 873 | 874 | ## * Role/class phasers 875 | COMPOSE { "When a role is composed into a class. /!\ NOT YET IMPLEMENTED" } 876 | 877 | # They allow for cute tricks or clever code ...: 878 | say "This code took " ~ (time - CHECK time) ~ "s to compile"; 879 | 880 | # ... or clever organization: 881 | sub do-db-stuff { 882 | $db.start-transaction; # start a new transaction 883 | KEEP $db.commit; # commit the transaction if all went well 884 | UNDO $db.rollback; # or rollback if all hell broke loose 885 | } 886 | 887 | ### Statement prefixes 888 | # Those act a bit like phasers: they affect the behavior of the following code. 889 | # Though, they run in-line with the executable code, so they're in lowercase. 890 | # (`try` and `start` are theoretically in that list, but explained somewhere else) 891 | # Note: all of these (except start) don't need explicit brackets `{` and `}`. 892 | 893 | # - `do` (that you already saw) - runs a block or a statement as a term 894 | # You can't normally use a statement as a value (or "term"): 895 | # 896 | # my $value = if True { 1 } # `if` is a statement - parse error 897 | # 898 | # This works: 899 | my $a = do if True { 5 } # with `do`, `if` is now a term. 900 | 901 | # - `once` - Makes sure a piece of code only runs once 902 | for ^5 { once say 1 }; #=> 1 903 | # Only prints ... once. 904 | # Like `state`, they're cloned per-scope 905 | for ^5 { sub { once say 1 }() } #=> 1 1 1 1 1 906 | # Prints once per lexical scope 907 | 908 | # - `gather` - Co-routine thread 909 | # Gather allows you to `take` several values in an array, 910 | # much like `do`, but allows you to take any expression. 911 | say gather for ^5 { 912 | take $_ * 3 - 1; 913 | take $_ * 3 + 1; 914 | } #=> -1 1 2 4 5 7 8 10 11 13 915 | say join ',', gather if False { 916 | take 1; 917 | take 2; 918 | take 3; 919 | } # Doesn't print anything. 920 | 921 | # - `eager` - Evaluate statement eagerly (forces eager context) 922 | # Don't try this at home: 923 | # 924 | # eager 1..*; # this will probably hang for a while (and might crash ...). 925 | # 926 | # But consider: 927 | constant thrice = gather for ^3 { say take $_ }; # Doesn't print anything 928 | # versus: 929 | constant thrice = eager gather for ^3 { say take $_ }; #=> 0 1 2 930 | 931 | # - `lazy` - Defer actual evaluation until value is fetched (forces lazy context) 932 | # Not yet implemented !! 933 | 934 | # - `sink` - An `eager` that discards the results (forces sink context) 935 | constant nilthingie = sink for ^3 { .say } #=> 0 1 2 936 | say nilthingie.perl; #=> Nil 937 | 938 | # - `quietly` - Supresses warnings 939 | # Not yet implemented ! 940 | 941 | # - `contend` - Attempts side effects under STM 942 | # Not yet implemented ! 943 | 944 | ### More operators thingies ! 945 | 946 | ## Everybody loves operators ! Let's get more of them 947 | 948 | # The precedence list can be found here: 949 | # http://perlcabal.org/syn/S03.html#Operator_precedence 950 | # But first, we need a little explanation about associativity: 951 | 952 | # * Binary operators: 953 | $a ! $b ! $c; # with a left-associative `!`, this is `($a ! $b) ! $c` 954 | $a ! $b ! $c; # with a right-associative `!`, this is `$a ! ($b ! $c)` 955 | $a ! $b ! $c; # with a non-associative `!`, this is illegal 956 | $a ! $b ! $c; # with a chain-associative `!`, this is `($a ! $b) and ($b ! $c)` 957 | $a ! $b ! $c; # with a list-associative `!`, this is `infix:<>` 958 | 959 | # * Unary operators: 960 | !$a! # with left-associative `!`, this is `(!$a)!` 961 | !$a! # with right-associative `!`, this is `!($a!)` 962 | !$a! # with non-associative `!`, this is illegal 963 | 964 | ## Create your own operators ! 965 | # Okay, you've been reading all of that, so I guess I should try 966 | # to show you something exciting. 967 | # I'll tell you a little secret (or not-so-secret): 968 | # In Perl 6, all operators are actually just funny-looking subroutines. 969 | 970 | # You can declare an operator just like you declare a sub: 971 | sub prefix:($winner) { # refer to the operator categories 972 | # (yes, it's the "words operator" `<>`) 973 | say "$winner Won !"; 974 | } 975 | win "The King"; #=> The King Won ! 976 | # (prefix is before) 977 | 978 | # you can still call the sub with its "full name" 979 | say prefix:(True); #=> False 980 | 981 | sub postfix:(Int $n) { 982 | [*] 2..$n; # using the reduce meta-operator ... See below ;-) ! 983 | } 984 | say 5!; #=> 120 985 | # Postfix operators (after) have to come *directly* after the term. 986 | # No whitespace. You can use parentheses to disambiguate, i.e. `(5!)!` 987 | 988 | 989 | sub infix:(Int $n, Block $r) { # infix in the middle 990 | for ^$n { 991 | $r(); # You need the explicit parentheses to call the function in `$r`, 992 | # else you'd be referring at the variable itself, like with `&r`. 993 | } 994 | } 995 | 3 times -> { say "hello" }; #=> hello 996 | #=> hello 997 | #=> hello 998 | # You're very recommended to put spaces 999 | # around your infix operator calls. 1000 | 1001 | # For circumfix and post-circumfix ones 1002 | sub circumfix:<[ ]>(Int $n) { 1003 | $n ** $n 1004 | } 1005 | say [5]; #=> 3125 1006 | # circumfix is around. Again, no whitespace. 1007 | 1008 | sub postcircumfix:<{ }>(Str $s, Int $idx) { 1009 | # post-circumfix is 1010 | # "after a term, around something" 1011 | $s.substr($idx, 1); 1012 | } 1013 | say "abc"{1}; #=> b 1014 | # after the term `"abc"`, and around the index (1) 1015 | 1016 | # This really means a lot -- because everything in Perl 6 uses this. 1017 | # For example, to delete a key from a hash, you use the `:delete` adverb 1018 | # (a simple named argument underneath): 1019 | %h{$key}:delete; 1020 | # equivalent to: 1021 | postcircumfix:<{ }>(%h, $key, :delete); # (you can call operators like that) 1022 | # It's *all* using the same building blocks! 1023 | # Syntactic categories (prefix infix ...), named arguments (adverbs), ..., 1024 | # - used to build the language - are available to you. 1025 | 1026 | # (you are, obviously, recommended against making an operator out of 1027 | # *everything* -- with great power comes great responsibility) 1028 | 1029 | ## Meta operators ! 1030 | # Oh boy, get ready. Get ready, because we're delving deep 1031 | # into the rabbit's hole, and you probably won't want to go 1032 | # back to other languages after reading that. 1033 | # (I'm guessing you don't want to already at that point). 1034 | # Meta-operators, as their name suggests, are *composed* operators. 1035 | # Basically, they're operators that apply another operator. 1036 | 1037 | ## * Reduce meta-operator 1038 | # It's a prefix meta-operator that takes a binary function and 1039 | # one or many lists. If it doesn't get passed any argument, 1040 | # it either returns a "default value" for this operator 1041 | # (a meaningless value) or `Any` if there's none (examples below). 1042 | # 1043 | # Otherwise, it pops an element from the list(s) one at a time, and applies 1044 | # the binary function to the last result (or the list's first element) 1045 | # and the popped element. 1046 | # 1047 | # To sum a list, you could use the reduce meta-operator with `+`, i.e.: 1048 | say [+] 1, 2, 3; #=> 6 1049 | # equivalent to `(1+2)+3` 1050 | say [*] 1..5; #=> 120 1051 | # equivalent to `((((1*2)*3)*4)*5)`. 1052 | 1053 | # You can reduce with any operator, not just with mathematical ones. 1054 | # For example, you could reduce with `//` to get 1055 | # the first defined element of a list: 1056 | say [//] Nil, Any, False, 1, 5; #=> False 1057 | # (Falsey, but still defined) 1058 | 1059 | 1060 | # Default value examples: 1061 | say [*] (); #=> 1 1062 | say [+] (); #=> 0 1063 | # meaningless values, since N*1=N and N+0=N. 1064 | say [//]; #=> (Any) 1065 | # There's no "default value" for `//`. 1066 | 1067 | # You can also call it with a function you made up, using double brackets: 1068 | sub add($a, $b) { $a + $b } 1069 | say [[&add]] 1, 2, 3; #=> 6 1070 | 1071 | ## * Zip meta-operator 1072 | # This one is an infix meta-operator than also can be used as a "normal" operator. 1073 | # It takes an optional binary function (by default, it just creates a pair), 1074 | # and will pop one value off of each array and call its binary function on these 1075 | # until it runs out of elements. It returns an array with all of these new elements. 1076 | (1, 2) Z (3, 4); # ((1, 3), (2, 4)), since by default, the function makes an array 1077 | 1..3 Z+ 4..6; # (5, 7, 9), using the custom infix:<+> function 1078 | 1079 | # Since `Z` is list-associative (see the list above), 1080 | # you can use it on more than one list 1081 | (True, False) Z|| (False, False) Z|| (False, False); # (True, False) 1082 | 1083 | # And, as it turns out, you can also use the reduce meta-operator with it: 1084 | [Z||] (True, False), (False, False), (False, False); # (True, False) 1085 | 1086 | 1087 | ## And to end the operator list: 1088 | 1089 | ## * Sequence operator 1090 | # The sequence operator is one of Perl 6's most powerful features: 1091 | # it's composed of first, on the left, the list you want Perl 6 to deduce from 1092 | # (and might include a closure), and on the right, a value or the predicate 1093 | # that says when to stop (or Whatever for a lazy infinite list). 1094 | my @list = 1, 2, 3 ... 10; # basic deducing 1095 | #my @list = 1, 3, 6 ... 10; # this dies because Perl 6 can't figure out the end 1096 | my @list = 1, 2, 3 ...^ 10; # as with ranges, you can exclude the last element 1097 | # (the iteration when the predicate matches). 1098 | my @list = 1, 3, 9 ... * > 30; # you can use a predicate 1099 | # (with the Whatever Star, here). 1100 | my @list = 1, 3, 9 ... { $_ > 30 }; # (equivalent to the above) 1101 | 1102 | my @fib = 1, 1, *+* ... *; # lazy infinite list of fibonacci series, 1103 | # computed using a closure! 1104 | my @fib = 1, 1, -> $a, $b { $a + $b } ... *; # (equivalent to the above) 1105 | my @fib = 1, 1, { $^a + $^b } ... *; #(... also equivalent to the above) 1106 | # $a and $b will always take the previous values, meaning here 1107 | # they'll start with $a = 1 and $b = 1 (values we set by hand). 1108 | # then $a = 1 and $b = 2 (result from previous $a+$b), and so on. 1109 | 1110 | say @fib[^10]; #=> 1 1 2 3 5 8 13 21 34 55 1111 | # (using a range as the index) 1112 | # Note : as for ranges, once reified, elements aren't re-calculated. 1113 | # That's why `@primes[^100]` will take a long time the first time you print 1114 | # it, then be instant. 1115 | 1116 | ### Regular Expressions 1117 | # I'm sure a lot of you have been waiting for this one. 1118 | # Well, now that you know a good deal of Perl 6 already, we can get started. 1119 | # First off, you'll have to forget about "PCRE regexps" (perl-compatible regexps). 1120 | # 1121 | # IMPORTANT: Don't skip them because you know PCRE. They're different. 1122 | # Some things are the same (like `?`, `+`, and `*`), 1123 | # but sometimes the semantics change (`|`). 1124 | # Make sure you read carefully, because you might trip over a new behavior. 1125 | # 1126 | # Perl 6 has many features related to RegExps. After all, Rakudo parses itself. 1127 | # We're first going to look at the syntax itself, 1128 | # then talk about grammars (PEG-like), differences between 1129 | # `token`, `regex` and `rule` declarators, and some more. 1130 | # Side note: you still have access to PCRE regexps using the `:P5` modifier. 1131 | # (we won't be discussing this in this tutorial, however) 1132 | # 1133 | # In essence, Perl 6 natively implements PEG ("Parsing Expression Grammars"). 1134 | # The pecking order for ambiguous parses is determined by a multi-level 1135 | # tie-breaking test: 1136 | # - Longest token matching. `foo\s+` beats `foo` (by 2 or more positions) 1137 | # - Longest literal prefix. `food\w*` beats `foo\w*` (by 1) 1138 | # - Declaration from most-derived to less derived grammars 1139 | # (grammars are actually classes) 1140 | # - Earliest declaration wins 1141 | say so 'a' ~~ /a/; #=> True 1142 | say so 'a' ~~ / a /; # More readable with some spaces! 1143 | 1144 | # In all our examples, we're going to use the smart-matching operator against 1145 | # a regexp. We're converting the result using `so`, but in fact, it's 1146 | # returning a `Match` object. They know how to respond to list indexing, 1147 | # hash indexing, and return the matched string. 1148 | # The results of the match are available as `$/` (implicitly lexically-scoped). 1149 | # You can also use the capture variables (`$0`, `$1`, ... starting at 0, not 1 !). 1150 | # 1151 | # You can also note that `~~` does not perform start/end checking 1152 | # (meaning the regexp can be matched with just one char of the string), 1153 | # we're going to explain later how you can do it. 1154 | 1155 | # In Perl 6, you can have any alphanumeric as a literal, 1156 | # everything else has to be escaped, using a backslash or quotes. 1157 | say so 'a|b' ~~ / a '|' b /; # `True`. Wouln't mean the same if `|` wasn't escaped 1158 | say so 'a|b' ~~ / a \| b /; # `True`. Another way to escape it. 1159 | 1160 | # The whitespace in a regexp is actually not significant, 1161 | # unless you use the `:s` (`:sigspace`, significant space) modifier. 1162 | say so 'a b c' ~~ / a b c /; # `False`. Space is not significant here 1163 | say so 'a b c' ~~ /:s a b c /; # `True`. We added the modifier `:s` here. 1164 | 1165 | # It is, however, important as for how modifiers (that you're gonna see just below) 1166 | # are applied ... 1167 | 1168 | ## Quantifying - `?`, `+`, `*` and `**`. 1169 | # - `?` - 0 or 1 1170 | so 'ac' ~~ / a b c /; # `False` 1171 | so 'ac' ~~ / a b? c /; # `True`, the "b" matched 0 times. 1172 | so 'abc' ~~ / a b? c /; # `True`, the "b" matched 1 time. 1173 | 1174 | # ... As you read just before, whitespace is important because it determines 1175 | # which part of the regexp is the target of the modifier: 1176 | so 'def' ~~ / a b c? /; # `False`. Only the `c` is optional 1177 | so 'def' ~~ / ab?c /; # `False`. Whitespace is not significant 1178 | so 'def' ~~ / 'abc'? /; # `True`. The whole "abc" group is optional. 1179 | 1180 | # Here (and below) the quantifier applies only to the `b` 1181 | 1182 | # - `+` - 1 or more 1183 | so 'ac' ~~ / a b+ c /; # `False`; `+` wants at least one matching 1184 | so 'abc' ~~ / a b+ c /; # `True`; one is enough 1185 | so 'abbbbc' ~~ / a b+ c /; # `True`, matched 4 "b"s 1186 | 1187 | # - `*` - 0 or more 1188 | so 'ac' ~~ / a b* c /; # `True`, they're all optional. 1189 | so 'abc' ~~ / a b* c /; # `True` 1190 | so 'abbbbc' ~~ / a b* c /; # `True` 1191 | so 'aec' ~~ / a b* c /; # `False`. "b"(s) are optional, not replaceable. 1192 | 1193 | # - `**` - (Unbound) Quantifier 1194 | # If you squint hard enough, you might understand 1195 | # why exponentation is used for quantity. 1196 | so 'abc' ~~ / a b ** 1 c /; # `True` (exactly one time) 1197 | so 'abc' ~~ / a b ** 1..3 c /; # `True` (one to three times) 1198 | so 'abbbc' ~~ / a b ** 1..3 c /; # `True` 1199 | so 'abbbbbbc' ~~ / a b ** 1..3 c /; # `False` (too much) 1200 | so 'abbbbbbc' ~~ / a b ** 3..* c /; # `True` (infinite ranges are okay) 1201 | 1202 | # - `<[]>` - Character classes 1203 | # Character classes are the equivalent of PCRE's `[]` classes, but 1204 | # they use a more perl6-ish syntax: 1205 | say 'fooa' ~~ / f <[ o a ]>+ /; #=> 'fooa' 1206 | # You can use ranges: 1207 | say 'aeiou' ~~ / a <[ e..w ]> /; #=> 'ae' 1208 | # Just like in normal regexes, if you want to use a special character, escape it 1209 | # (the last one is escaping a space) 1210 | say 'he-he !' ~~ / 'he-' <[ a..z \! \ ]> + /; #=> 'he-he !' 1211 | # You'll get a warning if you put duplicate names 1212 | # (which has the nice effect of catching the wrote quoting:) 1213 | 'he he' ~~ / <[ h e ' ' ]> /; # Warns "Repeated characters found in characters class" 1214 | 1215 | # You can also negate them ... (equivalent to `[^]` in PCRE) 1216 | so 'foo' ~~ / <-[ f o ]> + /; # False 1217 | 1218 | # ... and compose them: : 1219 | so 'foo' ~~ / <[ a..z ] - [ f o ]> + /; # False (any letter except f and o) 1220 | so 'foo' ~~ / <-[ a..z ] + [ f o ]> + /; # True (no letter except f and o) 1221 | so 'foo!' ~~ / <-[ a..z ] + [ f o ]> + /; # True (the + doesn't replace the left part) 1222 | 1223 | ## Grouping and capturing 1224 | # Group: you can group parts of your regexp with `[]`. 1225 | # These groups are *not* captured (like PCRE's `(?:)`). 1226 | so 'abc' ~~ / a [ b ] c /; # `True`. The grouping does pretty much nothing 1227 | so 'foo012012bar' ~~ / foo [ '01' <[0..9]> ] + bar /; 1228 | # The previous line returns `True`. 1229 | # We match the "012" 1 or more time (the `+` was applied to the group). 1230 | 1231 | # But this does not go far enough, because we can't actually get back what 1232 | # we matched. 1233 | # Capture: We can actually *capture* the results of the regexp, using parentheses. 1234 | so 'fooABCABCbar' ~~ / foo ( 'A' <[A..Z]> 'C' ) + bar /; # `True`. (using `so` here, `$/` below) 1235 | 1236 | # So, starting with the grouping explanations. 1237 | # As we said before, our `Match` object is available as `$/`: 1238 | say $/; # Will print some weird stuff (we'll explain) (or "Nil" if nothing matched). 1239 | 1240 | # As we also said before, it has array indexing: 1241 | say $/[0]; #=> 「ABC」 「ABC」 1242 | # These weird brackets are `Match` objects. 1243 | # Here, we have an array of these. 1244 | say $0; # The same as above. 1245 | 1246 | # Our capture is `$0` because it's the first and only one capture in the regexp. 1247 | # You might be wondering why it's an array, and the answer is simple: 1248 | # Some capture (indexed using `$0`, `$/[0]` or a named one) will be an array 1249 | # IFF it can have more than one element 1250 | # (so, with `*`, `+` and `**` (whatever the operands), but not with `?`). 1251 | # Let's use examples to see that: 1252 | so 'fooABCbar' ~~ / foo ( A B C )? bar /; # `True` 1253 | say $/[0]; #=> 「ABC」 1254 | say $0.WHAT; #=> (Match) 1255 | # It can't be more than one, so it's only a single match object. 1256 | so 'foobar' ~~ / foo ( A B C )? bar /; #=> True 1257 | say $0.WHAT; #=> (Any) 1258 | # This capture did not match, so it's empty 1259 | so 'foobar' ~~ / foo ( A B C ) ** 0..1 bar /; # `True` 1260 | say $0.WHAT; #=> (Array) 1261 | # A specific quantifier will always capture an Array, 1262 | # may it be a range or a specific value (even 1). 1263 | 1264 | # The captures are indexed per nesting. This means a group in a group will be nested 1265 | # under its parent group: `$/[0][0]`, for this code: 1266 | 'hello-~-world' ~~ / ( 'hello' ( <[ \- \~ ]> + ) ) 'world' /; 1267 | say $/[0].Str; #=> hello~ 1268 | say $/[0][0].Str; #=> ~ 1269 | 1270 | # This stems from a very simple fact: `$/` does not contain strings, integers or arrays, 1271 | # it only contains match objects. These contain the `.list`, `.hash` and `.Str` methods. 1272 | # (but you can also just use `match` for hash access 1273 | # and `match[idx]` for array access) 1274 | say $/[0].list.perl; #=> (Match.new(...),).list 1275 | # We can see it's a list of Match objects. Those contain 1276 | # a bunch of infos: where the match started/ended, 1277 | # the "ast" (see actions later), etc. 1278 | # You'll see named capture below with grammars. 1279 | 1280 | ## Alternatives - the `or` of regexps 1281 | # WARNING: They are DIFFERENT from PCRE regexps. 1282 | so 'abc' ~~ / a [ b | y ] c /; # `True`. Either "b" or "y". 1283 | so 'ayc' ~~ / a [ b | y ] c /; # `True`. Obviously enough ... 1284 | 1285 | # The difference between this `|` and the one you're used to is LTM. 1286 | # LTM means "Longest Token Matching". This means that the engine will always 1287 | # try to match as much as possible in the strng 1288 | 'foo' ~~ / fo | foo /; # `foo`, because it's longer. 1289 | # To decide which part is the "longest", it first splits the regex in two parts: 1290 | # The "declarative prefix" (the part that can be statically analyzed) 1291 | # and the procedural parts. 1292 | # Declarative prefixes include alternations (`|`), conjuctions (`&`), 1293 | # sub-rule calls (not yet introduced), literals, characters classes and quantifiers. 1294 | # The latter include everything else: back-references, code assertions, 1295 | # and other things that can't traditionnaly be represented by normal regexps. 1296 | # 1297 | # Then, all the alternatives are tried at once, and the longest wins. 1298 | # Exemples: 1299 | # DECLARATIVE | PROCEDURAL 1300 | / 'foo' \d+ [ || ] /; 1301 | # DECLARATIVE (nested groups are not a problem) 1302 | / \s* [ \w & b ] [ c | d ] /; 1303 | # However, closures and recursion (of named regexps) are procedural. 1304 | # ... There are also more complicated rules, like specificity 1305 | # (literals win over character classes) 1306 | 1307 | # Note: the first-matching `or` still exists, but is now spelled `||` 1308 | 'foo' ~~ / fo || foo /; # `fo` now. 1309 | 1310 | 1311 | 1312 | 1313 | ### Extra: the MAIN subroutime 1314 | # The `MAIN` subroutine is called when you run a Perl 6 file directly. 1315 | # It's very powerful, because Perl 6 actually parses the arguments 1316 | # and pass them as such to the sub. It also handles named argument (`--foo`) 1317 | # and will even go as far as to autogenerate a `--help` 1318 | sub MAIN($name) { say "Hello, $name !" } 1319 | # This produces: 1320 | # $ perl6 cli.pl 1321 | # Usage: 1322 | # t.pl 1323 | 1324 | # And since it's a regular Perl 6 sub, you can haz multi-dispatch: 1325 | # (using a "Bool" for the named argument so that we can do `--replace` 1326 | # instead of `--replace=1`) 1327 | subset File of Str where *.IO.d; # convert to IO object to check the file exists 1328 | 1329 | multi MAIN('add', $key, $value, Bool :$replace) { ... } 1330 | multi MAIN('remove', $key) { ... } 1331 | multi MAIN('import', File, Str :$as) { ... } # omitting parameter name 1332 | # This produces: 1333 | # $ perl6 cli.pl 1334 | # Usage: 1335 | # t.pl [--replace] add 1336 | # t.pl remove 1337 | # t.pl [--as=] import (File) 1338 | # As you can see, this is *very* powerful. 1339 | # It even went as far as to show inline the constants. 1340 | # (the type is only displayed if the argument is `$`/is named) 1341 | 1342 | ### 1343 | ### APPENDIX A: 1344 | ### 1345 | ### List of things 1346 | ### 1347 | 1348 | # It's considered by now you know the Perl6 basics. 1349 | # This section is just here to list some common operations, 1350 | # but which are not in the "main part" of the tutorial to bloat it up 1351 | 1352 | ## Operators 1353 | 1354 | 1355 | ## * Sort comparison 1356 | # They return one value of the `Order` enum : `Less`, `Same` and `More` 1357 | # (which numerify to -1, 0 or +1). 1358 | 1 <=> 4; # sort comparison for numerics 1359 | 'a' leg 'b'; # sort comparison for string 1360 | $obj eqv $obj2; # sort comparison using eqv semantics 1361 | 1362 | ## * Generic ordering 1363 | 3 before 4; # True 1364 | 'b' after 'a'; # True 1365 | 1366 | ## * Short-circuit default operator 1367 | # Like `or` and `||`, but instead returns the first *defined* value : 1368 | say Any // Nil // 0 // 5; #=> 0 1369 | 1370 | ## * Short-circuit exclusive or (XOR) 1371 | # Returns `True` if one (and only one) of its arguments is true 1372 | say True ^^ False; #=> True 1373 | ## * Flip Flop 1374 | # The flip flop operators (`ff` and `fff`, equivalent to P5's `..`/`...`). 1375 | # are operators that take two predicates to test: 1376 | # They are `False` until their left side returns `True`, then are `True` until 1377 | # their right side returns `True`. 1378 | # Like for ranges, you can exclude the iteration when it became `True`/`False` 1379 | # by using `^` on either side. 1380 | # Let's start with an example : 1381 | for { 1382 | # by default, `ff`/`fff` smart-match (`~~`) against `$_`: 1383 | if 'met' ^ff 'meet' { # Won't enter the if for "met" 1384 | # (explained in details below). 1385 | .say 1386 | } 1387 | 1388 | if rand == 0 ff rand == 1 { # compare variables other than `$_` 1389 | say "This ... probably will never run ..."; 1390 | } 1391 | } 1392 | # This will print "young hero we shall meet" (excluding "met"): 1393 | # the flip-flop will start returning `True` when it first encounters "met" 1394 | # (but will still return `False` for "met" itself, due to the leading `^` 1395 | # on `ff`), until it sees "meet", which is when it'll start returning `False`. 1396 | 1397 | # The difference between `ff` (awk-style) and `fff` (sed-style) is that 1398 | # `ff` will test its right side right when its left side changes to `True`, 1399 | # and can get back to `False` right away 1400 | # (*except* it'll be `True` for the iteration that matched) - 1401 | # While `fff` will wait for the next iteration to 1402 | # try its right side, once its left side changed: 1403 | .say if 'B' ff 'B' for ; #=> B B 1404 | # because the right-hand-side was tested 1405 | # directly (and returned `True`). 1406 | # "B"s are printed since it matched that time 1407 | # (it just went back to `False` right away). 1408 | .say if 'B' fff 'B' for ; #=> B C B 1409 | # The right-hand-side wasn't tested until 1410 | # `$_` became "C" 1411 | # (and thus did not match instantly). 1412 | 1413 | # A flip-flop can change state as many times as needed: 1414 | for { 1415 | .say if $_ eq 'start' ^ff^ $_ eq 'stop'; # exclude both "start" and "stop", 1416 | #=> "print it print again" 1417 | } 1418 | 1419 | # you might also use a Whatever Star, 1420 | # which is equivalent to `True` for the left side or `False` for the right: 1421 | for (1, 3, 60, 3, 40, 60) { # Note: the parenthesis are superfluous here 1422 | # (sometimes called "superstitious parentheses") 1423 | .say if $_ > 50 ff *; # Once the flip-flop reaches a number greater than 50, 1424 | # it'll never go back to `False` 1425 | #=> 60 3 40 60 1426 | } 1427 | 1428 | # You can also use this property to create an `If` 1429 | # that'll not go through the first time : 1430 | for { 1431 | .say if * ^ff *; # the flip-flop is `True` and never goes back to `False`, 1432 | # but the `^` makes it *not run* on the first iteration 1433 | #=> b c 1434 | } 1435 | 1436 | 1437 | # - `===` is value identity and uses `.WHICH` on the objects to compare them 1438 | # - `=:=` is container identity and uses `VAR()` on the objects to compare them 1439 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "language-perl6fe", 3 | "main": "./lib/main", 4 | "version": "2.0.0", 5 | "description": "Perl 6 Language Highlighter Forgotten Edition (Deprecated)", 6 | "engines": { 7 | "atom": "*", 8 | "node": "*" 9 | }, 10 | "homepage": "http://madcapjake.github.io/language-perl6fe", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/madcapjake/language-perl6fe.git" 14 | }, 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/madcapjake/language-perl6fe/issues" 18 | }, 19 | "package-deps": [ 20 | "language-perl6" 21 | ], 22 | "dependencies": { 23 | "atom-package-deps": "latest" 24 | }, 25 | "devDependencies": { 26 | "coffeelint": "^1.10.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /settings/language-perl6fe.cson: -------------------------------------------------------------------------------- 1 | '.source.perl6fe': 2 | 'editor': 3 | 'foldEndPattern': '(\\*/|^\\s*(\\}|\\]|\\)))' 4 | 'increaseIndentPattern': '^.*\\{\\}?\\s*$' 5 | 'decreaseIndentPattern': '^\\s*\\}' 6 | 'commentStart': '# ' 7 | 'nonWordCharacters': '/\\()"\':,.;<>~#^*|+=[]{}`?!' 8 | -------------------------------------------------------------------------------- /spec/grammar-perl6fe-spec.coffee: -------------------------------------------------------------------------------- 1 | describe "Perl 6 FE grammar", -> 2 | it "fake test to make travis not complain", -> 3 | tokens = null 4 | expect(tokens).toBeNull() 5 | --------------------------------------------------------------------------------