#cs(module xpath-parser mzscheme
(require (planet "ssax.ss" ("lizorkin" "ssax.plt" 1 0)))
(require "sxpathlib.ss")
(require "sxml-tools.ss")
(define (txp:param-value param-name txp-params)
  (cond
    ((assq param-name txp-params)
     => cadr)
    (else
     (display "Parameter unspecified: ")
     (display param-name)
     0       )))
(define (txp:error? obj)
  (or (eq? obj 'txp:parser-error)
      (eq? obj 'txp:semantic-error)))
(define (sxml:xpointer-parse-error . text)
  (apply cerr
         (append (list "XPath/XPointer parser error: ") text (list nl)))
  #f)
(define (sxml:xpointer-parse-warning . text)
  (apply cerr (append (list "XPointer parser warning: ") text (list nl))))
(define (txp:semantic-errs-detected? . res-list)
  (not (null?
        (filter
         (lambda (res) (eq? res 'txp:semantic-error))
         res-list))))
(define (txp:signal-semantic-error . text)
  (apply cerr
         (append (list "XPath/XPointer semantic error: ") text (list nl)))
  'txp:semantic-error)
(define sxml:whitespace '(#\space #\return #\newline #\tab))
(define sxml:delimiter (append sxml:whitespace
                              '(#\( #\) #\< #\> #\[ #\] #\: #\/ #\+ 
                                #\* #\, #\= #\| #\! #\" #\' #\@ #\$)))
(define (sxml:non-first? ch)
  (or (char-numeric? ch)
      (memv ch sxml:delimiter) 
      (memv ch '(#\. #\-))))
(define (sxml:skip-ws path)
  (if (or (null? path)
	  (not (memv (car path) sxml:whitespace)))
    path
    (sxml:skip-ws (cdr path))))
(define (sxml:assert-end-of-path path)
  (let ((path (sxml:skip-ws path)))
    (or 
     (null? path)
     (begin
       (sxml:xpointer-parse-error "unexpected - \"" (list->string path) "\"")
       #f))))
(define (sxml:parse-check str path . char-list)
  (let loop ((lst (string->list str)) 
             (p (sxml:skip-ws path)))
    (cond
      ((null? lst)
       (if
        (or (null? p) (null? char-list) (memv (car p) (car char-list)))
        p
        #f))
      ((null? p) #f)
      ((char=? (car lst) (car p))
       (loop (cdr lst) (cdr p)))
      (else #f))))
(define (sxml:parse-check-sequence str-seq path . char-list)
  (let ((char-list (if (null? char-list) #f (car char-list))))
    (let loop ((str-seq str-seq)
               (path path))
      (cond
        ((null? str-seq) path)          ((if char-list
             (sxml:parse-check (car str-seq) path char-list)
             (sxml:parse-check (car str-seq) path))
         => (lambda (new-path)
              (loop (cdr str-seq) new-path)))
        (else #f)))))  
(define (sxml:parse-assert str path)
  (let loop ((lst (string->list str)) 
	     (p (sxml:skip-ws path)))
    (cond
      ((null? lst) p)
      ((null? p) 
       (sxml:xpointer-parse-error 
        "unexpected end of XPointer path. "
        "Expected - \"" str "\", given - \"" (list->string path) "\""))
      ((char=? (car lst) (car p)) (loop (cdr lst) (cdr p)))
      (else
       (sxml:xpointer-parse-error
        "expected - \"" str "\", given - \"" (list->string path) "\"")))))
             
(define (sxml:parse-ncname path)
  (let((path (sxml:skip-ws path)))
    (cond
      ((null? path) 
       (sxml:xpointer-parse-error
        "unexpected end of XPointer path. Expected - NCName"))
      ((sxml:non-first? (car path))
       (sxml:xpointer-parse-error
        "expected - NCName instead of " (car path)))
      (else
       (let loop ((ncname (list (car path)))
                  (path (cdr path)))
         (cond
           ((null? path) (list (list->string (reverse ncname)) path))
           ((memv (car path) sxml:delimiter)           
            (list (list->string (reverse ncname)) path))
           (else (loop (cons (car path) ncname) (cdr path)))))))))
(define (sxml:parse-name path)
  (let ((path (sxml:skip-ws path)))
    (cond
      ((null? path)
       (sxml:xpointer-parse-error
	 "unexpected end of XPointer path. Expected - Name"))
      ((and (sxml:non-first? (car path))
	    (not (char=? (car path) #\:)))
       (sxml:xpointer-parse-error "expected - Name instead of " (car path)))
      (else (let loop ((ncname (list (car path)))
		       (path (cdr path)))
	      (cond
		((null? path) 
		 (list (list->string (reverse ncname)) path))
		((and (memv (car path) sxml:delimiter)
		      (not (char=? (car path) #\:)))
		 (list (list->string (reverse ncname)) path))
		(else (loop (cons (car path) ncname) (cdr path)))))))))
(define (sxml:parse-qname path)
  (and-let* ((r1 (sxml:parse-ncname path)))
	    (let ((first (car r1))
		  (path2 (cadr r1)))
	      (cond
		((null? path2) (list first path2))
		((not (char=? (car path2) #\:)) (list first path2))
		((null? (cdr path2))
		 (sxml:xpointer-parse-error "no local part of a qualified name"))
		((char=? (cadr path2) #\:) (list first path2))
		(else (and-let* ((r2 (sxml:parse-ncname (cdr path2))))
				(list (cons first (car r2)) (cadr r2)))
		      )))))
                   
(define (sxml:parse-natural path)
  (let ((path (sxml:skip-ws path)))
    (cond
      ((null? path)
       (sxml:xpointer-parse-error
        "unexpected end of XPointer path. Expected - number"))
      ((or (char<? (car path) #\1) (char>? (car path) #\9))
       (sxml:xpointer-parse-error "expected - number instead of " (car path)))
      (else (let loop ((res (- (char->integer (car path))
			  48))                   (path (cdr path)))
         (cond
           ((null? path) (list res path))
           ((char-numeric? (car path))
            (loop (+ (* res 10) (- (char->integer (car path)) 
				   48))                   (cdr path)))
           (else (list res path))))))))
(define (sxml:parse-literal path)
  (let ((ch (if (sxml:parse-check "\"" path) #\" #\')))
    (let loop ((res '())
	       (path (sxml:parse-assert (if (char=? ch #\") "\"" "'") 
				       path)))
      (cond
	((not path) #f)
	((null? path)
	 (sxml:parse-assert (if (char=? ch #\") "\"" "'") 
			   path)
	 #f)
	((char=? (car path) ch)
	 (list (list->string (reverse res))
	       (cdr path)))
	(else (loop (cons (car path) res) (cdr path)))))))
(define (sxml:parse-number path) 
  (define (digits path)
    (let loop ((n-lst '())
               (path path))
      (cond
        ((and (null? path) (null? n-lst))
         (sxml:xpointer-parse-error 
          "unexpected end of XPointer path. Expected - number"))
        ((null? path) (list n-lst path))
        ((and (or (char<? (car path) #\0) (char>? (car path) #\9))
              (null? n-lst))       
         (sxml:xpointer-parse-error "expected - number instead of " (car path)))
        ((or (char<? (car path) #\0) (char>? (car path) #\9))
         (list n-lst path))
        (else
         (loop (cons (- (char->integer (car path)) (char->integer #\0)) n-lst)
               (cdr path))))))
    
  (let ((path (sxml:skip-ws path)))
    (cond
      ((null? path)
       (sxml:xpointer-parse-error 
        "unexpected end of XPointer path. Expected - number"))
      ((char=? (car path) #\.)
       (and-let* ((lst (digits (cdr path))))
            (let rpt ((res 0)
                      (n-lst (car lst))
                      (path (cadr lst)))
              (if(null? n-lst)
                 (list (/ res 10) path)
                 (rpt (+ (/ res 10) (car n-lst))
                      (cdr n-lst) 
                      path)))))
      (else (and-let* ((lst (digits path)))
		      (let loop ((num1 0)
				 (n-lst (reverse (car lst)))
				 (path (cadr lst)))
			(if (null? n-lst)
			  (cond
			    ((null? path) (list num1 path))
			    ((not (char=? (car path) #\.)) (list num1 path))
			    (else
			      (and-let* ((lst2 (digits (cdr path))))
					(let rpt ((num2 0)
						  (n-lst (car lst2))
						  (path (cadr lst2)))
					  (if (null? n-lst)
					    (list (+ num1 (/ num2 10)) path)
					    (rpt (+ (/ num2 10) (car n-lst))
						 (cdr n-lst) 
						 path))))))
			  (loop (+ (* num1 10) (car n-lst))
				(cdr n-lst) 
				path))))))))
(define (txp:parameterize-parser txp-params)
  (letrec
      (
                                          
                     
                                                                                                                                                                                      (txp:parse-axis-specifier
        (let* ((axis-param-value (txp:param-value 'axis txp-params))
               (child-impl (txp:param-value 'child axis-param-value))
               (parser-pairs
                (cons
                 `(("@") ,(txp:param-value 'attribute axis-param-value))
                 (map
                  (lambda (single-pair)
                    (list
                     (list (symbol->string (car single-pair)) "::")
                     (cadr single-pair)))
                  axis-param-value))))
          (lambda (path ns-binding add-on)               (let loop ((pairs parser-pairs))
              (cond
                ((null? pairs)                   (list (child-impl add-on) path))
                ((sxml:parse-check-sequence (caar pairs) path)
                 => (lambda (path)
                      (list ((cadar pairs) add-on) path)))
                (else                   (loop (cdr pairs))))))))
       
                                                                                                                                                                                                                                (txp:parse-node-test
        (let* ((ntest-param-value (txp:param-value 'node-test txp-params))
               (star-impl (txp:param-value 'star ntest-param-value))
               (uri+star-impl (txp:param-value 'uri+star ntest-param-value))
               (qname-impl (txp:param-value 'qname ntest-param-value))
               (comment-impl (txp:param-value 'comment ntest-param-value))
               (text-impl (txp:param-value 'text ntest-param-value))
               (pi-impl
                (txp:param-value 'processing-instruction ntest-param-value))
               (node-impl (txp:param-value 'node ntest-param-value))
               (point-impl (txp:param-value 'point ntest-param-value))
               (range-impl (txp:param-value 'range ntest-param-value))
               (brackets
                (lambda (path)
                  (and-let* ((path (sxml:parse-assert "(" path)))
                            (sxml:parse-assert ")" path)))))
          (lambda (path ns-binding add-on)
            (cond
              ((sxml:parse-check-sequence '("comment" "(") path)
               => (lambda (path)
                    (and-let* ((path (sxml:parse-assert ")" path)))
                              (list (comment-impl add-on) path))))
              ((sxml:parse-check-sequence '("text" "(") path)
               => (lambda (path)
                    (and-let* ((path (sxml:parse-assert ")" path)))
                              (list (text-impl add-on) path))))
              ((sxml:parse-check-sequence '("node" "(") path)
               => (lambda (path)
                    (and-let* ((path (sxml:parse-assert ")" path)))
                          (list (node-impl add-on) path))))
              ((sxml:parse-check-sequence '("processing-instruction" "(") path)
               => (lambda (path)
                    (cond
                      ((sxml:parse-check ")" path)
                       => (lambda (path)
                            (list (pi-impl #f add-on) path)))
                      (else
                       (and-let*
                        ((lst (sxml:parse-literal path))
                         (name (car lst))
                         (path (sxml:parse-assert ")" (cadr lst))))
                        (list (pi-impl name add-on) path))))))
              ((sxml:parse-check-sequence '("point" "(") path)
               => (lambda (path)
                    (and-let* ((path (sxml:parse-assert ")" path)))
                              (list (point-impl add-on) path))))
              ((sxml:parse-check-sequence '("range" "(") path)
               => (lambda (path)
                    (and-let* ((path (sxml:parse-assert ")" path)))
                              (list (range-impl add-on) path))))
              ((sxml:parse-check "*" path)
               => (lambda (path)
                    (list (star-impl add-on) path)))
              (else                 (and-let*
                ((lst (sxml:parse-ncname path)))
                (let ((path (cadr lst)))
                  (if
                   (or (null? path) (not (char=? (car path) #\:)))                    (list (qname-impl #f (car lst) add-on) path)
                   (let* ((name (string->symbol (car lst)))
                          (path (sxml:parse-assert ":" path))
                          (pair (assq name ns-binding)))
                     (cond
                       ((not pair)
                        (sxml:xpointer-parse-error
                         "unknown namespace prefix - " name))
                       ((and (not (null? path)) (char=? (car path) #\*))
                        (list
                         (uri+star-impl (cdr pair) add-on)
                         (sxml:parse-assert "*" path)))
                       (else
                        (and-let*
                         ((lst (sxml:parse-ncname path)))
                         (list
                          (qname-impl (cdr pair) (car lst) add-on)                      
                          (cadr lst))))))))))))))
                
                                                                                                                       (txp:parse-step
        (let* ((step-param-value (txp:param-value 'step txp-params))
               (common-value (txp:param-value 'common step-param-value))
               (range-to-value (txp:param-value 'range-to step-param-value))
               (axis-param-value (txp:param-value 'axis txp-params))
               (self-value (txp:param-value 'self axis-param-value))
               (parent-value (txp:param-value 'parent axis-param-value))
               (ntest-param-value (txp:param-value 'node-test txp-params))
               (star-value (txp:param-value 'star ntest-param-value)))
          (lambda (path ns-binding add-on)
            (cond
              ((sxml:parse-check ".." path)
               (list
                (common-value (parent-value add-on)
                              (star-value add-on) '() add-on)
                (sxml:parse-assert ".." path)))
              ((sxml:parse-check "." path)
               (list
                (common-value (self-value add-on)
                              (star-value add-on) '() add-on)
                (sxml:parse-assert "." path)))
              ((sxml:parse-check "range-to" path)
               (and-let*
                ((path0
                  (sxml:parse-assert "(" (sxml:parse-assert "range-to" path)))
                 (lst (txp:parse-expr path0 ns-binding add-on))
                 (path (sxml:parse-assert ")" (cadr lst))))
                (let ((expr-res (car lst)))
                  (let loop ((path path)
                             (pred-lst '()))
                    (if
                     (sxml:parse-check "[" path)
                     (and-let*
                      ((lst (txp:parse-predicate path ns-binding add-on)))
                      (loop (cadr lst)
                            (cons (car lst) pred-lst)))
                                          (list
                      (if
                       (apply txp:semantic-errs-detected?
                              (cons expr-res pred-lst))
                       'txp:semantic-error
                       (range-to-value expr-res (reverse pred-lst) add-on))
                      path))))))
              (else                 (and-let*
                ((lst (txp:parse-axis-specifier path ns-binding add-on)))
                (let ((axis (car lst)))
                  (and-let*
                   ((lst (txp:parse-node-test (cadr lst) ns-binding add-on)))
                   (let ((test (car lst)))
                     (let loop ((preds '())
                                (path (cadr lst)))
                       (if
                        (sxml:parse-check "[" path)
                        (and-let*
                         ((lst (txp:parse-predicate path ns-binding add-on)))
                         (loop (cons (car lst) preds)
                               (cadr lst)))
                                                (list
                         (if (or (txp:semantic-errs-detected? axis test)
                                 (apply txp:semantic-errs-detected? preds))
                             'txp:semantic-error
                             (common-value axis test (reverse preds) add-on))
                         path))))))))))))
                                                                                    (txp:parse-relative-location-path
        (let* ((relative-lpath-value
                (txp:param-value 'relative-lpath txp-params))
               (step-param-value (txp:param-value 'step txp-params))
               (common-value (txp:param-value 'common step-param-value))
               (axis-param-value (txp:param-value 'axis txp-params))
               (descendant-or-self-value
                (txp:param-value 'descendant-or-self axis-param-value))
               (ntest-param-value (txp:param-value 'node-test txp-params))
               (node-value (txp:param-value 'node ntest-param-value)))
          (lambda (path ns-binding add-on)
            (let loop ((step-res-lst '())
                       (path path))
              (and-let*
               ((lst (txp:parse-step path ns-binding add-on)))
               (let ((step-res (car lst))
                     (path (cadr lst)))
                 (cond
                   ((sxml:parse-check "//" path)
                    (loop
                     (cons
                                            (common-value
                       (descendant-or-self-value add-on)
                       (node-value add-on) '() add-on)
                      (cons step-res step-res-lst))
                     (sxml:parse-assert "//" path)))
                   ((sxml:parse-check "/" path)
                    (loop (cons step-res step-res-lst)
                          (sxml:parse-assert "/" path)))                          
                   (else                      (list
                     (if
                      (apply txp:semantic-errs-detected? step-res-lst)
                      'txp:semantic-error
                      (relative-lpath-value
                       (reverse (cons step-res step-res-lst)) add-on))
                     path)))))))))
                                                                                                                (txp:parse-location-path
        (let* ((location-path-value
                (txp:param-value 'location-path txp-params))
               (bare-slash-value
                (txp:param-value 'bare-slash location-path-value))
               (slash-value
                (txp:param-value 'slash location-path-value))
               (double-slash-value
                (txp:param-value 'double-slash location-path-value))               
               (nothing?                  (lambda (path)
                  (let ((path (sxml:skip-ws path)))
                    (cond
                      ((null? path) #t)
                      ((memv (car path)
                             '(#\| #\+ #\- #\< #\> #\= #\) #\] #\,)) #t)
                      ((or (sxml:parse-check "mod" path sxml:delimiter)
                           (sxml:parse-check "div" path sxml:delimiter)
                           (sxml:parse-check "!=" path)
                           (sxml:parse-check "and" path sxml:delimiter)
                           (sxml:parse-check "or" path sxml:delimiter)) #t)
                      (else #f))))))
          (lambda (path ns-binding add-on)
            (cond
              ((sxml:parse-check "//" path)
               (and-let*
                ((lst (txp:parse-relative-location-path
                       (sxml:parse-assert "//" path) ns-binding add-on)))
                (let ((relative-res (car lst))
                      (path (cadr lst)))
                  (list
                   (if (txp:semantic-errs-detected? relative-res)
                       'txp:semantic-error
                       (double-slash-value relative-res add-on))
                   path))))
              ((sxml:parse-check "/" path)
               => (lambda (path)
                    (if (nothing? path)
                        (list (bare-slash-value add-on) path)
                        (and-let*
                         ((lst (txp:parse-relative-location-path
                                path ns-binding add-on)))
                         (let ((relative-res (car lst))
                               (path (cadr lst)))
                           (list
                            (if (txp:semantic-errs-detected? relative-res)
                                'txp:semantic-error
                                (slash-value relative-res add-on))
                            path))))))
              (else                 (txp:parse-relative-location-path path ns-binding add-on))))))
                                                        (txp:parse-predicate
        (let ((predicate-value (txp:param-value 'predicate txp-params)))
          (lambda (path ns-binding add-on)
            (and-let*
             ((path0 (sxml:parse-assert "[" path))
              (lst (txp:parse-expr path0 ns-binding add-on))
              (path (sxml:parse-assert "]" (cadr lst))))
             (list
              (if (txp:semantic-errs-detected? (car lst))
                  'txp:semantic-error
                  (predicate-value (car lst) add-on))
              path)))))
                                                 (txp:parse-variable-reference  
        (let ((var-ref-value (txp:param-value 'variable-ref txp-params)))
          (lambda (path ns-binding add-on)
            (and-let*
             ((path (sxml:parse-assert "$" path))
              (lst (sxml:parse-qname path)))
             (let ((name              
                    (if (pair? (car lst))                          (string-append (caar lst) ":" (cdar lst))
                        (car lst))))
               (list (var-ref-value name add-on) (cadr lst)))))))
                                                                                           (txp:parse-function-call
        (let ((fun-call-value (txp:param-value 'function-call txp-params))
              (parse-arguments
                              (lambda (path ns-binding add-on)
                 (and-let*
                  ((path (sxml:parse-assert "(" path)))
                  (cond	
                    ((sxml:parse-check ")" path)
                      => (lambda (path) (list '() path)))
                    (else
                     (let single-arg ((arg-res-lst '())
                                      (path path))
                       (and-let*
                        ((lst (txp:parse-expr path ns-binding add-on)))
                        (let ((arg-res (car lst))
                              (path (cadr lst)))
                          (cond
                            ((sxml:parse-check ")" path)
                             => (lambda (path)
                                  (list (reverse (cons arg-res arg-res-lst))
                                        path)))
                            (else
                             (and-let*
                              ((path (sxml:parse-assert "," path)))
                              (single-arg
                               (cons arg-res arg-res-lst) path)))))))))))))
          (lambda (path ns-binding add-on)
            (and-let*
             ((lst (sxml:parse-qname path)))
             (let ((fun-name (car lst)))                 (and-let*
                ((lst (parse-arguments (cadr lst) ns-binding add-on)))
                (let ((arg-res-lst (car lst))
                      (path (cadr lst)))
                  (list
                   (if (apply txp:semantic-errs-detected? arg-res-lst)
                       'txp:semantic-error
                       (fun-call-value
                        (if (pair? fun-name)                              (string-append (car fun-name) ":" (cdr fun-name))
                            fun-name)
                        arg-res-lst add-on))
                   path))))))))
                     
                                                                                                                              (txp:parse-primary-expr
        (let* ((primary-expr-value (txp:param-value 'primary-expr txp-params))
               (literal-value (txp:param-value 'literal primary-expr-value))
               (number-value (txp:param-value 'number primary-expr-value)))
          (lambda (path ns-binding add-on)
            (cond
              ((sxml:parse-check "$" path)                 (txp:parse-variable-reference path ns-binding add-on))
              ((sxml:parse-check "(" path)                 (and-let*
                ((lst (txp:parse-expr
                       (sxml:parse-assert "(" path) ns-binding add-on))
                 (path (sxml:parse-assert ")" (cadr lst))))
                (let ((expr-res (car lst)))
                  (list expr-res path))))
              ((or (sxml:parse-check "\"" path)
                   (sxml:parse-check "'" path))                 (and-let*
                ((lst (sxml:parse-literal path)))
                (list
                 (literal-value (car lst) add-on)
                 (cadr lst))))
              ((let ((p (sxml:skip-ws path)))                   (cond ((null? p) #f)
                       ((char=? (car p) #\.) #t)
                       ((and (char>=? (car p) #\0) (char<=? (car p) #\9)) #t)
                       (else #f)))
               (and-let*
                ((lst (sxml:parse-number path)))                               
                (list
                 (number-value (car lst) add-on)	   
                 (cadr lst))))
              (else                  (txp:parse-function-call path ns-binding add-on))))))
                                                               (txp:parse-filter-expr
        (let ((filter-expr-value (txp:param-value 'filter-expr txp-params)))
          (lambda (path ns-binding add-on)
            (and-let*
             ((lst (txp:parse-primary-expr path ns-binding add-on)))
             (let ((prim-res (car lst)))
               (let loop ((pred-res-lst '())
                          (path (cadr lst)))
                 (cond
                   ((sxml:parse-check "[" path)
                    (and-let*
                     ((lst (txp:parse-predicate path ns-binding add-on)))
                     (loop (cons (car lst) pred-res-lst)
                           (cadr lst))))
                                      ((null? pred-res-lst) (list prim-res path))
                   (else              
                    (list
                     (if
                      (apply txp:semantic-errs-detected?
                             (cons prim-res pred-res-lst))
                      'txp:semantic-error
                      (filter-expr-value prim-res (reverse pred-res-lst) add-on))
                     path)))))))))
                                                                                                         (txp:parse-path-expr
         (let ((filter-expr?
                (lambda (path)
                  (let ((path (sxml:skip-ws path)))
                    (cond
                      ((null? path) #f)
                      ((member 
                        (car path) 
                        '(#\$ #\( #\" #\' #\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
                       #t)
                      ((char=? (car path) #\.)
                       (cond
                         ((null? (cdr path)) #f)
                         ((member
                           (cadr path)
                           '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))
                          #t)
                         (else #f)))
                      ((member
                        (car path)
                        '(#\) #\< #\> #\[ #\] #\/ #\+ #\* #\, #\= #\| #\! #\@ #\-))
                       #f)
                      (else
                       (let ((lst (sxml:parse-ncname path)))
                         (cond
                           ((not lst) #f)
                           ((sxml:parse-check "::" (cadr lst)) #f)
                           (else
                            (and-let*
                             ((lst (sxml:parse-name path)))
                             (let ((name (car lst))
                                   (new-path (sxml:skip-ws (cadr lst))))
                               (cond
                                 ((string=? name "range-to") #f)
                                 ((string=? name "comment") #f)
                                 ((string=? name "text") #f)
                                 ((string=? name "processing-instruction") #f)
                                 ((string=? name "node") #f)
                                 ((string=? name "point") #f)
                                 ((string=? name "range") #f)
                                 ((null? new-path) #f)
                                 ((char=? (car new-path) #\() #t)
                                 (else #f)))))))))))))
           (let* ((path-expr-value (txp:param-value 'path-expr txp-params))
                  (slash-value (txp:param-value 'slash path-expr-value))
                  (double-slash-value
                   (txp:param-value 'double-slash path-expr-value)))
             (lambda (path ns-binding add-on)
               (if
                (not (filter-expr? path))
                (txp:parse-location-path path ns-binding add-on)
                (and-let*
                 ((lst (txp:parse-filter-expr path ns-binding add-on)))
                 (let ((filter-ex-res (car lst))
                       (path (cadr lst)))
                   (cond
                     ((sxml:parse-check "//" path)
                      (and-let*
                       ((lst2
                         (txp:parse-relative-location-path
                          (sxml:parse-assert "//" path) ns-binding add-on)))
                       (let ((rel-lpath-res (car lst2))
                             (path (cadr lst2)))
                         (list
                          (if
                           (txp:semantic-errs-detected?
                            filter-ex-res rel-lpath-res)
                           'txp:semantic-error
                           (double-slash-value
                            filter-ex-res rel-lpath-res add-on))
                          path))))
                     ((sxml:parse-check "/" path)
                      (and-let*
                       ((lst2
                         (txp:parse-relative-location-path
                          (sxml:parse-assert "/" path) ns-binding add-on)))
                       (let ((rel-lpath-res (car lst2))
                             (path (cadr lst2)))
                         (list
                          (if
                           (txp:semantic-errs-detected?
                            filter-ex-res rel-lpath-res)
                           'txp:semantic-error
                           (slash-value filter-ex-res rel-lpath-res add-on))
                          path))))
                     (else                        lst)))))))))
                                                        (txp:parse-union-expr
        (let ((union-expr-value (txp:param-value 'union-expr txp-params)))              
          (lambda (path ns-binding add-on)
            (let loop ((p-e-res-lst '())
                       (path path))
              (and-let*
               ((lst (txp:parse-path-expr path ns-binding add-on)))
               (let ((p-e-res (car lst))
                     (path (cadr lst)))
                 (let ((new-path (sxml:parse-check "|" path)))
                   (cond
                     (new-path                        (loop (cons p-e-res p-e-res-lst) new-path))
                                          ((null? p-e-res-lst)                        (list p-e-res path))
                     (else                        (list
                       (if
                        (apply txp:semantic-errs-detected?
                               (cons p-e-res p-e-res-lst))
                        'txp:semantic-error
                        (union-expr-value
                         (reverse (cons p-e-res p-e-res-lst)) add-on))
                       path))))))))))
 
                                                               (txp:parse-unary-expr
        (let ((unary-expr-value (txp:param-value 'unary-expr txp-params)))              
          (lambda (path ns-binding add-on)
            (if (not (sxml:parse-check "-" path))
                (txp:parse-union-expr path ns-binding add-on)
                (let loop ((num-minuses 0) (path path))
                  (let ((new-path (sxml:parse-check "-" path)))
                    (if new-path                           (loop (+ num-minuses 1) new-path)               
                        (and-let*
                         ((lst (txp:parse-union-expr path ns-binding add-on)))
                         (let ((union-expr-res (car lst))
                               (path (cadr lst)))
                           (list
                            (if
                             (txp:semantic-errs-detected? union-expr-res)
                             'txp:semantic-error
                             (unary-expr-value
                              union-expr-res num-minuses add-on))
                            path))))))))))
                     			
                                                                                           (txp:parse-multiplicative-expr
        (let* ((mul-expr-value (txp:param-value 'mul-expr txp-params))
               (operations-value (txp:param-value 'operations txp-params))
               (multiply-value (txp:param-value '* operations-value))
               (div-value (txp:param-value 'div operations-value))
               (mod-value (txp:param-value 'mod operations-value)))
          (lambda (path ns-binding add-on)
            (let loop ((unary-expr-res-lst '())
                       (op-lst '())
                       (path path))
              (and-let*
               ((lst (txp:parse-unary-expr path ns-binding add-on)))
               (let ((unary-expr-res (car lst))
                     (path (cadr lst)))
                 (cond
                   ((sxml:parse-check "*" path)
                    (loop (cons unary-expr-res unary-expr-res-lst)
                          (cons (multiply-value add-on) op-lst)
                          (sxml:parse-assert "*" path)))
                   ((sxml:parse-check "div" path sxml:delimiter)
                    (loop (cons unary-expr-res unary-expr-res-lst)
                          (cons (div-value add-on) op-lst)
                          (sxml:parse-assert "div" path)))
                   ((sxml:parse-check "mod" path sxml:delimiter)
                    (loop (cons unary-expr-res unary-expr-res-lst)
                          (cons (mod-value add-on) op-lst)
                          (sxml:parse-assert "mod" path)))
                                      ((null? unary-expr-res-lst)                      lst)
                   (else                       (list
                     (if
                      (apply txp:semantic-errs-detected?
                             (cons unary-expr-res unary-expr-res-lst))
                      'txp:semantic-error
                      (mul-expr-value
                       (reverse (cons unary-expr-res unary-expr-res-lst))
                       (reverse op-lst) add-on))
                     path)))))))))
              
                                                               (txp:parse-additive-expr
        (let* ((add-expr-value (txp:param-value 'add-expr txp-params))
               (operations-value (txp:param-value 'operations txp-params))
               (plus-value (txp:param-value '+ operations-value))
               (minus-value (txp:param-value '- operations-value)))
          (lambda (path ns-binding add-on)
            (let loop ((mul-expr-res-lst '())
                       (op-lst '())
                       (path path))
              (and-let*
               ((lst (txp:parse-multiplicative-expr path ns-binding add-on)))
               (let ((mul-expr-res (car lst))
                     (path (cadr lst)))
                 (cond
                   ((sxml:parse-check "+" path)
                    (loop (cons mul-expr-res mul-expr-res-lst)
                          (cons (plus-value add-on) op-lst)
                          (sxml:parse-assert "+" path)))
                   ((sxml:parse-check "-" path)
                    (loop (cons mul-expr-res mul-expr-res-lst)
                          (cons (minus-value add-on) op-lst)
                          (sxml:parse-assert "-" path)))
                                      ((null? mul-expr-res-lst)                      lst)
                   (else                       (list
                     (if
                      (apply txp:semantic-errs-detected?
                             (cons mul-expr-res mul-expr-res-lst))
                      'txp:semantic-error
                      (add-expr-value
                       (reverse (cons mul-expr-res mul-expr-res-lst))
                       (reverse op-lst) add-on))
                     path)))))))))
       
                                                                                    (txp:parse-relational-expr
        (let* ((rel-expr-value (txp:param-value 'relational-expr txp-params))
               (operations-value (txp:param-value 'operations txp-params))
               (ls-value (txp:param-value '< operations-value))
               (gt-value (txp:param-value '> operations-value))
               (le-value (txp:param-value '<= operations-value))
               (ge-value (txp:param-value '>= operations-value)))                              
          (lambda (path ns-binding add-on)
            (let loop ((add-res-lst '())
                       (cmp-op-lst '())
                       (path path))
              (and-let*
               ((lst (txp:parse-additive-expr path ns-binding add-on)))
               (let ((add-res (car lst))
                     (path (cadr lst)))
                 (cond
                   ((sxml:parse-check "<=" path)
                    (loop (cons add-res add-res-lst)
                          (cons (le-value add-on) cmp-op-lst)
                          (sxml:parse-assert "<=" path)))
                   ((sxml:parse-check ">=" path)
                    (loop (cons add-res add-res-lst)
                          (cons (ge-value add-on) cmp-op-lst)
                          (sxml:parse-assert ">=" path)))
                   ((sxml:parse-check "<" path)
                    (loop (cons add-res add-res-lst)
                          (cons (ls-value add-on) cmp-op-lst)
                          (sxml:parse-assert "<" path)))
                   ((sxml:parse-check ">" path)
                    (loop (cons add-res add-res-lst)
                          (cons (gt-value add-on) cmp-op-lst)
                          (sxml:parse-assert ">" path)))
                                      ((null? add-res-lst)                     lst)
                   (else                       (list
                     (if
                      (apply txp:semantic-errs-detected?
                             (cons add-res add-res-lst))
                      'txp:semantic-error
                      (rel-expr-value
                       (reverse (cons add-res add-res-lst))
                       (reverse cmp-op-lst) add-on))
                     path)))))))))
       
                                                                      (txp:parse-equality-expr
        (let* ((equality-expr-value
                (txp:param-value 'equality-expr txp-params))
               (operations-value
                (txp:param-value 'operations txp-params))
               (equal-value (txp:param-value '= operations-value))
               (not-equal-value (txp:param-value '!= operations-value)))
          (lambda (path ns-binding add-on)
            (let loop ((rel-res-lst '())
                       (cmp-op-lst '())
                       (path path))
              (and-let*
               ((lst (txp:parse-relational-expr path ns-binding add-on)))
               (let ((rel-res (car lst))
                     (path (cadr lst)))
                 (cond
                   ((sxml:parse-check "=" path)
                    (loop (cons rel-res rel-res-lst)
                          (cons (equal-value add-on) cmp-op-lst)
                          (sxml:parse-assert "=" path)))
		  ((sxml:parse-check "!=" path)
		   (loop (cons rel-res rel-res-lst)
                         (cons (not-equal-value add-on) cmp-op-lst)
			 (sxml:parse-assert "!=" path)))
		                    ((null? rel-res-lst)                    lst)
                  (else                     (list
                    (if
                     (apply txp:semantic-errs-detected?
                            (cons rel-res rel-res-lst))
                      'txp:semantic-error
                      (equality-expr-value
                       (reverse (cons rel-res rel-res-lst))
                       (reverse cmp-op-lst) add-on))
                     path)))))))))
                   
                                                                      (txp:parse-and-expr
        (let ((and-expr-value (txp:param-value 'and-expr txp-params)))
          (lambda (path ns-binding add-on)
            (let loop ((equality-res-lst '())
                       (path path))
              (and-let*
               ((lst (txp:parse-equality-expr path ns-binding add-on)))
               (let ((equality-res (car lst))
                     (path (cadr lst)))
                 (let ((new-path (sxml:parse-check "and" path sxml:delimiter)))
                   (cond
                     (new-path
                      (loop (cons equality-res equality-res-lst) new-path))
                                          ((null? equality-res-lst)                        lst)
                     (else                        (list
                       (if
                        (apply txp:semantic-errs-detected?
                               (cons equality-res equality-res-lst))
                        'txp:semantic-error
                        (and-expr-value
                         (reverse (cons equality-res equality-res-lst))
                         add-on))
                     path))))))))))
                  
                                                                             (txp:parse-expr
        (let ((or-expr-value (txp:param-value 'or-expr txp-params)))
          (lambda (path ns-binding add-on)
            (let loop ((and-res-lst '())
                       (path path))
              (and-let*
               ((lst (txp:parse-and-expr path ns-binding add-on)))
               (let ((and-res (car lst))
                     (path (cadr lst)))
                 (let ((new-path (sxml:parse-check "or" path sxml:delimiter)))
                   (cond
                     (new-path
                      (loop (cons and-res and-res-lst) new-path))
                                          ((null? and-res-lst)                        lst)
                     (else                        (list
                       (if
                        (apply txp:semantic-errs-detected?
                               (cons and-res and-res-lst))
                        'txp:semantic-error
                        (or-expr-value
                         (reverse (cons and-res and-res-lst)) add-on))
                      path))))))))))
       
                     
                                                                                                                       (txp:parse-full-xptr
        (let ((full-xptr-value (txp:param-value 'full-xptr txp-params)))
          (lambda (path ns-binding add-on)
            (let loop ((expr-res-lst '())
                       (ns-binding ns-binding)
                       (path path))
              (if
               (null? (sxml:skip-ws path))                 (cond
                 ((= (length expr-res-lst) 1)                    (car expr-res-lst))
                 ((apply txp:semantic-errs-detected? expr-res-lst)
                  'txp:semantic-error)
                 (else
                  (full-xptr-value (reverse expr-res-lst) add-on)))
               (and-let*
                ((lst (sxml:parse-name path))
                 (name (car lst))
                 (path (cadr lst)))
                (cond
                  ((string=? name "xpointer")                     (and-let*
                    ((path (sxml:parse-assert "(" path))
                     (lst2 (txp:parse-expr path ns-binding add-on)))
                    (let ((expr-res (car lst2))
                          (path (cadr lst2)))
                      (and-let*
                       ((path (sxml:parse-assert ")" path)))
                       (loop (cons expr-res expr-res-lst) ns-binding path)))))
                  ((string=? name "xmlns")                     (and-let*
                    ((path0 (sxml:parse-assert "(" path))
                     (lst2 (sxml:parse-ncname path0))
                     (prefix (string->symbol (car lst2)))
                     (path (sxml:parse-assert "=" (cadr lst2))))
                    (let rpt2 ((path (sxml:skip-ws path)) (uri '()))
                      (cond
                        ((null? path)
                         (sxml:parse-assert ")" path)
                         #f)
                        ((and (char=? (car path) #\)) (null? uri))
                         (sxml:xpointer-parse-error
                          "namespace URI cannot be empty"))
                        ((char=? (car path) #\))
                         (loop expr-res-lst
                               (cons
                                (cons prefix (list->string (reverse uri)))
                                ns-binding)
                               (cdr path)))
                        (else
                         (rpt2 (cdr path) (cons (car path) uri)))))))
                  (else                     (and-let*
                    ((path (sxml:parse-assert "(" path)))
                    (let rpt3 ((n 1) (path path))
                      (cond
                        ((= n 0)
                         (sxml:xpointer-parse-warning
                          "unknown xpointer schema - " name ". Ignoring")
                         (loop expr-res-lst ns-binding path))
                        ((null? path)
                         (sxml:parse-assert ")" path)
                         #f)
                        ((char=? (car path) #\() (rpt3 (+ n 1) (cdr path)))
                        ((char=? (car path) #\)) (rpt3 (- n 1) (cdr path)))
                        (else (rpt3 n (cdr path))))))))))))))
       
                                                                                    (txp:parse-child-seq
        (let ((helper
               (lambda (path)
                 (let loop ((num-lst '())
                            (path path))
                   (let ((path2 (sxml:parse-check "/" path)))
                     (cond
                       (path2                          (and-let* ((lst (sxml:parse-natural path2)))
                                  (loop (cons (car lst) num-lst)
                                        (cadr lst))))
                       ((null? (sxml:skip-ws path))                          (reverse num-lst))
                       (else                            (sxml:parse-assert "/" path))))))))                         
          (let* ((child-seq-value (txp:param-value 'child-seq txp-params))
                 (with-name-value (txp:param-value 'with-name child-seq-value))
                  (without-name-value
                   (txp:param-value 'without-name child-seq-value)))
            (lambda (path ns-binding add-on)
              (let ((path2 (sxml:parse-check "/" path)))
                (if
                 path2                   (and-let*
                  ((number-lst (helper path)))                  
                  (without-name-value number-lst add-on))
                 (and-let*
                  ((lst (sxml:parse-name path))
                   (name (car lst))
                   (number-lst (helper (cadr lst))))
                  (with-name-value name number-lst add-on))))))))
                   
                                                                             
                     (txp:parse-xpath
        (lambda (path-string ns-binding add-on)
          (let ((res (txp:parse-location-path
                      (string->list path-string) ns-binding add-on)))
            (if (and res                       (sxml:assert-end-of-path (cadr res)))
                (car res)
                'txp:parser-error))))
       
                     (txp:parse-xpointer
        (lambda (path-string ns-binding add-on)
          (let ((path (string->list path-string)))
            (if (sxml:parse-check "/" path)                   (txp:parse-child-seq path ns-binding add-on)
                (and-let*
                 ((lst (sxml:parse-name path))
                  (new-path (cadr lst)))
                 (if (sxml:parse-check "(" new-path)                       (txp:parse-full-xptr path ns-binding add-on)
                     (txp:parse-child-seq path ns-binding add-on)))))))
       
                     (txp:parse-xpath-expression
        (lambda (path-string ns-binding add-on)
          (let ((res (txp:parse-expr
                      (string->list path-string) ns-binding add-on)))
            (if (and res                       (sxml:assert-end-of-path (cadr res)))
                (car res)
                'txp:parser-error))))
       
       )
        
    `((xpath ,txp:parse-xpath)
      (xpointer ,txp:parse-xpointer)
      (expr ,txp:parse-xpath-expression))
    ))
(provide (all-defined)))