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