15dfecf96Smrg;; 25dfecf96Smrg;; Copyright (c) 2002 by The XFree86 Project, Inc. 35dfecf96Smrg;; 45dfecf96Smrg;; Permission is hereby granted, free of charge, to any person obtaining a 55dfecf96Smrg;; copy of this software and associated documentation files (the "Software"), 65dfecf96Smrg;; to deal in the Software without restriction, including without limitation 75dfecf96Smrg;; the rights to use, copy, modify, merge, publish, distribute, sublicense, 85dfecf96Smrg;; and/or sell copies of the Software, and to permit persons to whom the 95dfecf96Smrg;; Software is furnished to do so, subject to the following conditions: 105dfecf96Smrg;; 115dfecf96Smrg;; The above copyright notice and this permission notice shall be included in 125dfecf96Smrg;; all copies or substantial portions of the Software. 135dfecf96Smrg;; 145dfecf96Smrg;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 155dfecf96Smrg;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 165dfecf96Smrg;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 175dfecf96Smrg;; THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 185dfecf96Smrg;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 195dfecf96Smrg;; OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 205dfecf96Smrg;; SOFTWARE. 215dfecf96Smrg;; 225dfecf96Smrg;; Except as contained in this notice, the name of the XFree86 Project shall 235dfecf96Smrg;; not be used in advertising or otherwise to promote the sale, use or other 245dfecf96Smrg;; dealings in this Software without prior written authorization from the 255dfecf96Smrg;; XFree86 Project. 265dfecf96Smrg;; 275dfecf96Smrg;; Author: Paulo César Pereira de Andrade 285dfecf96Smrg;; 295dfecf96Smrg;; 305dfecf96Smrg;; $XFree86: xc/programs/xedit/lisp/modules/syntax.lsp,v 1.11 2003/01/16 03:50:46 paulo Exp $ 315dfecf96Smrg;; 325dfecf96Smrg 335dfecf96Smrg(provide "syntax") 345dfecf96Smrg(require "xedit") 355dfecf96Smrg(in-package "XEDIT") 365dfecf96Smrg 375dfecf96Smrg(defvar *syntax-symbols* '( 385dfecf96Smrg syntax-highlight defsyntax defsynprop synprop-p syntax-p 395dfecf96Smrg syntable syntoken synaugment 405dfecf96Smrg *prop-default* *prop-keyword* *prop-number* *prop-string* 415dfecf96Smrg *prop-constant* *prop-comment* *prop-preprocessor* 425dfecf96Smrg *prop-punctuation* *prop-error* *prop-annotation* 435dfecf96Smrg)) 445dfecf96Smrg(export *syntax-symbols*) 455dfecf96Smrg(in-package "USER") 465dfecf96Smrg(dolist (symbol xedit::*syntax-symbols*) 475dfecf96Smrg (import symbol) 485dfecf96Smrg) 495dfecf96Smrg(in-package "XEDIT") 505dfecf96Smrg(makunbound '*syntax-symbols*) 515dfecf96Smrg 525dfecf96Smrg#| 535dfecf96SmrgTODO: 545dfecf96Smrgo Add a command to match without increment the offset in the input, this 555dfecf96Smrg may be useful for example in a case like: 565dfecf96Smrg some-table 575dfecf96Smrg match "<" 585dfecf96Smrg switch -1 595dfecf96Smrg match "<" <- the table already eated this, so it won't be matched. 605dfecf96Smrg This must be carefully checked at compile time, such instruction should 615dfecf96Smrg be in a token that returns or starts a new one, and even then, may need 625dfecf96Smrg runtime check to make sure it won't enter an infinite loop. 635dfecf96Smrgo Allow combining properties, this is supported in Xaw, and could allow some 645dfecf96Smrg very interesting effects for complex documents. 655dfecf96Smrgo Maybe have an separated function/loop for tables that don't have tokens 665dfecf96Smrg that start/switch to another table, and/or have the contained attribute set. 675dfecf96Smrg This could allow running considerably faster. 685dfecf96Smrgo Do a better handling of interactive edition for tokens that start and end 695dfecf96Smrg with the same pattern, as an example strings, if the user types '"', it 705dfecf96Smrg will parse up to the end of the file, "inverting" all strings. 715dfecf96Smrgo Allow generic code to be run once a match is found, such code could handle 725dfecf96Smrg some defined variables and take decisions based on the parser state. This 735dfecf96Smrg should be detected at compile time, to maybe run a different parser for 745dfecf96Smrg such syntax tables, due to the extra time building the environment to 755dfecf96Smrg call the code. This would be useful to "really" parse documents with 765dfecf96Smrg complex syntax, for example, a man page source file. 775dfecf96Smrgo Add command to change current default property without initializing a new 785dfecf96Smrg state. 795dfecf96Smrgo Fix problems matching EOL. Since EOL is an empty string match, if there 805dfecf96Smrg is a rule to match only EOL, but some other rule matches up to the end 815dfecf96Smrg of the input, the match to EOL will not be recognized. Currently the only 825dfecf96Smrg way to handle this is to have a nested table that always returns once a 835dfecf96Smrg match is found, so that it will restart the match loop code even if the 845dfecf96Smrg input is at EOL. 855dfecf96Smrg One possible solution would be to add the ending newline to the input, 865dfecf96Smrg and then instead of matching "$", should match "\\n". 875dfecf96Smrgo XXX Usage of the variable newline-property must be reviewed in function 885dfecf96Smrg syntax-highlight, if the text property has a background attribute, 895dfecf96Smrg visual effect will look "strange", will paint a square with the 905dfecf96Smrg background attribute at the end of every line in the matched text. 915dfecf96Smrg|# 925dfecf96Smrg 935dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 945dfecf96Smrg;; Some annotations to later write documentation for the module... 955dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 965dfecf96Smrg#| 975dfecf96Smrg The current interface logic should be easy to understand for people 985dfecf96Smrgthat have written lex scanners before. It has some extended semantics, 995dfecf96Smrgthat could be translated to stacked BEGIN() statements in lex, but 1005dfecf96Smrgcurrently does not have rules for matches in the format RE/TRAILING, as 1015dfecf96Smrgwell as code attached to rules (the biggest difference) and/or things 1025dfecf96Smrglike REJECT and unput(). Also, at least currently, it is *really* quite 1035dfecf96Smrgslower than lex. 1045dfecf96Smrg 1055dfecf96Smrg MATCHING RULES 1065dfecf96Smrg -------------- 1075dfecf96Smrg When two tokens are matched at the same input offset, the longest 1085dfecf96Smrgtoken is used, if the length is the same, the first definition is 1095dfecf96Smrgused. For example: 1105dfecf96Smrg token1 => int 1115dfecf96Smrg token2 => [A-Za-z]+ 1125dfecf96Smrg input => integer 1135dfecf96Smrg Token1 matches "int" and token2 matches "integer", but since token2 is 1145dfecf96Smrglonger, it is used. But in the case: 1155dfecf96Smrg token1 => int 1165dfecf96Smrg token2 => [A-Za-z]+ 1175dfecf96Smrg input => int 1185dfecf96Smrg Both, token1 and token2 match "int", since token1 is defined first, it 1195dfecf96Smrgis used. 1205dfecf96Smrg|# 1215dfecf96Smrg 1225dfecf96Smrg 1235dfecf96Smrg;; Initialize some default properties that may be shared in syntax 1245dfecf96Smrg;; highlight definitions. Use of these default properties is encouraged, 1255dfecf96Smrg;; so that "tokens" will be shown identically when editing program 1265dfecf96Smrg;; sources in different programming languages. 1275dfecf96Smrg(defsynprop *prop-default* 1285dfecf96Smrg "default" 1295dfecf96Smrg :font "*courier-medium-r*-12-*" 1305dfecf96Smrg :foreground "black") 1315dfecf96Smrg 1325dfecf96Smrg(defsynprop *prop-keyword* 1335dfecf96Smrg "keyword" 1345dfecf96Smrg :font "*courier-bold-r*-12-*" 1355dfecf96Smrg :foreground "gray12") 1365dfecf96Smrg 1375dfecf96Smrg(defsynprop *prop-number* 1385dfecf96Smrg "number" 1395dfecf96Smrg :font "*courier-bold-r*-12-*" 1405dfecf96Smrg :foreground "OrangeRed3") 1415dfecf96Smrg 1425dfecf96Smrg(defsynprop *prop-string* 1435dfecf96Smrg "string" 1445dfecf96Smrg :font "*lucidatypewriter-medium-r*-12-*" 1455dfecf96Smrg :foreground "RoyalBlue2") 1465dfecf96Smrg 1475dfecf96Smrg(defsynprop *prop-constant* 1485dfecf96Smrg "constant" 1495dfecf96Smrg :font "*lucidatypewriter-medium-r*-12-*" 1505dfecf96Smrg :foreground "VioletRed3") 1515dfecf96Smrg 1525dfecf96Smrg(defsynprop *prop-comment* 1535dfecf96Smrg "comment" 1545dfecf96Smrg :font "*courier-medium-o*-12-*" 1555dfecf96Smrg :foreground "SlateBlue3") 1565dfecf96Smrg 1575dfecf96Smrg(defsynprop *prop-preprocessor* 1585dfecf96Smrg "preprocessor" 1595dfecf96Smrg :font "*courier-medium-r*-12-*" 1605dfecf96Smrg :foreground "green4") 1615dfecf96Smrg 1625dfecf96Smrg(defsynprop *prop-punctuation* 1635dfecf96Smrg "punctuation" 1645dfecf96Smrg :font "*courier-bold-r*-12-*" 1655dfecf96Smrg :foreground "gray12") 1665dfecf96Smrg 1675dfecf96Smrg;; Control characters, not always errors... 1685dfecf96Smrg(defsynprop *prop-control* 1695dfecf96Smrg "control" 1705dfecf96Smrg :font "*courier-bold-r*-12-*" 1715dfecf96Smrg :foreground "yellow2" 1725dfecf96Smrg :background "red3") 1735dfecf96Smrg 1745dfecf96Smrg(defsynprop *prop-error* 1755dfecf96Smrg "error" 1765dfecf96Smrg :font "*new century schoolbook-bold*-24-*" 1775dfecf96Smrg :foreground "yellow" 1785dfecf96Smrg :background "red") 1795dfecf96Smrg 1805dfecf96Smrg(defsynprop *prop-annotation* 1815dfecf96Smrg "annotation" 1825dfecf96Smrg :font "*courier-medium-r*-12-*" 1835dfecf96Smrg :foreground "black" 1845dfecf96Smrg :background "PaleGreen") 1855dfecf96Smrg 1865dfecf96Smrg 1875dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1885dfecf96Smrg;; The "main" definition of the syntax highlight coding interface. 1895dfecf96Smrg;; Creates a "special" variable with the given name, associating to 1905dfecf96Smrg;; it an already compiled syntax table. 1915dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 1925dfecf96Smrg(defmacro defsyntax (variable label property indent options &rest lists) 1935dfecf96Smrg `(if (boundp ',variable) 1945dfecf96Smrg ,variable 1955dfecf96Smrg (progn 1965dfecf96Smrg (proclaim '(special ,variable)) 1975dfecf96Smrg (setq ,variable 1985dfecf96Smrg (compile-syntax-table 1995dfecf96Smrg (string ',variable) ,options 2005dfecf96Smrg (syntable ,label ,property ,indent ,@lists) 2015dfecf96Smrg ) 2025dfecf96Smrg ) 2035dfecf96Smrg ) 2045dfecf96Smrg ) 2055dfecf96Smrg) 2065dfecf96Smrg 2075dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2085dfecf96Smrg;; Just a wrapper to create a hash-table and bound it to a symbol. 2095dfecf96Smrg;; Example of call: 2105dfecf96Smrg;; (defsynoptions *my-syntax-options* 2115dfecf96Smrg;; (:indent . 8) 2125dfecf96Smrg;; (:indent-option-1 . 1) 2135dfecf96Smrg;; (:indent-option-2 . 2) 2145dfecf96Smrg;; ) 2155dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2165dfecf96Smrg(defmacro defsynoptions (variable &rest options) 2175dfecf96Smrg `(if (boundp ',variable) 2185dfecf96Smrg ,variable 2195dfecf96Smrg (progn 2205dfecf96Smrg (proclaim '(special ,variable)) 2215dfecf96Smrg (setq ,variable (make-hash-table :initial-contents ',options)) 2225dfecf96Smrg ) 2235dfecf96Smrg ) 2245dfecf96Smrg) 2255dfecf96Smrg 2265dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2275dfecf96Smrg;; These definitions should be "private". 2285dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2295dfecf96Smrg(defstruct syntoken 2305dfecf96Smrg regex ;; A compiled regexp. 2315dfecf96Smrg property ;; NIL for default, or a synprop structure. 2325dfecf96Smrg contained ;; Only used when switch/begin is not NIL. Values: 2335dfecf96Smrg ;; NIL -> just switch to or begin new 2345dfecf96Smrg ;; syntax table. 2355dfecf96Smrg ;; (not NIL) -> apply syntoken property 2365dfecf96Smrg ;; (or default one) to matched 2375dfecf96Smrg ;; text *after* switching to or 2385dfecf96Smrg ;; beginning a new syntax table. 2395dfecf96Smrg switch ;; Values for switch are: 2405dfecf96Smrg ;; NIL -> do nothing 2415dfecf96Smrg ;; A keyword -> switch to the syntax table 2425dfecf96Smrg ;; identified by the keyword. 2435dfecf96Smrg ;; A negative integer -> Pop the stack 2445dfecf96Smrg ;; -<swich-value> times. 2455dfecf96Smrg ;; A common value is -1, 2465dfecf96Smrg ;; to switch to the previous 2475dfecf96Smrg ;; state, but some times 2485dfecf96Smrg ;; it is desired to return 2495dfecf96Smrg ;; two or more times in 2505dfecf96Smrg ;; in the stack. 2515dfecf96Smrg ;; NOTE: This is actually a jump, the stack is 2525dfecf96Smrg ;; popped until the named syntax table is found, 2535dfecf96Smrg ;; if the stack becomes empty, a new state is 2545dfecf96Smrg ;; implicitly created. 2555dfecf96Smrg begin ;; NIL or a keyword (like switch), but instead of 2565dfecf96Smrg ;; popping the stack, it pushes the current syntax 2575dfecf96Smrg ;; table to the stack and sets a new current one. 2585dfecf96Smrg) 2595dfecf96Smrg 2605dfecf96Smrg 2615dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2625dfecf96Smrg;; Just a wrapper to make-syntoken. 2635dfecf96Smrg;; TODO: Add support for structure constructors. 2645dfecf96Smrg;; XXX: Note that the NOSUB only works with the xedit regex, it 2655dfecf96Smrg;; will still return the match offsets, but will ignore subexpressions, 2665dfecf96Smrg;; that is, parenthesis are used only for grouping. 2675dfecf96Smrg;; TODO: Create a new version of the re-exec call that returns 2685dfecf96Smrg;; offsets in the format (<from> . <to>) and not 2695dfecf96Smrg;; ((<from0> . <to0>) ... (<fromN> . <toN>)). Only the global result 2705dfecf96Smrg;; is expected/used, so there is no reason to allocate more than one 2715dfecf96Smrg;; cons cell per call. 2725dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2735dfecf96Smrg(defun syntoken (pattern 2745dfecf96Smrg &key icase nospec property contained switch begin (nosub t) 2755dfecf96Smrg &aux 2765dfecf96Smrg (regex 2775dfecf96Smrg (re-comp pattern :icase icase :nospec nospec :nosub nosub) 2785dfecf96Smrg ) 2795dfecf96Smrg check) 2805dfecf96Smrg 2815dfecf96Smrg ;; Don't allow a regex that matches the null string enter the 2825dfecf96Smrg ;; syntax table list. 2835dfecf96Smrg (if (consp (setq check (re-exec regex "" :noteol t :notbol t))) 2845dfecf96Smrg#+xedit (error "SYNTOKEN: regex matches empty string ~S" regex) 2855dfecf96Smrg#-xedit () 2865dfecf96Smrg ) 2875dfecf96Smrg 2885dfecf96Smrg (make-syntoken 2895dfecf96Smrg :regex regex 2905dfecf96Smrg :property property 2915dfecf96Smrg :contained contained 2925dfecf96Smrg :switch switch 2935dfecf96Smrg :begin begin 2945dfecf96Smrg ) 2955dfecf96Smrg) 2965dfecf96Smrg 2975dfecf96Smrg 2985dfecf96Smrg;; This structure is defined only to do some type checking, it just 2995dfecf96Smrg;; holds a list of keywords. 3005dfecf96Smrg(defstruct synaugment 3015dfecf96Smrg labels ;; List of keywords labeling syntax tables. 3025dfecf96Smrg) 3035dfecf96Smrg 3045dfecf96Smrg(defstruct syntable 3055dfecf96Smrg label ;; A keyword naming this syntax table. 3065dfecf96Smrg property ;; NIL or a default synprop structure. 3075dfecf96Smrg indent ;; Indentation function for the syntax table. 3085dfecf96Smrg tokens ;; A list of syntoken structures. 3095dfecf96Smrg tables ;; A list of syntable structures. 3105dfecf96Smrg augments ;; A list of synaugment structures, used only 3115dfecf96Smrg ;; at "compile time", so that a table can be 3125dfecf96Smrg ;; used before it's definition. 3135dfecf96Smrg bol ;; One of the tokens match the empty string at 3145dfecf96Smrg ;; the start of a line (loop optimization hint). 3155dfecf96Smrg ;; Field filled at "link" time. 3165dfecf96Smrg eol ;; Same comments as bol, but in this case, for 3175dfecf96Smrg ;; the empty string at the end of a line. 3185dfecf96Smrg) 3195dfecf96Smrg 3205dfecf96Smrg 3215dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3225dfecf96Smrg;; Just call make-syntable, but sorts the elements by type, allowing 3235dfecf96Smrg;; a cleaner code when defining the syntax highlight rules. 3245dfecf96Smrg;; XXX Same comments as for syntoken about the use of a constructor for 3255dfecf96Smrg;; structures. TODO: when/if clos is implemented in the interpreter. 3265dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3275dfecf96Smrg(defun syntable (label default-property indent &rest definitions) 3285dfecf96Smrg 3295dfecf96Smrg ;; Check for possible errors in the arguments. 3305dfecf96Smrg (unless (keywordp label) 3315dfecf96Smrg (error "SYNTABLE: ~A is not a keyword" label) 3325dfecf96Smrg ) 3335dfecf96Smrg (unless 3345dfecf96Smrg (or 3355dfecf96Smrg (null default-property) 3365dfecf96Smrg (synprop-p default-property) 3375dfecf96Smrg ) 3385dfecf96Smrg (error "SYNTABLE: ~A is an invalid text property" 3395dfecf96Smrg default-property 3405dfecf96Smrg ) 3415dfecf96Smrg ) 3425dfecf96Smrg 3435dfecf96Smrg ;; Don't allow unknown data in the definition list. 3445dfecf96Smrg ;; XXX typecase should be added to the interpreter, and since 3455dfecf96Smrg ;; the code is traversing the entire list, it could build 3465dfecf96Smrg ;; now the arguments to make-syntable. 3475dfecf96Smrg (dolist (item definitions) 3485dfecf96Smrg (unless 3495dfecf96Smrg (or 3505dfecf96Smrg 3515dfecf96Smrg ;; Allow NIL in the definition list, so that one 3525dfecf96Smrg ;; can put conditionals in the syntax definition, 3535dfecf96Smrg ;; and if the conditional is false, fill the slot 3545dfecf96Smrg ;; with a NIL value. 3555dfecf96Smrg (atom item) 3565dfecf96Smrg (syntoken-p item) 3575dfecf96Smrg (syntable-p item) 3585dfecf96Smrg (synaugment-p item) 3595dfecf96Smrg ) 3605dfecf96Smrg (error "SYNTABLE: invalid syntax table argument ~A" item) 3615dfecf96Smrg ) 3625dfecf96Smrg ) 3635dfecf96Smrg 3645dfecf96Smrg ;; Build the syntax table. 3655dfecf96Smrg (make-syntable 3665dfecf96Smrg :label label 3675dfecf96Smrg :property default-property 3685dfecf96Smrg :indent indent 3695dfecf96Smrg :tokens (remove-if-not #'syntoken-p definitions) 3705dfecf96Smrg :tables (remove-if-not #'syntable-p definitions) 3715dfecf96Smrg :augments (remove-if-not #'synaugment-p definitions) 3725dfecf96Smrg ) 3735dfecf96Smrg) 3745dfecf96Smrg 3755dfecf96Smrg 3765dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3775dfecf96Smrg;; Just to do a "preliminary" error checking, every element must be a 3785dfecf96Smrg;; a keyword, and also check for reserved names. 3795dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3805dfecf96Smrg(defun synaugment (&rest keywords) 3815dfecf96Smrg (dolist (keyword keywords) 3825dfecf96Smrg (unless (keywordp keyword) 3835dfecf96Smrg (error "SYNAUGMENT: bad syntax table label ~A" keyword) 3845dfecf96Smrg ) 3855dfecf96Smrg ) 3865dfecf96Smrg (make-synaugment :labels keywords) 3875dfecf96Smrg) 3885dfecf96Smrg 3895dfecf96Smrg 3905dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3915dfecf96Smrg;; Recursive compile utility function. 3925dfecf96Smrg;; Returns a cons in the format: 3935dfecf96Smrg;; car => List of all syntoken structures 3945dfecf96Smrg;; (including child tables). 3955dfecf96Smrg;; cdr => List of all child syntable structures. 3965dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3975dfecf96Smrg(defun list-syntable-elements (table &aux result sub-result) 3985dfecf96Smrg (setq 3995dfecf96Smrg result 4005dfecf96Smrg (cons 4015dfecf96Smrg (syntable-tokens table) 4025dfecf96Smrg (syntable-tables table)) 4035dfecf96Smrg ) 4045dfecf96Smrg 4055dfecf96Smrg ;; For every child syntax table. 4065dfecf96Smrg (dolist (child (syntable-tables table)) 4075dfecf96Smrg 4085dfecf96Smrg ;; Recursively call list-syntable-elements. 4095dfecf96Smrg (setq sub-result (list-syntable-elements child)) 4105dfecf96Smrg 4115dfecf96Smrg (rplaca result (append (car result) (car sub-result))) 4125dfecf96Smrg (rplacd result (append (cdr result) (cdr sub-result))) 4135dfecf96Smrg ) 4145dfecf96Smrg 4155dfecf96Smrg ;; Return the pair of nested tokens and tables. 4165dfecf96Smrg result 4175dfecf96Smrg) 4185dfecf96Smrg 4195dfecf96Smrg 4205dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4215dfecf96Smrg;; Append tokens of the augment list to the tokens of the specified 4225dfecf96Smrg;; syntax table. 4235dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4245dfecf96Smrg(defun compile-syntax-augment-list (table table-list 4255dfecf96Smrg &aux labels augment tokens) 4265dfecf96Smrg 4275dfecf96Smrg ;; Create a list of all augment tables. 4285dfecf96Smrg (dolist (augment (syntable-augments table)) 4295dfecf96Smrg (setq labels (append labels (synaugment-labels augment))) 4305dfecf96Smrg ) 4315dfecf96Smrg 4325dfecf96Smrg ;; Remove duplicates and references to "itself", 4335dfecf96Smrg ;; without warnings? 4345dfecf96Smrg (setq 4355dfecf96Smrg labels 4365dfecf96Smrg (remove 4375dfecf96Smrg (syntable-label table) 4385dfecf96Smrg (remove-duplicates labels :from-end t) 4395dfecf96Smrg ) 4405dfecf96Smrg ) 4415dfecf96Smrg 4425dfecf96Smrg ;; Check if the specified syntax tables exists! 4435dfecf96Smrg (dolist (label labels) 4445dfecf96Smrg (unless 4455dfecf96Smrg (setq 4465dfecf96Smrg augment 4475dfecf96Smrg (car (member label table-list :key #'syntable-label)) 4485dfecf96Smrg ) 4495dfecf96Smrg (error "COMPILE-SYNTAX-AUGMENT-LIST: Cannot augment ~A in ~A" 4505dfecf96Smrg label 4515dfecf96Smrg (syntable-label table) 4525dfecf96Smrg ) 4535dfecf96Smrg ) 4545dfecf96Smrg 4555dfecf96Smrg ;; Increase list of tokens. 4565dfecf96Smrg (setq tokens (append tokens (syntable-tokens augment))) 4575dfecf96Smrg ) 4585dfecf96Smrg 4595dfecf96Smrg ;; Store the tokens in the augment list. They will be added 4605dfecf96Smrg ;; to the syntax table in the second pass. 4615dfecf96Smrg (setf (syntable-augments table) tokens) 4625dfecf96Smrg 4635dfecf96Smrg ;; Recurse on every child table. 4645dfecf96Smrg (dolist (child (syntable-tables table)) 4655dfecf96Smrg (compile-syntax-augment-list child table-list) 4665dfecf96Smrg ) 4675dfecf96Smrg) 4685dfecf96Smrg 4695dfecf96Smrg 4705dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4715dfecf96Smrg;; Just add the augmented tokens to the token list, recursing on 4725dfecf96Smrg;; every child syntax table. 4735dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4745dfecf96Smrg(defun link-syntax-augment-table (table) 4755dfecf96Smrg (setf 4765dfecf96Smrg (syntable-tokens table) 4775dfecf96Smrg ;; When augmenting a table, duplicated tokens or different tokens 4785dfecf96Smrg ;; that use the same regex pattern should be common. 4795dfecf96Smrg (remove-duplicates 4805dfecf96Smrg (nconc (syntable-tokens table) (syntable-augments table)) 4815dfecf96Smrg :key #'syntoken-regex 4825dfecf96Smrg :test #'equal 4835dfecf96Smrg :from-end t 4845dfecf96Smrg ) 4855dfecf96Smrg 4865dfecf96Smrg ;; Don't need to keep this list anymore. 4875dfecf96Smrg (syntable-augments table) 4885dfecf96Smrg () 4895dfecf96Smrg ) 4905dfecf96Smrg 4915dfecf96Smrg ;; Check if one of the tokens match the empty string at the 4925dfecf96Smrg ;; start or end of a text line. XXX The fields bol and eol 4935dfecf96Smrg ;; are expected to be initialized to NIL. 4945dfecf96Smrg (dolist (token (syntable-tokens table)) 4955dfecf96Smrg (when (consp (re-exec (syntoken-regex token) "" :noteol t)) 4965dfecf96Smrg (setf (syntable-bol table) t) 4975dfecf96Smrg (return) 4985dfecf96Smrg ) 4995dfecf96Smrg ) 5005dfecf96Smrg (dolist (token (syntable-tokens table)) 5015dfecf96Smrg (when (consp (re-exec (syntoken-regex token) "" :notbol t)) 5025dfecf96Smrg (setf (syntable-eol table) t) 5035dfecf96Smrg (return) 5045dfecf96Smrg ) 5055dfecf96Smrg ) 5065dfecf96Smrg 5075dfecf96Smrg (dolist (child (syntable-tables table)) 5085dfecf96Smrg (link-syntax-augment-table child) 5095dfecf96Smrg ) 5105dfecf96Smrg) 5115dfecf96Smrg 5125dfecf96Smrg 5135dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 5145dfecf96Smrg;; "Compile" the main structure of the syntax highlight code. 5155dfecf96Smrg;; Variables "switches" and "begins" are used only for error checking. 5165dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 5175dfecf96Smrg(defun compile-syntax-table (name options main-table &aux syntax elements 5185dfecf96Smrg switches begins tables properties) 5195dfecf96Smrg (unless (stringp name) 5205dfecf96Smrg (error "COMPILE-SYNTAX-TABLE: ~A is not a string" name) 5215dfecf96Smrg ) 5225dfecf96Smrg 5235dfecf96Smrg (setq 5245dfecf96Smrg elements 5255dfecf96Smrg (list-syntable-elements main-table) 5265dfecf96Smrg 5275dfecf96Smrg switches 5285dfecf96Smrg (remove-if 5295dfecf96Smrg #'null 5305dfecf96Smrg (car elements) 5315dfecf96Smrg :key #'syntoken-switch 5325dfecf96Smrg ) 5335dfecf96Smrg 5345dfecf96Smrg begins 5355dfecf96Smrg (remove-if-not 5365dfecf96Smrg #'keywordp 5375dfecf96Smrg (car elements) 5385dfecf96Smrg :key #'syntoken-begin 5395dfecf96Smrg ) 5405dfecf96Smrg 5415dfecf96Smrg ;; The "main-table" isn't in the list, because 5425dfecf96Smrg ;; list-syntable-elements includes only the child tables; 5435dfecf96Smrg ;; this is done to avoid the need of removing duplicates here. 5445dfecf96Smrg tables 5455dfecf96Smrg (cons main-table (cdr elements)) 5465dfecf96Smrg ) 5475dfecf96Smrg 5485dfecf96Smrg ;; Check for typos in the keywords, or for not defined syntax tables. 5495dfecf96Smrg (dolist (item (mapcar #'syntoken-switch switches)) 5505dfecf96Smrg (unless 5515dfecf96Smrg (or 5525dfecf96Smrg (and 5535dfecf96Smrg (integerp item) 5545dfecf96Smrg (minusp item) 5555dfecf96Smrg ) 5565dfecf96Smrg (member item tables :key #'syntable-label) 5575dfecf96Smrg ) 5585dfecf96Smrg (error "COMPILE-SYNTAX-TABLE: SWITCH ~A cannot be matched" 5595dfecf96Smrg item 5605dfecf96Smrg ) 5615dfecf96Smrg ) 5625dfecf96Smrg ) 5635dfecf96Smrg (dolist (item (mapcar #'syntoken-begin begins)) 5645dfecf96Smrg (unless (member item tables :key #'syntable-label) 5655dfecf96Smrg (error "COMPILE-SYNTAX-TABLE: BEGIN ~A cannot be matched" 5665dfecf96Smrg item 5675dfecf96Smrg ) 5685dfecf96Smrg ) 5695dfecf96Smrg ) 5705dfecf96Smrg 5715dfecf96Smrg ;; Create a list of all properties used by the syntax. 5725dfecf96Smrg (setq 5735dfecf96Smrg properties 5745dfecf96Smrg (delete-duplicates 5755dfecf96Smrg 5765dfecf96Smrg ;; Remove explicitly set to "default" properties. 5775dfecf96Smrg (remove nil 5785dfecf96Smrg 5795dfecf96Smrg (append 5805dfecf96Smrg 5815dfecf96Smrg ;; List all properties in the syntoken list. 5825dfecf96Smrg (mapcar 5835dfecf96Smrg #'syntoken-property 5845dfecf96Smrg (car elements) 5855dfecf96Smrg ) 5865dfecf96Smrg 5875dfecf96Smrg ;; List all properties in the syntable list. 5885dfecf96Smrg (mapcar 5895dfecf96Smrg #'syntable-property 5905dfecf96Smrg tables 5915dfecf96Smrg ) 5925dfecf96Smrg ) 5935dfecf96Smrg ) 5945dfecf96Smrg :test #'string= 5955dfecf96Smrg :key #'synprop-name 5965dfecf96Smrg ) 5975dfecf96Smrg ) 5985dfecf96Smrg 5995dfecf96Smrg ;; Provide a default property if none specified. 6005dfecf96Smrg (unless 6015dfecf96Smrg (member 6025dfecf96Smrg "default" 6035dfecf96Smrg properties 6045dfecf96Smrg :test #'string= 6055dfecf96Smrg :key #'synprop-name 6065dfecf96Smrg ) 6075dfecf96Smrg (setq properties (append (list *prop-default*) properties)) 6085dfecf96Smrg ) 6095dfecf96Smrg 6105dfecf96Smrg 6115dfecf96Smrg ;; Now that a list of all nested syntax tables is known, compile the 6125dfecf96Smrg ;; augment list. Note that even the main-table can be augmented to 6135dfecf96Smrg ;; include tokens of one of it's children. 6145dfecf96Smrg 6155dfecf96Smrg ;; Adding the tokens of the augment tables must be done in 6165dfecf96Smrg ;; two passes, or it may cause surprises due to "inherited" 6175dfecf96Smrg ;; tokens, as the augment table was processed first, and 6185dfecf96Smrg ;; increased it's token list. 6195dfecf96Smrg (compile-syntax-augment-list main-table tables) 6205dfecf96Smrg 6215dfecf96Smrg ;; Now just append the augmented tokens to the table's token list. 6225dfecf96Smrg (link-syntax-augment-table main-table) 6235dfecf96Smrg 6245dfecf96Smrg ;; Change all syntoken switch and begin fields to point to the 6255dfecf96Smrg ;; syntable. 6265dfecf96Smrg (dolist (item switches) 6275dfecf96Smrg (if (keywordp (syntoken-switch item)) 6285dfecf96Smrg ;; A switch may be relative, check if a keyword 6295dfecf96Smrg ;; was specified. 6305dfecf96Smrg (setf 6315dfecf96Smrg (syntoken-switch item) 6325dfecf96Smrg (car 6335dfecf96Smrg (member 6345dfecf96Smrg (syntoken-switch item) 6355dfecf96Smrg tables 6365dfecf96Smrg :key #'syntable-label 6375dfecf96Smrg ) 6385dfecf96Smrg ) 6395dfecf96Smrg ) 6405dfecf96Smrg ) 6415dfecf96Smrg ) 6425dfecf96Smrg (dolist (item begins) 6435dfecf96Smrg (setf 6445dfecf96Smrg (syntoken-begin item) 6455dfecf96Smrg (car 6465dfecf96Smrg (member 6475dfecf96Smrg (syntoken-begin item) 6485dfecf96Smrg tables 6495dfecf96Smrg :key #'syntable-label 6505dfecf96Smrg ) 6515dfecf96Smrg ) 6525dfecf96Smrg ) 6535dfecf96Smrg ) 6545dfecf96Smrg 6555dfecf96Smrg ;; Don't need to add a entity for default properties 6565dfecf96Smrg (dolist (item (car elements)) 6575dfecf96Smrg (and 6585dfecf96Smrg (syntoken-property item) 6595dfecf96Smrg (string= (synprop-name (syntoken-property item)) "default") 6605dfecf96Smrg (setf (syntoken-property item) ()) 6615dfecf96Smrg ) 6625dfecf96Smrg ) 6635dfecf96Smrg (dolist (item tables) 6645dfecf96Smrg (and 6655dfecf96Smrg (syntable-property item) 6665dfecf96Smrg (string= (synprop-name (syntable-property item)) "default") 6675dfecf96Smrg (setf (syntable-property item) ()) 6685dfecf96Smrg ) 6695dfecf96Smrg ) 6705dfecf96Smrg 6715dfecf96Smrg (setq syntax 6725dfecf96Smrg (make-syntax 6735dfecf96Smrg :name name 6745dfecf96Smrg :options options 6755dfecf96Smrg :labels tables 6765dfecf96Smrg :quark 6775dfecf96Smrg (compile-syntax-property-list 6785dfecf96Smrg name 6795dfecf96Smrg properties 6805dfecf96Smrg ) 6815dfecf96Smrg :token-count 6825dfecf96Smrg (length (car elements)) 6835dfecf96Smrg ) 6845dfecf96Smrg ) 6855dfecf96Smrg 6865dfecf96Smrg ;; Ready to run! 6875dfecf96Smrg) 6885dfecf96Smrg 6895dfecf96Smrg 6905dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6915dfecf96Smrg;; Loop applying the specifed syntax table to the text. 6925dfecf96Smrg;; XXX This function needs a review. Should compile the regex patterns 6935dfecf96Smrg;; with newline sensitive match (and scan the entire file), and keep a 6945dfecf96Smrg;; cache of matched tokens (that may be at a very longer offset), and, 6955dfecf96Smrg;; when the match is removed from the cache, readd the token to the 6965dfecf96Smrg;; token-list; if the token does not match, it will not be in the cache, 6975dfecf96Smrg;; but should be removed from the token-list. If properly implemented, it 6985dfecf96Smrg;; should be somewhat like 4 times faster, but I would not be surprised 6995dfecf96Smrg;; if it becames even faster. 7005dfecf96Smrg;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 7015dfecf96Smrg(defun syntax-highlight (*syntax* 7025dfecf96Smrg &optional 7035dfecf96Smrg (*from* (point-min)) 7045dfecf96Smrg (*to* (point-max)) 7055dfecf96Smrg interactive 7065dfecf96Smrg &aux 7075dfecf96Smrg#+debug (*line-number* 0) 7085dfecf96Smrg stream 7095dfecf96Smrg indent-table 7105dfecf96Smrg ) 7115dfecf96Smrg 7125dfecf96Smrg ;; Make sure the property list is in use. 7135dfecf96Smrg ;; The interactive flag is only set after loading the file. 7145dfecf96Smrg (or interactive 7155dfecf96Smrg (property-list (syntax-quark *syntax*)) 7165dfecf96Smrg ) 7175dfecf96Smrg 7185dfecf96Smrg#+debug 7195dfecf96Smrg (setq *from* 0 *to* 0) 7205dfecf96Smrg 7215dfecf96Smrg#-debug 7225dfecf96Smrg (and (>= *from* *to*) (return-from syntax-highlight (values *from* nil))) 7235dfecf96Smrg 7245dfecf96Smrg ;; Remove any existing properties from the text. 7255dfecf96Smrg (clear-entities *from* (1+ *to*)) 7265dfecf96Smrg 7275dfecf96Smrg (setq stream 7285dfecf96Smrg#-debug (make-string-input-stream (read-text *from* (- *to* *from*))) 7295dfecf96Smrg#+debug *standard-input* 7305dfecf96Smrg ) 7315dfecf96Smrg 7325dfecf96Smrg (prog* 7335dfecf96Smrg ( 7345dfecf96Smrg ;; Used to check if end of file found but syntax stack did 7355dfecf96Smrg ;; not finish. 7365dfecf96Smrg (point-max (point-max)) 7375dfecf96Smrg 7385dfecf96Smrg ;; Used in interactive mode, to return the syntax table 7395dfecf96Smrg ;; where the cursor is located. 7405dfecf96Smrg (point (point)) 7415dfecf96Smrg 7425dfecf96Smrg ;; The current stack of states. 7435dfecf96Smrg stack 7445dfecf96Smrg 7455dfecf96Smrg ;; The current syntable. 7465dfecf96Smrg (syntax-table (car (syntax-labels *syntax*))) 7475dfecf96Smrg 7485dfecf96Smrg ;; The current syntable's default property. 7495dfecf96Smrg (default-property (syntable-property syntax-table)) 7505dfecf96Smrg 7515dfecf96Smrg ;; Add this property to newlines as a hint to the interactive 7525dfecf96Smrg ;; callback, so that it knows from where to restart parsing. 7535dfecf96Smrg newline-property 7545dfecf96Smrg 7555dfecf96Smrg ;; The tokens in the current syntax table that may match, 7565dfecf96Smrg ;; i.e. the items in this list are not in nomatch. 7575dfecf96Smrg token-list 7585dfecf96Smrg 7595dfecf96Smrg ;; A pointer to the syntable token list, if token-list is 7605dfecf96Smrg ;; eq to this value, cannot change it inplace. 7615dfecf96Smrg current-token-list 7625dfecf96Smrg 7635dfecf96Smrg ;; Help to avoid allocating too many new object cells, and 7645dfecf96Smrg ;; optmizes a bit time in [n]?set-difference. 7655dfecf96Smrg ;; This optimizes only the processing of one line of text 7665dfecf96Smrg ;; as nomatch must be rebuilt when reading a new line of text. 7675dfecf96Smrg token-list-stack 7685dfecf96Smrg 7695dfecf96Smrg ;; Matches for the current list of tokens. 7705dfecf96Smrg matches 7715dfecf96Smrg 7725dfecf96Smrg ;; Line of text. 7735dfecf96Smrg line 7745dfecf96Smrg 7755dfecf96Smrg ;; Length of the text line. 7765dfecf96Smrg length 7775dfecf96Smrg 7785dfecf96Smrg ;; A inverse cache, don't call re-exec when the regex is 7795dfecf96Smrg ;; already known to not match. 7805dfecf96Smrg nomatch 7815dfecf96Smrg 7825dfecf96Smrg ;; Use cache as a list of matches to avoid repetitive 7835dfecf96Smrg ;; unnecessary calls to re-exec. 7845dfecf96Smrg ;; cache is a list in which every element has the format: 7855dfecf96Smrg ;; (token . (start . end)) 7865dfecf96Smrg ;; Line of text. 7875dfecf96Smrg cache 7885dfecf96Smrg 7895dfecf96Smrg ;; Used just to avoid a function call at every re-exec call. 7905dfecf96Smrg notbol 7915dfecf96Smrg 7925dfecf96Smrg match 7935dfecf96Smrg 7945dfecf96Smrg start 7955dfecf96Smrg left 7965dfecf96Smrg right 7975dfecf96Smrg result 7985dfecf96Smrg property 7995dfecf96Smrg 8005dfecf96Smrg ;; Beginig a new syntax table? 8015dfecf96Smrg begin 8025dfecf96Smrg 8035dfecf96Smrg ;; Switching to another syntax table? 8045dfecf96Smrg switch 8055dfecf96Smrg 8065dfecf96Smrg ;; Property flag when changing the current syntax table. 8075dfecf96Smrg contained 8085dfecf96Smrg 8095dfecf96Smrg ;; Flag to know if syntax table has changed. 8105dfecf96Smrg change 8115dfecf96Smrg 8125dfecf96Smrg ;; Variables used when removing invalid elements from the 8135dfecf96Smrg ;; the cache. 8145dfecf96Smrg item 8155dfecf96Smrg from 8165dfecf96Smrg to 8175dfecf96Smrg ) 8185dfecf96Smrg 8195dfecf96Smrg;----------------------------------------------------------------------- 8205dfecf96Smrg:read 8215dfecf96Smrg#+debug-verbose 8225dfecf96Smrg (format t "** Entering :READ stack length is ~D~%" (length stack)) 8235dfecf96Smrg#+debug (format t "~%[~D]> " (incf *line-number*)) 8245dfecf96Smrg 8255dfecf96Smrg ;; If input has finished, return. 8265dfecf96Smrg (unless (setq line (read-line stream nil nil)) 8275dfecf96Smrg (when 8285dfecf96Smrg (and 8295dfecf96Smrg ;; If a nested syntax table wasn't finished 8305dfecf96Smrg (consp stack) 8315dfecf96Smrg (< 8325dfecf96Smrg (setq *to* (scan *from* :eol :right)) 8335dfecf96Smrg point-max 8345dfecf96Smrg ) 8355dfecf96Smrg ) 8365dfecf96Smrg (setq line (read-text *from* (- *to* *from*))) 8375dfecf96Smrg (clear-entities *from* (1+ *to*)) 8385dfecf96Smrg (go :again) 8395dfecf96Smrg ) 8405dfecf96Smrg#-debug (close stream) 8415dfecf96Smrg (return) 8425dfecf96Smrg ) 8435dfecf96Smrg 8445dfecf96Smrg;------------------------------------------------------------------------ 8455dfecf96Smrg:again 8465dfecf96Smrg (setq 8475dfecf96Smrg start 0 8485dfecf96Smrg length (length line) 8495dfecf96Smrg token-list (syntable-tokens syntax-table) 8505dfecf96Smrg current-token-list token-list 8515dfecf96Smrg token-list-stack () 8525dfecf96Smrg nomatch () 8535dfecf96Smrg cache () 8545dfecf96Smrg ) 8555dfecf96Smrg 8565dfecf96Smrg 8575dfecf96Smrg ;; If empty line, and current table does not have matches for 8585dfecf96Smrg ;; the empty string at start or end of a text line. 8595dfecf96Smrg (when 8605dfecf96Smrg (and 8615dfecf96Smrg (= length 0) 8625dfecf96Smrg (not (syntable-eol syntax-table)) 8635dfecf96Smrg (not (syntable-bol syntax-table))) 8645dfecf96Smrg#+debug-verbose 8655dfecf96Smrg (format t "Empty line and table has no match to bol or eol~%") 8665dfecf96Smrg 8675dfecf96Smrg (and newline-property 8685dfecf96Smrg (add-entity *from* 1 (synprop-quark newline-property))) 8695dfecf96Smrg (go :update) 8705dfecf96Smrg ) 8715dfecf96Smrg 8725dfecf96Smrg;------------------------------------------------------------------------ 8735dfecf96Smrg:loop 8745dfecf96Smrg#+debug-verbose 8755dfecf96Smrg (format t "** Entering :LOOP at offset ~D in table ~A, cache has ~D items~%" 8765dfecf96Smrg start 8775dfecf96Smrg (syntable-label syntax-table) 8785dfecf96Smrg (length cache)) 8795dfecf96Smrg 8805dfecf96Smrg (setq notbol (> start 0)) 8815dfecf96Smrg 8825dfecf96Smrg ;; For every token that may match. 8835dfecf96Smrg (dolist 8845dfecf96Smrg (token 8855dfecf96Smrg (setq 8865dfecf96Smrg token-list 8875dfecf96Smrg (if (eq token-list current-token-list) 8885dfecf96Smrg (set-difference token-list nomatch :test #'eq) 8895dfecf96Smrg (nset-difference token-list nomatch :test #'eq) 8905dfecf96Smrg ) 8915dfecf96Smrg ) 8925dfecf96Smrg ) 8935dfecf96Smrg 8945dfecf96Smrg ;; Try to fetch match from cache. 8955dfecf96Smrg (if (setq match (member token cache :test #'eq :key #'car)) 8965dfecf96Smrg ;; Match is in the cache. 8975dfecf96Smrg 8985dfecf96Smrg (progn 8995dfecf96Smrg ;; Match must be moved to the beginning of the 9005dfecf96Smrg ;; matches list, as a match from another syntax 9015dfecf96Smrg ;; table may be also in the cache, but before 9025dfecf96Smrg ;; the match for the current token. 9035dfecf96Smrg#+debug-verbose (format t "cached: {~A:~S} ~A~%" 9045dfecf96Smrg (cdar match) 9055dfecf96Smrg (subseq line (cadar match) (cddar match)) 9065dfecf96Smrg (syntoken-regex token)) 9075dfecf96Smrg 9085dfecf96Smrg ;; Remove the match from the cache. 9095dfecf96Smrg (if (eq match cache) 9105dfecf96Smrg 9115dfecf96Smrg ;; This could be changed to only set "matches" 9125dfecf96Smrg ;; if it is not the first element of cache, 9135dfecf96Smrg ;; but is unsafe, because other tokens may 9145dfecf96Smrg ;; be added to "matches", and will end up 9155dfecf96Smrg ;; before when joining "matches" and "cache". 9165dfecf96Smrg (progn 9175dfecf96Smrg (setq cache (cdr cache)) 9185dfecf96Smrg (rplacd match matches) 9195dfecf96Smrg (setq matches match)) 9205dfecf96Smrg 9215dfecf96Smrg (progn 9225dfecf96Smrg (if (= (length match) 1) 9235dfecf96Smrg (progn 9245dfecf96Smrg (rplacd (last cache 2) nil) 9255dfecf96Smrg (rplacd match matches) 9265dfecf96Smrg (setq matches match)) 9275dfecf96Smrg (progn 9285dfecf96Smrg (setq matches (cons (car match) matches)) 9295dfecf96Smrg (rplaca match (cadr match)) 9305dfecf96Smrg (rplacd match (cddr match))) 9315dfecf96Smrg ) 9325dfecf96Smrg ) 9335dfecf96Smrg ) 9345dfecf96Smrg 9355dfecf96Smrg ;; Exit loop if the all the remaining 9365dfecf96Smrg ;; input was matched. 9375dfecf96Smrg (when 9385dfecf96Smrg (and 9395dfecf96Smrg (= start (cadar match)) 9405dfecf96Smrg (= length (cddar match)) 9415dfecf96Smrg ) 9425dfecf96Smrg#+debug-verbose (format t "Rest of line match~%") 9435dfecf96Smrg (return) 9445dfecf96Smrg ) 9455dfecf96Smrg ) 9465dfecf96Smrg 9475dfecf96Smrg ;; Not in the cache, call re-exec. 9485dfecf96Smrg (if 9495dfecf96Smrg (consp 9505dfecf96Smrg (setq 9515dfecf96Smrg match 9525dfecf96Smrg (re-exec 9535dfecf96Smrg (syntoken-regex token) 9545dfecf96Smrg line 9555dfecf96Smrg :start start 9565dfecf96Smrg :notbol notbol))) 9575dfecf96Smrg 9585dfecf96Smrg ;; Match found. 9595dfecf96Smrg (progn 9605dfecf96Smrg#+debug-verbose (format t "Adding to cache: {~A:~S} ~A~%" 9615dfecf96Smrg (car match) 9625dfecf96Smrg (subseq line (caar match) (cdar match)) 9635dfecf96Smrg (syntoken-regex token)) 9645dfecf96Smrg 9655dfecf96Smrg ;; Only the first pair is used. 9665dfecf96Smrg (setq match (car match)) 9675dfecf96Smrg 9685dfecf96Smrg (cond 9695dfecf96Smrg ( 9705dfecf96Smrg (or 9715dfecf96Smrg (null matches) 9725dfecf96Smrg ;; No overlap and after most 9735dfecf96Smrg ;; recent match. 9745dfecf96Smrg (>= (car match) (cddar matches)) 9755dfecf96Smrg ;; No overlap and before most 9765dfecf96Smrg ;; recent match. 9775dfecf96Smrg (<= (cdr match) (cadar matches)) 9785dfecf96Smrg ) 9795dfecf96Smrg (setq 9805dfecf96Smrg matches 9815dfecf96Smrg (cons (cons token match) matches) 9825dfecf96Smrg ) 9835dfecf96Smrg ) 9845dfecf96Smrg ( 9855dfecf96Smrg (or 9865dfecf96Smrg ;; Overlap, but start before most 9875dfecf96Smrg ;; recent match. 9885dfecf96Smrg (< (car match) (cadar matches)) 9895dfecf96Smrg (and 9905dfecf96Smrg ;; Same offset as most recent 9915dfecf96Smrg ;; match, but is longer. 9925dfecf96Smrg (= (car match) (cadar matches)) 9935dfecf96Smrg (> (cdr match) (cddar matches)) 9945dfecf96Smrg ) 9955dfecf96Smrg ) 9965dfecf96Smrg (rplaca (car matches) token) 9975dfecf96Smrg (rplacd (car matches) match) 9985dfecf96Smrg#+debug-verbose (format t "Replaced most recent match~%") 9995dfecf96Smrg ) 10005dfecf96Smrg (t 10015dfecf96Smrg#+debug-verbose (format t "Ignored~%") 10025dfecf96Smrg ;; XXX The interpreter does not yet implement 10035dfecf96Smrg ;; implicit tagbody in dolist, just comment 10045dfecf96Smrg ;; the go call in that case. (Will just do 10055dfecf96Smrg ;; an unecessary test...) 10065dfecf96Smrg (go :ignored) 10075dfecf96Smrg ) 10085dfecf96Smrg ) 10095dfecf96Smrg 10105dfecf96Smrg ;; Exit loop if the all the remaining 10115dfecf96Smrg ;; input was matched. 10125dfecf96Smrg (when 10135dfecf96Smrg (and 10145dfecf96Smrg (= start (car match)) 10155dfecf96Smrg (= length (cdr match))) 10165dfecf96Smrg#+debug-verbose (format t "Rest of line match~%") 10175dfecf96Smrg (return)) 10185dfecf96Smrg ) 10195dfecf96Smrg 10205dfecf96Smrg ;; Match not found. 10215dfecf96Smrg (progn 10225dfecf96Smrg#+debug-verbose (format t "Adding to nomatch: ~A~%" 10235dfecf96Smrg (syntoken-regex token)) 10245dfecf96Smrg (setq nomatch (cons token nomatch))) 10255dfecf96Smrg ) 10265dfecf96Smrg ) 10275dfecf96Smrg:ignored 10285dfecf96Smrg ) 10295dfecf96Smrg 10305dfecf96Smrg ;; Add matches to the beginning of the cache list. 10315dfecf96Smrg (setq 10325dfecf96Smrg ;; Put matches with smaller offset first. 10335dfecf96Smrg cache 10345dfecf96Smrg (stable-sort (nconc (nreverse matches) cache) #'< :key #'cadr) 10355dfecf96Smrg 10365dfecf96Smrg ;; Make sure that when the match loop is reentered, this 10375dfecf96Smrg ;; variable is NIL. 10385dfecf96Smrg matches 10395dfecf96Smrg () 10405dfecf96Smrg ) 10415dfecf96Smrg 10425dfecf96Smrg ;; While the first entry in the cache is not from the current table. 10435dfecf96Smrg (until (or (null cache) (member (caar cache) token-list :test #'eq)) 10445dfecf96Smrg 10455dfecf96Smrg#+debug-verbose 10465dfecf96Smrg (format t "Not in the current table, removing {~A:~S} ~A~%" 10475dfecf96Smrg (cdar cache) 10485dfecf96Smrg (subseq line (cadar cache) (cddar cache)) 10495dfecf96Smrg (syntoken-regex (caar cache))) 10505dfecf96Smrg 10515dfecf96Smrg (setq cache (cdr cache)) 10525dfecf96Smrg ) 10535dfecf96Smrg 10545dfecf96Smrg 10555dfecf96Smrg ;; If nothing was matched in the entire/remaining line. 10565dfecf96Smrg (unless cache 10575dfecf96Smrg (when default-property 10585dfecf96Smrg (if 10595dfecf96Smrg (or 10605dfecf96Smrg (null result) 10615dfecf96Smrg (> start (cadar result)) 10625dfecf96Smrg (not (eq (cddar result) default-property))) 10635dfecf96Smrg (setq 10645dfecf96Smrg result 10655dfecf96Smrg (cons 10665dfecf96Smrg (cons start (cons length default-property)) 10675dfecf96Smrg result 10685dfecf96Smrg ) 10695dfecf96Smrg ) 10705dfecf96Smrg (rplaca (cdar result) length) 10715dfecf96Smrg ) 10725dfecf96Smrg ) 10735dfecf96Smrg 10745dfecf96Smrg#+debug-verbose 10755dfecf96Smrg (format t "No match until end of line~%") 10765dfecf96Smrg 10775dfecf96Smrg ;; Result already known, and there is no syntax table 10785dfecf96Smrg ;; change, bypass :PARSE. 10795dfecf96Smrg (and interactive 10805dfecf96Smrg (null indent-table) 10815dfecf96Smrg (<= 0 (- point *from*) length) 10825dfecf96Smrg (setq indent-table syntax-table)) 10835dfecf96Smrg (go :process) 10845dfecf96Smrg ) 10855dfecf96Smrg 10865dfecf96Smrg#+debug-verbose 10875dfecf96Smrg (format t "Removing first candidate from cache {~A:~S} ~A~%" 10885dfecf96Smrg (cdar cache) 10895dfecf96Smrg (subseq line (cadar cache) (cddar cache)) 10905dfecf96Smrg (syntoken-regex (caar cache)) 10915dfecf96Smrg ) 10925dfecf96Smrg 10935dfecf96Smrg ;; Prepare to choose best match. 10945dfecf96Smrg (setq 10955dfecf96Smrg match (car cache) 10965dfecf96Smrg left (cadr match) 10975dfecf96Smrg right (cddr match) 10985dfecf96Smrg cache (cdr cache) 10995dfecf96Smrg ) 11005dfecf96Smrg 11015dfecf96Smrg ;; First element can be safely removed now. 11025dfecf96Smrg ;; If there is only one, skip loop below. 11035dfecf96Smrg (or cache (go :parse)) 11045dfecf96Smrg 11055dfecf96Smrg ;; Remove elements of cache that must be discarded. 11065dfecf96Smrg (setq 11075dfecf96Smrg item (car cache) 11085dfecf96Smrg from (cadr item) 11095dfecf96Smrg to (cddr item) 11105dfecf96Smrg ) 11115dfecf96Smrg 11125dfecf96Smrg (loop 11135dfecf96Smrg (if 11145dfecf96Smrg (or 11155dfecf96Smrg 11165dfecf96Smrg ;; If everything removed from the cache. 11175dfecf96Smrg (null item) 11185dfecf96Smrg 11195dfecf96Smrg ;; Or next item is at a longer offset than the 11205dfecf96Smrg ;; end of current match. 11215dfecf96Smrg (>= from right) 11225dfecf96Smrg ) 11235dfecf96Smrg (return) 11245dfecf96Smrg ) 11255dfecf96Smrg 11265dfecf96Smrg (and 11275dfecf96Smrg ;; If another match at the same offset. 11285dfecf96Smrg (= left from) 11295dfecf96Smrg 11305dfecf96Smrg ;; And if this match is longer than the current one. 11315dfecf96Smrg (> to right) 11325dfecf96Smrg 11335dfecf96Smrg (member (car item) token-list :test #'eq) 11345dfecf96Smrg 11355dfecf96Smrg (setq 11365dfecf96Smrg match item 11375dfecf96Smrg right to 11385dfecf96Smrg ) 11395dfecf96Smrg ) 11405dfecf96Smrg 11415dfecf96Smrg#+debug-verbose 11425dfecf96Smrg (format t "Removing from cache {~A:~S} ~A~%" 11435dfecf96Smrg (cdar cache) 11445dfecf96Smrg (subseq line from to) 11455dfecf96Smrg (syntoken-regex (caar cache))) 11465dfecf96Smrg 11475dfecf96Smrg (setq 11485dfecf96Smrg cache (cdr cache) 11495dfecf96Smrg item (car cache) 11505dfecf96Smrg from (cadr item) 11515dfecf96Smrg to (cddr item) 11525dfecf96Smrg ) 11535dfecf96Smrg ) 11545dfecf96Smrg 11555dfecf96Smrg 11565dfecf96Smrg;----------------------------------------------------------------------- 11575dfecf96Smrg:parse 11585dfecf96Smrg#+debug-verbose 11595dfecf96Smrg (format t "** Entering :PARSE~%") 11605dfecf96Smrg 11615dfecf96Smrg (setq 11625dfecf96Smrg 11635dfecf96Smrg ;; Change match value to the syntoken. 11645dfecf96Smrg match (car match) 11655dfecf96Smrg 11665dfecf96Smrg begin (syntoken-begin match) 11675dfecf96Smrg switch (syntoken-switch match) 11685dfecf96Smrg contained (syntoken-contained match) 11695dfecf96Smrg change (or begin switch) 11705dfecf96Smrg ) 11715dfecf96Smrg 11725dfecf96Smrg ;; Check for unmatched leading text. 11735dfecf96Smrg (when (and default-property (> left start)) 11745dfecf96Smrg#+debug-verbose (format t "No match in {(~D . ~D):~S}~%" 11755dfecf96Smrg start 11765dfecf96Smrg left 11775dfecf96Smrg (subseq line start left) 11785dfecf96Smrg ) 11795dfecf96Smrg (if 11805dfecf96Smrg (or 11815dfecf96Smrg (null result) 11825dfecf96Smrg (> start (cadar result)) 11835dfecf96Smrg (not (eq (cddar result) default-property))) 11845dfecf96Smrg (setq 11855dfecf96Smrg result 11865dfecf96Smrg (cons 11875dfecf96Smrg (cons start (cons left default-property)) 11885dfecf96Smrg result 11895dfecf96Smrg ) 11905dfecf96Smrg ) 11915dfecf96Smrg (rplaca (cdar result) left) 11925dfecf96Smrg ) 11935dfecf96Smrg ) 11945dfecf96Smrg 11955dfecf96Smrg ;; If the syntax table is not changed, 11965dfecf96Smrg ;; or if the new table requires that the 11975dfecf96Smrg ;; current default property be used. 11985dfecf96Smrg (unless (and change contained) 11995dfecf96Smrg 12005dfecf96Smrg (and 12015dfecf96Smrg (> right left) 12025dfecf96Smrg (setq 12035dfecf96Smrg property 12045dfecf96Smrg (or 12055dfecf96Smrg ;; If token specifies the property. 12065dfecf96Smrg (syntoken-property match) 12075dfecf96Smrg default-property 12085dfecf96Smrg ) 12095dfecf96Smrg ) 12105dfecf96Smrg 12115dfecf96Smrg ;; Add matched text. 12125dfecf96Smrg (if 12135dfecf96Smrg (or 12145dfecf96Smrg (null result) 12155dfecf96Smrg (> left (cadar result)) 12165dfecf96Smrg (not (eq (cddar result) property)) 12175dfecf96Smrg ) 12185dfecf96Smrg (setq 12195dfecf96Smrg result 12205dfecf96Smrg (cons 12215dfecf96Smrg (cons left (cons right property)) 12225dfecf96Smrg result 12235dfecf96Smrg ) 12245dfecf96Smrg ) 12255dfecf96Smrg (rplaca (cdar result) right) 12265dfecf96Smrg ) 12275dfecf96Smrg ) 12285dfecf96Smrg 12295dfecf96Smrg#+debug-verbose 12305dfecf96Smrg (format t "(0)Match found for {(~D . ~D):~S}~%" 12315dfecf96Smrg left 12325dfecf96Smrg right 12335dfecf96Smrg (subseq line left right) 12345dfecf96Smrg ) 12355dfecf96Smrg ) 12365dfecf96Smrg 12375dfecf96Smrg 12385dfecf96Smrg ;; Update start offset in the input now! 12395dfecf96Smrg (and interactive 12405dfecf96Smrg (null indent-table) 12415dfecf96Smrg (<= start (- point *from*) right) 12425dfecf96Smrg (setq indent-table syntax-table)) 12435dfecf96Smrg (setq start right) 12445dfecf96Smrg 12455dfecf96Smrg 12465dfecf96Smrg ;; When changing the current syntax table. 12475dfecf96Smrg (when change 12485dfecf96Smrg (when switch 12495dfecf96Smrg (if (numberp switch) 12505dfecf96Smrg 12515dfecf96Smrg ;; If returning to a previous state. 12525dfecf96Smrg ;; Don't generate an error if the stack 12535dfecf96Smrg ;; becomes empty? 12545dfecf96Smrg (while 12555dfecf96Smrg (< switch 0) 12565dfecf96Smrg 12575dfecf96Smrg (setq 12585dfecf96Smrg syntax-table (pop stack) 12595dfecf96Smrg token-list (pop token-list-stack) 12605dfecf96Smrg switch (1+ switch) 12615dfecf96Smrg ) 12625dfecf96Smrg ) 12635dfecf96Smrg 12645dfecf96Smrg ;; Else, not to a previous state, but 12655dfecf96Smrg ;; returning to a named syntax table, 12665dfecf96Smrg ;; search for it in the stack. 12675dfecf96Smrg (while 12685dfecf96Smrg (and 12695dfecf96Smrg 12705dfecf96Smrg (setq 12715dfecf96Smrg token-list (pop token-list-stack) 12725dfecf96Smrg syntax-table (pop stack) 12735dfecf96Smrg ) 12745dfecf96Smrg 12755dfecf96Smrg (not (eq switch syntax-table)) 12765dfecf96Smrg ) 12775dfecf96Smrg ;; Empty loop. 12785dfecf96Smrg ) 12795dfecf96Smrg ) 12805dfecf96Smrg 12815dfecf96Smrg ;; If no match found while popping 12825dfecf96Smrg ;; the stack. 12835dfecf96Smrg (unless syntax-table 12845dfecf96Smrg 12855dfecf96Smrg ;; Return to the topmost syntax table. 12865dfecf96Smrg (setq 12875dfecf96Smrg syntax-table 12885dfecf96Smrg (car (syntax-labels *syntax*)) 12895dfecf96Smrg ) 12905dfecf96Smrg ) 12915dfecf96Smrg 12925dfecf96Smrg#+debug-verbose (format t "switching to ~A offset: ~D~%" 12935dfecf96Smrg (syntable-label syntax-table) 12945dfecf96Smrg start 12955dfecf96Smrg ) 12965dfecf96Smrg 12975dfecf96Smrg (if (null token-list) 12985dfecf96Smrg (setq token-list (syntable-tokens syntax-table)) 12995dfecf96Smrg ) 13005dfecf96Smrg ) 13015dfecf96Smrg 13025dfecf96Smrg (when begin 13035dfecf96Smrg ;; Save state for a possible 13045dfecf96Smrg ;; :SWITCH later. 13055dfecf96Smrg (setq 13065dfecf96Smrg stack (cons syntax-table stack) 13075dfecf96Smrg token-list-stack (cons token-list token-list-stack) 13085dfecf96Smrg token-list (syntable-tokens begin) 13095dfecf96Smrg syntax-table begin 13105dfecf96Smrg ) 13115dfecf96Smrg#+debug-verbose (format t "begining ~A offset: ~D~%" 13125dfecf96Smrg (syntable-label syntax-table) 13135dfecf96Smrg start 13145dfecf96Smrg ) 13155dfecf96Smrg ) 13165dfecf96Smrg 13175dfecf96Smrg ;; Change current syntax table. 13185dfecf96Smrg (setq 13195dfecf96Smrg default-property (syntable-property syntax-table) 13205dfecf96Smrg current-token-list (syntable-tokens syntax-table) 13215dfecf96Smrg ) 13225dfecf96Smrg 13235dfecf96Smrg ;; Set newline property, to help interactive callback 13245dfecf96Smrg ;; Only need to have a defined value, for now don't care 13255dfecf96Smrg ;; about wich value is being used, neither if there is 13265dfecf96Smrg ;; a value to be set. 13275dfecf96Smrg (if (null stack) 13285dfecf96Smrg (setq newline-property nil) 13295dfecf96Smrg (or newline-property 13305dfecf96Smrg (setq newline-property default-property) 13315dfecf96Smrg (setq newline-property (syntoken-property match)) 13325dfecf96Smrg ) 13335dfecf96Smrg ) 13345dfecf96Smrg 13355dfecf96Smrg ;; If processing of text was deferred. 13365dfecf96Smrg (when contained 13375dfecf96Smrg 13385dfecf96Smrg (and 13395dfecf96Smrg (> right left) 13405dfecf96Smrg (setq 13415dfecf96Smrg property 13425dfecf96Smrg (or 13435dfecf96Smrg (syntoken-property match) 13445dfecf96Smrg default-property 13455dfecf96Smrg ) 13465dfecf96Smrg ) 13475dfecf96Smrg ;; Add matched text with the updated property. 13485dfecf96Smrg (if 13495dfecf96Smrg (or 13505dfecf96Smrg (null result) 13515dfecf96Smrg (> left (cadar result)) 13525dfecf96Smrg (not (eq (cddar result) property)) 13535dfecf96Smrg ) 13545dfecf96Smrg (setq 13555dfecf96Smrg result 13565dfecf96Smrg (cons 13575dfecf96Smrg (cons left (cons right property)) 13585dfecf96Smrg result 13595dfecf96Smrg ) 13605dfecf96Smrg ) 13615dfecf96Smrg (rplaca (cdar result) right) 13625dfecf96Smrg ) 13635dfecf96Smrg ) 13645dfecf96Smrg 13655dfecf96Smrg#+debug-verbose (format t "(1)Match found for {(~D . ~D):~S}~%" 13665dfecf96Smrg left 13675dfecf96Smrg right 13685dfecf96Smrg (subseq line left right) 13695dfecf96Smrg ) 13705dfecf96Smrg ) 13715dfecf96Smrg 13725dfecf96Smrg (go :loop) 13735dfecf96Smrg ) 13745dfecf96Smrg 13755dfecf96Smrg 13765dfecf96Smrg;----------------------------------------------------------------------- 13775dfecf96Smrg ;; Wait for the end of the line to process, so that 13785dfecf96Smrg ;; it is possible to join sequential matches with the 13795dfecf96Smrg ;; same text property. 13805dfecf96Smrg (and (or cache (< start length)) (go :loop)) 13815dfecf96Smrg:process 13825dfecf96Smrg 13835dfecf96Smrg#+debug-verbose 13845dfecf96Smrg (format t "** Entering :PROCESS~%") 13855dfecf96Smrg 13865dfecf96Smrg (if result 13875dfecf96Smrg (progn 13885dfecf96Smrg ;; If the last property was at the end of the line, 13895dfecf96Smrg ;; there are nested syntax tables, and there is a 13905dfecf96Smrg ;; default property, include the newline in the property, 13915dfecf96Smrg ;; as a hint to the interactive callback. 13925dfecf96Smrg (and 13935dfecf96Smrg newline-property 13945dfecf96Smrg (if 13955dfecf96Smrg (and 13965dfecf96Smrg (eq (cddar result) newline-property) 13975dfecf96Smrg (= length (cadar result)) 13985dfecf96Smrg ) 13995dfecf96Smrg (rplaca (cdar result) (1+ length)) 14005dfecf96Smrg (setq 14015dfecf96Smrg result 14025dfecf96Smrg (cons 14035dfecf96Smrg (cons length (cons (1+ length) newline-property)) 14045dfecf96Smrg result 14055dfecf96Smrg ) 14065dfecf96Smrg ) 14075dfecf96Smrg ) 14085dfecf96Smrg ) 14095dfecf96Smrg 14105dfecf96Smrg ;; Result was created in reversed order. 14115dfecf96Smrg (nreverse result) 14125dfecf96Smrg (dolist (item result) 14135dfecf96Smrg (setq 14145dfecf96Smrg left (car item) 14155dfecf96Smrg right (cadr item) 14165dfecf96Smrg property (cddr item)) 14175dfecf96Smrg 14185dfecf96Smrg ;; Use the information. 14195dfecf96Smrg (add-entity 14205dfecf96Smrg (+ *from* left) 14215dfecf96Smrg (- right left) 14225dfecf96Smrg (synprop-quark property)) 14235dfecf96Smrg ) 14245dfecf96Smrg ) 14255dfecf96Smrg 14265dfecf96Smrg (and newline-property 14275dfecf96Smrg (add-entity 14285dfecf96Smrg (+ *from* length) 14295dfecf96Smrg 1 14305dfecf96Smrg (synprop-quark newline-property)) 14315dfecf96Smrg ) 14325dfecf96Smrg ) 14335dfecf96Smrg 14345dfecf96Smrg;------------------------------------------------------------------------ 14355dfecf96Smrg:update 14365dfecf96Smrg ;; Prepare for new matches. 14375dfecf96Smrg (setq 14385dfecf96Smrg result nil 14395dfecf96Smrg 14405dfecf96Smrg ;; Update offset to read text. 14415dfecf96Smrg ;; Add 1 for the skipped newline. 14425dfecf96Smrg *from* (+ *from* length 1) 14435dfecf96Smrg ) 14445dfecf96Smrg 14455dfecf96Smrg (go :read) 14465dfecf96Smrg ) 14475dfecf96Smrg 14485dfecf96Smrg#+debug (terpri) 14495dfecf96Smrg (values *to* indent-table) 14505dfecf96Smrg) 14515dfecf96Smrg 14525dfecf96Smrg(compile 'syntax-highlight) 1453