1f14f4646Smrg;; Copyright (c) 2007,2008 Paulo Cesar Pereira de Andrade 2f14f4646Smrg;; 3f14f4646Smrg;; Permission is hereby granted, free of charge, to any person obtaining a 4f14f4646Smrg;; copy of this software and associated documentation files (the "Software"), 5f14f4646Smrg;; to deal in the Software without restriction, including without limitation 6f14f4646Smrg;; the rights to use, copy, modify, merge, publish, distribute, sublicense, 7f14f4646Smrg;; and/or sell copies of the Software, and to permit persons to whom the 8f14f4646Smrg;; Software is furnished to do so, subject to the following conditions: 9f14f4646Smrg;; 10f14f4646Smrg;; The above copyright notice and this permission notice (including the next 11f14f4646Smrg;; paragraph) shall be included in all copies or substantial portions of the 12f14f4646Smrg;; Software. 13f14f4646Smrg;; 14f14f4646Smrg;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15f14f4646Smrg;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16f14f4646Smrg;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17f14f4646Smrg;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18f14f4646Smrg;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19f14f4646Smrg;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20f14f4646Smrg;; DEALINGS IN THE SOFTWARE. 21f14f4646Smrg;; 22f14f4646Smrg;; Author: Paulo Cesar Pereira de Andrade 23f14f4646Smrg;; 24f14f4646Smrg 25f14f4646Smrg;; Perl syntax and indentation mode 26f14f4646Smrg;; Based on the C/C++ and Lisp modes. Attempting to make simple 27f14f4646Smrg;; syntax/indentation rules, that should work correctly with most 28f14f4646Smrg;; perl code. 29f14f4646Smrg 30f14f4646Smrg;; *cont-indent* is somewhat buggy, that if pressing C-A,Tab, will 31f14f4646Smrg;; not generate the same output as when normally typing the expression. 32f14f4646Smrg;; This is because the parser doesn't search for a matching ';', '{', 33f14f4646Smrg;; '[' or '(' to know where the expression starts. The C mode has the 34f14f4646Smrg;; same problem. Example: 35f14f4646Smrg;; a + 36f14f4646Smrg;; b; <-- if pressing C-A,Tab will align "b;" with "a +" 37f14f4646Smrg 38f14f4646Smrg;; Maybe most of the code here, and some code in the C mode could be 39f14f4646Smrg;; merged to have a single "default mode" parser for languages that 40f14f4646Smrg;; basically only depend on { and } for indentation. 41f14f4646Smrg 42f14f4646Smrg(require "syntax") 43f14f4646Smrg(require "indent") 44f14f4646Smrg(in-package "XEDIT") 45f14f4646Smrg 46f14f4646Smrg;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 47f14f4646Smrg(defsynprop *prop-string-escape* 48f14f4646Smrg "string-escape" 49f14f4646Smrg :font "*lucidatypewriter-bold-r*-12-*" 50f14f4646Smrg :foreground "RoyalBlue2" 51f14f4646Smrg :underline t) 52f14f4646Smrg 53f14f4646Smrg(defsynprop *prop-string-keyword-bold* 54f14f4646Smrg "string-variable-bold" 55f14f4646Smrg :font "*lucidatypewriter-bold-r*-12-*" 56f14f4646Smrg :foreground "RoyalBlue4") 57f14f4646Smrg 58f14f4646Smrg(defsynprop *prop-string-keyword* 59f14f4646Smrg "string-variable" 60f14f4646Smrg :font "*lucidatypewriter-medium-r*-12-*" 61f14f4646Smrg :foreground "RoyalBlue4") 62f14f4646Smrg 63f14f4646Smrg(defsynprop *prop-constant-escape* 64f14f4646Smrg "constant-escape" 65f14f4646Smrg :font "*lucidatypewriter-medium-r*-12-*" 66f14f4646Smrg :foreground "VioletRed3" 67f14f4646Smrg :underline t) 68f14f4646Smrg 69f14f4646Smrg(defsynprop *prop-regex* 70f14f4646Smrg "regex" 71f14f4646Smrg :font "*courier-medium-o*-12-*" 72f14f4646Smrg :foreground "black") 73f14f4646Smrg 74f14f4646Smrg(defsynprop *prop-shell* 75f14f4646Smrg "shell" 76f14f4646Smrg :font "*lucidatypewriter-medium-r*-12-*" 77f14f4646Smrg :foreground "red3") 78f14f4646Smrg 79f14f4646Smrg(defsynprop *prop-shell-escape* 80f14f4646Smrg "shell-escape" 81f14f4646Smrg :font "*lucidatypewriter-bold-r*-12-*" 82f14f4646Smrg :foreground "red3" 83f14f4646Smrg :underline t) 84f14f4646Smrg 85f14f4646Smrg(defsynprop *prop-documentation* 86f14f4646Smrg "documentation" 87f14f4646Smrg :font "fixed" 88f14f4646Smrg :foreground "black" 89f14f4646Smrg :background "rgb:e/e/e" 90f14f4646Smrg) 91f14f4646Smrg 92f14f4646Smrg 93f14f4646Smrg;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 94f14f4646Smrg(defsynoptions *perl-DEFAULT-style* 95f14f4646Smrg ;; Positive number. Basic indentation 96f14f4646Smrg (:indentation . 4) 97f14f4646Smrg 98f14f4646Smrg ;; Boolean. Add one indentation level to continuations? 99f14f4646Smrg (:cont-indent . t) 100f14f4646Smrg 101f14f4646Smrg ;; Boolean. Move cursor to the indent column after pressing <Enter>? 102f14f4646Smrg (:newline-indent . t) 103f14f4646Smrg 104f14f4646Smrg ;; Boolean. Set to T if tabs shouldn't be used to fill indentation. 105f14f4646Smrg (:emulate-tabs . nil) 106f14f4646Smrg 107f14f4646Smrg ;; Boolean. Only calculate indentation after pressing <Enter>? 108f14f4646Smrg ;; This may be useful if the parser does not always 109f14f4646Smrg ;; do what the user expects... 110f14f4646Smrg (:only-newline-indent . nil) 111f14f4646Smrg 112f14f4646Smrg ;; Boolean. Remove extra spaces from previous line. 113f14f4646Smrg ;; This should default to T when newline-indent is not NIL. 114f14f4646Smrg (:trim-blank-lines . t) 115f14f4646Smrg 116f14f4646Smrg ;; Boolean. If this hash-table entry is set, no indentation is done. 117f14f4646Smrg ;; Useful to temporarily disable indentation. 118f14f4646Smrg (:disable-indent . nil)) 119f14f4646Smrg 120f14f4646Smrg 121f14f4646Smrg 122f14f4646Smrg;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 123f14f4646Smrg(defvar *perl-mode-options* *perl-DEFAULT-style*) 124f14f4646Smrg 125f14f4646Smrg;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 126f14f4646Smrg;; Parenthesis are usually not required, just distinguish as: 127f14f4646Smrg;; expression: code without an ending ';' 128f14f4646Smrg;; statement: code ending in a ';' 129f14f4646Smrg;; block: code enclosed in '{' and '}' 130f14f4646Smrg;; In Perl a simpler logic can be used, unlikely the C mode, as in 131f14f4646Smrg;; perl braces are mandatory 132f14f4646Smrg(defindent *perl-mode-indent* :main 133f14f4646Smrg ;; this must be the first token 134f14f4646Smrg (indtoken "^\\s*" :indent 135f14f4646Smrg :code (or *offset* (setq *offset* (+ *ind-offset* *ind-length*)))) 136f14f4646Smrg ;; this may cause some other patterns to fail, due to matching single \' 137f14f4646Smrg (indtoken "(&?(\\w+)|&(\\w+)?)'\\w+" :expression) 138f14f4646Smrg ;; special variables 139f14f4646Smrg (indtoken "\\$(\\d|^\\u|[][0-9!#$*()_@<>?/|,\"'])" :expression) 140f14f4646Smrg ;; ignore comments 141f14f4646Smrg (indtoken "#.*$" nil) 142f14f4646Smrg ;; treat regex as expressions to avoid confusing parser 143f14f4646Smrg (indtoken "m?/([^/]|\\\\/)+/\\w*" :expression) 144f14f4646Smrg (indtoken "m\\{[^}]+\\}\\w*" :expression) 145f14f4646Smrg (indtoken "m<[^>]+>\\w*" :expression) 146f14f4646Smrg (indtoken "(s|tr)/[^/]+/([^/]|\\\\/)*/\\w*" :expression) 147f14f4646Smrg (indtoken "//" :expression :nospec t) 148f14f4646Smrg ;; fast resolve deferences to expressions 149f14f4646Smrg (indtoken "[$@%&*]?\\{\\$?\\S+\\}" :expression) 150f14f4646Smrg 151f14f4646Smrg (indtoken "($%@*)?\\w+" :expression) 152f14f4646Smrg (indtoken ";" :semi :nospec t) 153f14f4646Smrg (indinit (braces 0)) 154f14f4646Smrg (indtoken "{" :obrace :nospec t 155f14f4646Smrg :code (decf braces)) 156f14f4646Smrg (indtoken "}" :cbrace :nospec t 157f14f4646Smrg :code (incf braces)) 158f14f4646Smrg (indinit (parens&bracks 0)) 159f14f4646Smrg (indtoken ")" :cparen :nospec t :code (incf parens&bracks)) 160f14f4646Smrg (indtoken "(" :oparen :nospec t :code (decf parens&bracks)) 161f14f4646Smrg (indtoken "]" :cbrack :nospec t :code (incf parens&bracks)) 162f14f4646Smrg (indtoken "[" :obrack :nospec t :code (decf parens&bracks)) 163f14f4646Smrg ;; if in the same line, reduce now, this must be done because the 164f14f4646Smrg ;; delimiters are identical 165f14f4646Smrg (indtoken "'([^\\']|\\\\.)*'" :expression) 166f14f4646Smrg (indtoken "\"([^\\\"]|\\\\.)*\"" :expression) 167f14f4646Smrg (indtoken "\"" :cstring1 :nospec t :begin :string1) 168f14f4646Smrg (indtoken "'" :cstring2 :nospec t :begin :string2) 169f14f4646Smrg ;; This must be the last rule 170f14f4646Smrg (indtoken "\\s*$" :eol) 171f14f4646Smrg 172f14f4646Smrg (indtable :string1 173f14f4646Smrg ;; Ignore escaped characters 174f14f4646Smrg (indtoken "\\." nil) 175f14f4646Smrg ;; Return to the toplevel when the start of the string is found 176f14f4646Smrg (indtoken "\"" :ostring1 :nospec t :switch -1)) 177f14f4646Smrg (indtable :string2 178f14f4646Smrg (indtoken "\\." nil) 179f14f4646Smrg (indtoken "'" :ostring2 :nospec t :switch -1)) 180f14f4646Smrg 181f14f4646Smrg ;; This avoids some problems with *cont-indent* adding an indentation 182f14f4646Smrg ;; level to an expression after an empty line 183f14f4646Smrg (indreduce nil 184f14f4646Smrg t 185f14f4646Smrg ((:indent :eol))) 186f14f4646Smrg 187f14f4646Smrg ;; Reduce to a single expression token 188f14f4646Smrg (indreduce :expression 189f14f4646Smrg t 190f14f4646Smrg ((:indent :expression) 191f14f4646Smrg (:expression :eol) 192f14f4646Smrg (:expression :parens) 193f14f4646Smrg (:expression :bracks) 194f14f4646Smrg (:expression :expression) 195f14f4646Smrg ;; multiline strings 196f14f4646Smrg (:ostring1 (not :ostring1) :cstring1) 197f14f4646Smrg (:ostring2 (not :ostring2) :cstring2) 198f14f4646Smrg ;; parenthesis and brackets 199f14f4646Smrg (:oparen (not :oparen) :cparen) 200f14f4646Smrg (:obrack (not :obrack) :cbrack))) 201f14f4646Smrg 202f14f4646Smrg ;; Statements end in a semicollon 203f14f4646Smrg (indreduce :statement 204f14f4646Smrg t 205f14f4646Smrg ((:semi) 206f14f4646Smrg (:indent :semi) 207f14f4646Smrg (:expression :statement) 208f14f4646Smrg (:statement :eol) 209f14f4646Smrg ;; Doesn't necessarily end in a semicollon 210f14f4646Smrg (:expression :block))) 211f14f4646Smrg 212f14f4646Smrg (indreduce :block 213f14f4646Smrg t 214f14f4646Smrg ((:obrace (not :obrace) :cbrace) 215f14f4646Smrg (:block :eol))) 216f14f4646Smrg (indreduce :obrace 217f14f4646Smrg (< *ind-offset* *ind-start*) 218f14f4646Smrg ((:indent :obrace)) 219f14f4646Smrg (setq *indent* (offset-indentation (+ *ind-offset* *ind-length*) :resolve t)) 220f14f4646Smrg (indent-macro-reject-left)) 221f14f4646Smrg 222f14f4646Smrg ;; Try to do an smart indentation on open parenthesis and brackets 223f14f4646Smrg (indreduce :parens 224f14f4646Smrg t 225f14f4646Smrg ((:oparen (not :oparen) :cparen)) 226f14f4646Smrg (when (and 227f14f4646Smrg (< *ind-offset* *ind-start*) 228f14f4646Smrg (> (+ *ind-offset* *ind-length*) *ind-start*)) 229f14f4646Smrg (setq *indent* (1+ (offset-indentation *ind-offset* :align t))) 230f14f4646Smrg (indent-macro-reject-left))) 231f14f4646Smrg (indreduce :bracks 232f14f4646Smrg t 233f14f4646Smrg ((:obrack (not :obrack) :cbrack)) 234f14f4646Smrg (when (and 235f14f4646Smrg (< *ind-offset* *ind-start*) 236f14f4646Smrg (> (+ *ind-offset* *ind-length*) *ind-start*)) 237f14f4646Smrg (setq *indent* (1+ (offset-indentation *ind-offset* :align t))) 238f14f4646Smrg (indent-macro-reject-left))) 239f14f4646Smrg 240f14f4646Smrg ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 241f14f4646Smrg ;; Assuming previous lines have correct indentation, try to 242f14f4646Smrg ;; fast resolve brace indentation 243f14f4646Smrg ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 244f14f4646Smrg ;; Line ended with an open brace 245f14f4646Smrg (indreduce :obrace 246f14f4646Smrg (< *ind-offset* *ind-start*) 247f14f4646Smrg ((:expression :obrace)) 248f14f4646Smrg (setq *indent* (offset-indentation *ind-offset* :resolve t)) 249f14f4646Smrg (indent-macro-reject-left)) 250f14f4646Smrg ;; Line starts with an open brace 251f14f4646Smrg (indreduce nil 252f14f4646Smrg (< *ind-offset* *ind-start* (+ *ind-offset* *ind-length*)) 253f14f4646Smrg ;; Just set initial indentation 254f14f4646Smrg ((:indent :obrace)) 255f14f4646Smrg (setq 256f14f4646Smrg *indent* (- (offset-indentation *ind-offset* :resolve t) *base-indent*)) 257f14f4646Smrg (indent-macro-reject-left)) 258f14f4646Smrg 259f14f4646Smrg (indresolve :statement 260f14f4646Smrg (when (< *ind-offset* *ind-start*) 261f14f4646Smrg (while (> braces 0) 262f14f4646Smrg (setq 263f14f4646Smrg *indent* (- *indent* *base-indent*) 264f14f4646Smrg braces (1- braces))))) 265f14f4646Smrg 266f14f4646Smrg (indresolve :obrace 267f14f4646Smrg (and (< *ind-offset* *ind-start*) 268f14f4646Smrg (incf *indent* *base-indent*))) 269f14f4646Smrg (indresolve :cbrace 270f14f4646Smrg (decf *indent* *base-indent*)) 271f14f4646Smrg (indresolve :expression 272f14f4646Smrg (and 273f14f4646Smrg *cont-indent* 274f14f4646Smrg (> *indent* 0) 275f14f4646Smrg (zerop parens&bracks) 276f14f4646Smrg (< *ind-offset* *ind-start*) 277f14f4646Smrg (> (+ *ind-offset* *ind-length*) *ind-start*) 278f14f4646Smrg (incf *indent* *base-indent*))) 279f14f4646Smrg 280f14f4646Smrg (indresolve (:oparen :obrack) 281f14f4646Smrg (and (< *ind-offset* *ind-start*) 282f14f4646Smrg (setq *indent* (1+ (offset-indentation *ind-offset* :align t))))) 283f14f4646Smrg) 284f14f4646Smrg 285f14f4646Smrg;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 286f14f4646Smrg(defun perl-offset-indent (&aux char (point (point))) 287f14f4646Smrg ;; Skip spaces forward 288f14f4646Smrg (while (member (setq char (char-after point)) indent-spaces) 289f14f4646Smrg (incf point)) 290f14f4646Smrg (if (member char '(#\})) (1+ point) point)) 291f14f4646Smrg 292f14f4646Smrg(compile 'perl-offset-indent) 293f14f4646Smrg 294f14f4646Smrg;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 295f14f4646Smrg(defun perl-should-indent (options &aux char point start offset) 296f14f4646Smrg (when (hash-table-p options) 297f14f4646Smrg ;; check if previous line has extra spaces 298f14f4646Smrg (and (gethash :trim-blank-lines options) 299f14f4646Smrg (indent-clear-empty-line)) 300f14f4646Smrg 301f14f4646Smrg ;; indentation disabled? 302f14f4646Smrg (and (gethash :disable-indent options) 303f14f4646Smrg (return-from perl-should-indent)) 304f14f4646Smrg 305f14f4646Smrg (setq 306f14f4646Smrg point (point) 307f14f4646Smrg char (char-before point) 308f14f4646Smrg start (scan point :eol :left)) 309f14f4646Smrg 310f14f4646Smrg ;; if at bol and should indent only when starting a line 311f14f4646Smrg (and (gethash :only-newline-indent options) 312f14f4646Smrg (return-from perl-should-indent (= point start))) 313f14f4646Smrg 314f14f4646Smrg ;; at the start of a line 315f14f4646Smrg (and (= point start) 316f14f4646Smrg (return-from perl-should-indent (gethash :newline-indent options))) 317f14f4646Smrg 318f14f4646Smrg ;; if first character 319f14f4646Smrg (and (= point (1+ start)) 320f14f4646Smrg (return-from perl-should-indent t)) 321f14f4646Smrg 322f14f4646Smrg ;; check if is the first non-blank character in a new line 323f14f4646Smrg (when (and 324f14f4646Smrg (gethash :cont-indent options) 325f14f4646Smrg (= point (scan point :eol :right)) 326f14f4646Smrg (alphanumericp char)) 327f14f4646Smrg (setq offset (1- point)) 328f14f4646Smrg (while (and 329f14f4646Smrg (> offset start) 330f14f4646Smrg (member (char-before offset) indent-spaces)) 331f14f4646Smrg (decf offset)) 332f14f4646Smrg ;; line has only one character with possible spaces before it 333f14f4646Smrg (and (<= offset start) 334f14f4646Smrg (return-from perl-should-indent t))) 335f14f4646Smrg 336f14f4646Smrg ;; if one of these was typed, should check indentation 337f14f4646Smrg (if (member char '(#\})) (return-from perl-should-indent t)) 338f14f4646Smrg ) 339f14f4646Smrg ;; Should not indent 340f14f4646Smrg nil) 341f14f4646Smrg 342f14f4646Smrg(compile 'perl-should-indent) 343f14f4646Smrg 344f14f4646Smrg;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 345f14f4646Smrg(defun perl-indent (syntax syntable) 346f14f4646Smrg (let* 347f14f4646Smrg ((options (syntax-options syntax)) 348f14f4646Smrg *base-indent* 349f14f4646Smrg *cont-indent*) 350f14f4646Smrg 351f14f4646Smrg (or (perl-should-indent options) (return-from perl-indent)) 352f14f4646Smrg (setq 353f14f4646Smrg *base-indent* (gethash :indentation options 4) 354f14f4646Smrg *cont-indent* (gethash :cont-indent options t)) 355f14f4646Smrg 356f14f4646Smrg (indent-macro 357f14f4646Smrg *perl-mode-indent* 358f14f4646Smrg (perl-offset-indent) 359f14f4646Smrg (gethash :emulate-tabs options)))) 360f14f4646Smrg 361f14f4646Smrg(compile 'perl-indent) 362f14f4646Smrg 363f14f4646Smrg;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 364f14f4646Smrg;; some example macros to easily add new patterns for strings and possibly 365f14f4646Smrg;; regex or other patterns 366f14f4646Smrg(defmacro perl-q-string-token (token) 367f14f4646Smrg `(syntoken (string-concat "\\<q(q|w)?\\s*\\" ,token) 368f14f4646Smrg :icase t :contained t :begin 369f14f4646Smrg (intern (string-concat "string" ,token) 'keyword))) 370f14f4646Smrg(defmacro perl-q-string-table (start end) 371f14f4646Smrg `(syntable (intern (string-concat "string" ,start) 'keyword) 372f14f4646Smrg *prop-string* #'default-indent 373f14f4646Smrg (syntoken ,end :nospec t :switch -1) 374f14f4646Smrg (synaugment :inside-string))) 375f14f4646Smrg 376f14f4646Smrg;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 377f14f4646Smrg(defsyntax *perl-mode* :main nil #'perl-indent *perl-mode-options* 378f14f4646Smrg ;; keywords 379f14f4646Smrg (syntoken 380f14f4646Smrg (string-concat 381f14f4646Smrg "\\<(" 382f14f4646Smrg "and|for|foreach|gt|if|else|elsif|eq|goto|le|lt|last|ne|" 383f14f4646Smrg "neg|next|not|or|return|shift|sub|unless|unshift|until|while" 384f14f4646Smrg ")\\>") 385f14f4646Smrg :property *prop-keyword*) 386f14f4646Smrg 387f14f4646Smrg ;; pseudo keywords 388f14f4646Smrg (syntoken 389f14f4646Smrg (string-concat 390f14f4646Smrg "\\<(" 391f14f4646Smrg "BEGIN|END|bless|blessed|defined|delete|eval|local|my|our|" 392f14f4646Smrg "package|require|undef|use" 393f14f4646Smrg ")\\>") 394f14f4646Smrg :property *prop-preprocessor*) 395f14f4646Smrg ;; this may cause some other patterns to fail, due to matching single \' 396f14f4646Smrg (syntoken "(&?(\\w+)|&(\\w+)?)'\\w+" :property *prop-preprocessor*) 397f14f4646Smrg 398f14f4646Smrg ;; numbers 399f14f4646Smrg (syntoken 400f14f4646Smrg (string-concat 401f14f4646Smrg "\\<(" 402f14f4646Smrg ;; Integers 403f14f4646Smrg "(\\d+|0x\\x+)|" 404f14f4646Smrg ;; Floats 405f14f4646Smrg "\\d+\\.?\\d*(e[+-]?\\d+)?" 406f14f4646Smrg ")\\>") 407f14f4646Smrg :icase t 408f14f4646Smrg :property *prop-number*) 409f14f4646Smrg 410f14f4646Smrg ;; special variables 411f14f4646Smrg (syntoken "\\$(\\d|^\\u|[][0-9!#$*()_@<>?/|,\"'])" :property *prop-keyword*) 412f14f4646Smrg 413f14f4646Smrg ;; also match variables 414f14f4646Smrg (syntable :inside-string nil nil 415f14f4646Smrg ;; escaped characters 416f14f4646Smrg 417f14f4646Smrg ;; XXX This pattern was matching the empty string and entering an 418f14f4646Smrg ;; infinite loop in code like: 419f14f4646Smrg#| 420f14f4646Smrg---%<--- 421f14f4646Smrg" <-- *** if an backslash is added it fails. Inverting 422f14f4646Smrga"; *** the pattern fixed the problem, but was the wrong 423f14f4646Smrg---%<--- *** solution. Note that C-G stops the interpreter, and 424f14f4646Smrg *** special care must be taken with patterns matching 425f14f4646Smrg *** empty strings. 426f14f4646Smrg|# 427f14f4646Smrg 428f14f4646Smrg (syntoken "\\\\\\d{3}|\\\\." :property *prop-string-escape*) 429f14f4646Smrg (syntoken "(\\{\\$|\\$\\{)" :property *prop-string-keyword-bold* :begin :string-varbrace) 430f14f4646Smrg (syntoken "[$@]" :property *prop-string-keyword-bold* :begin :string-variable) 431f14f4646Smrg (syntoken "\\$(\\d|^\\u|[][0-9!#$*()_@<>?/|,\"'])" :property *prop-string-keyword-bold*)) 432f14f4646Smrg 433f14f4646Smrg ;; variables insided strings 434f14f4646Smrg (syntable :string-variable *prop-string-keyword* nil 435f14f4646Smrg (syntoken "\\w+" :switch -1)) 436f14f4646Smrg (syntable :string-varbrace *prop-string-keyword* nil 437f14f4646Smrg (syntoken "}" 438f14f4646Smrg :nospec t 439f14f4646Smrg :property *prop-string-keyword-bold* 440f14f4646Smrg :switch -1) 441f14f4646Smrg (synaugment :inside-string)) 442f14f4646Smrg 443f14f4646Smrg ;; comments 444f14f4646Smrg (syntoken "#.*$" :property *prop-comment*) 445f14f4646Smrg 446f14f4646Smrg ;; regex 447f14f4646Smrg (syntoken "(\\<m)?/([^/]|\\\\/)+/\\w*" :property *prop-regex*) 448f14f4646Smrg (syntoken "\\<m\\{[^}]+\\}\\w*" :property *prop-regex*) 449f14f4646Smrg (syntoken "\\<m<[^>]+>\\w*" :property *prop-regex*) 450f14f4646Smrg (syntoken "\\<(s|tr)/[^/]+/([^/]|\\\\/)*/\\w*":property *prop-regex*) 451f14f4646Smrg ;; just to avoid confusing the parser on something like split //, ... 452f14f4646Smrg (syntoken "//" :nospec t :property *prop-regex*) 453f14f4646Smrg 454f14f4646Smrg ;; strings 455f14f4646Smrg (syntoken "\"" :nospec t :contained t :begin :string) 456f14f4646Smrg (syntable :string *prop-string* #'default-indent 457f14f4646Smrg (syntoken "\"" :nospec t :switch -1) 458f14f4646Smrg (synaugment :inside-string)) 459f14f4646Smrg 460f14f4646Smrg ;; more strings 461f14f4646Smrg (perl-q-string-token "{") 462f14f4646Smrg (perl-q-string-table "{" "}") 463f14f4646Smrg (perl-q-string-token "[") 464f14f4646Smrg (perl-q-string-table "[" "]") 465f14f4646Smrg (perl-q-string-token "(") 466f14f4646Smrg (perl-q-string-table "(" ")") 467f14f4646Smrg (perl-q-string-token "/") 468f14f4646Smrg (perl-q-string-table "/" "/") 469f14f4646Smrg 470f14f4646Smrg ;; yet more strings 471f14f4646Smrg (syntoken "'" :nospec t :contained t :begin :constant) 472f14f4646Smrg (syntable :constant *prop-constant* #'default-indent 473f14f4646Smrg (syntoken "'" :nospec t :switch -1) 474f14f4646Smrg (syntoken "\\\\." :property *prop-string-escape*)) 475f14f4646Smrg 476f14f4646Smrg ;; shell commands 477f14f4646Smrg (syntoken "`" :nospec t :contained t :begin :shell) 478f14f4646Smrg (syntable :shell *prop-shell* #'default-indent 479f14f4646Smrg (syntoken "`" :nospec t :switch -1) 480f14f4646Smrg (synaugment :inside-string)) 481f14f4646Smrg 482f14f4646Smrg ;; punctuation 483f14f4646Smrg (syntoken "[][$@%(){}/*+:;=<>,&!|^~\\.?-]" :property *prop-punctuation*) 484f14f4646Smrg (syntoken "\\<x\\>" :property *prop-punctuation*) 485f14f4646Smrg 486f14f4646Smrg ;; primitive faked heredoc support, doesn't match the proper string, just 487f14f4646Smrg ;; expects an uppercase identifier in a single line 488f14f4646Smrg (syntoken "<<\"[A-Z][A-Z0-9_]+\"" :property *prop-string* :begin :heredoc) 489f14f4646Smrg (syntoken "<<'[A-Z][A-Z0-9_]+'" :property *prop-constant* :begin :heredoc) 490f14f4646Smrg (syntoken "<<[A-Z][A-Z0-9_]+" :property *prop-preprocessor* :begin :heredoc) 491f14f4646Smrg (syntable :heredoc *prop-documentation* #'default-indent 492f14f4646Smrg (syntoken "^[A-Z][A-Z0-9_]+$" :switch -1)) 493f14f4646Smrg 494f14f4646Smrg (syntoken "^=(pod|item|over|head\\d)\\>.*$" :property *prop-documentation* :begin :info) 495f14f4646Smrg (syntable :info *prop-documentation* nil 496f14f4646Smrg (syntoken "^=cut\\>.*$" :switch -1) 497f14f4646Smrg (syntoken "^.*$")) 498f14f4646Smrg 499f14f4646Smrg (syntoken "^(__END__|__DATA__)$" :property *prop-documentation* 500f14f4646Smrg :begin :documentation) 501f14f4646Smrg 502f14f4646Smrg (syntoken "__\\u+__" :property *prop-preprocessor*) 503f14f4646Smrg 504f14f4646Smrg (syntable :documentation *prop-documentation* nil 505f14f4646Smrg (syntoken "^.*$")) 506f14f4646Smrg 507f14f4646Smrg) 508