#cs(module ddo-txpath mzscheme
(require (planet "ssax.ss" ("lizorkin" "ssax.plt" 1 0)))
(require "sxpathlib.ss")
(require "sxml-tools.ss")
(require "sxpath-ext.ss")
(require "xpath-parser.ss")
(require "txpath.ss")
(require "xpath-ast.ss")
(require "xpathlink.ss")
(require "ddo-axes.ss")
(define (ddo:or . args)
(if (null? args) #f (or (car args) (apply ddo:or (cdr args)))))
(define ddo:type-nodeset 'ddo:type-nodeset)
(define ddo:type-number 'ddo:type-number)
(define ddo:type-string 'ddo:type-string)
(define ddo:type-boolean 'ddo:type-boolean)
(define ddo:type-any 'ddo:type-any)
(define (ddo:nset-contained? nodeset1 nodeset2)
(cond
((null? nodeset1) #t)
((memq (car nodeset1) nodeset2)
(ddo:nset-contained? (cdr nodeset1) nodeset2))
(else #f)))
(define (ddo:nset-equal? nodeset1 nodeset2)
(and (ddo:nset-contained? nodeset1 nodeset2)
(ddo:nset-contained? nodeset2 nodeset1)))
(define (ddo:pos-result-forward? pos-result)
(let loop ((pos-res pos-result))
(cond
((null? pos-res) #t)
((or (null? (car pos-res)) (null? (cdar pos-res)))
(loop (cdr pos-res)))
(else
(< (cdaar pos-res) (cdadar pos-res))))))
(define (ddo:pos-result->nodeset pos-result)
(letrec ( (combine-2-pos-nodesets
(lambda (chain1 chain2)
(cond
((null? chain1) chain2)
((null? chain2) chain1)
((eq? (caar chain1) (caar chain2)) (cons (car chain1)
(combine-2-pos-nodesets (cdr chain1) (cdr chain2))))
((< (cdar chain1) (cdar chain2))
(cons (car chain1)
(combine-2-pos-nodesets (cdr chain1) chain2)))
(else
(cons (car chain2)
(combine-2-pos-nodesets chain1 (cdr chain2))))))))
(if
(null? pos-result) pos-result
(let ((pos-result (if (ddo:pos-result-forward? pos-result)
pos-result
(map reverse pos-result))))
(let loop ((res (car pos-result))
(to-scan (cdr pos-result)))
(if (null? to-scan)
res
(loop (combine-2-pos-nodesets res (car to-scan))
(cdr to-scan))))))))
(define (ddo:location-step-pos pos-axis-impl pred-impl-lst)
(lambda (nodeset position+size var-binding)
(map
car
(ddo:pos-result->nodeset
(map
(lambda (pos-nodeset)
(let iter-preds ((nset pos-nodeset)
(preds pred-impl-lst))
(if
(null? preds)
nset
(let ((size (length nset))) (let iter-pairs ((nset nset)
(res '())
(pos 1))
(if
(null? nset) (iter-preds (reverse res) (cdr preds))
(let ((val ((car preds) (list (caar nset)) (cons pos size) var-binding)))
(iter-pairs (cdr nset)
(if (if (number? val)
(= val pos)
(sxml:boolean val))
(cons (car nset) res)
res)
(+ pos 1)))))))))
(pos-axis-impl nodeset))))))
(define (ddo:location-step-non-intersect axis-impl pred-impl-lst)
(lambda (nodeset position+size var-binding)
(map-union
(lambda (node)
(let iter-preds ((nset (axis-impl node))
(preds pred-impl-lst))
(if
(null? preds)
nset
(let ((size (length nset))) (let iter-nodes ((nset nset)
(res '())
(pos 1))
(if
(null? nset) (iter-preds (reverse res) (cdr preds))
(let ((val ((car preds) (list (car nset)) (cons pos size) var-binding)))
(iter-nodes (cdr nset)
(if (if (number? val)
(= val pos)
(sxml:boolean val))
(cons (car nset) res)
res)
(+ pos 1)))))))))
nodeset)))
(define (ddo:location-step-non-pos axis-impl pred-impl-lst)
(lambda (nodeset position+size var-binding)
(let iter-preds ((nset (axis-impl nodeset))
(preds pred-impl-lst))
(if
(null? preds)
nset
(let ((curr-pred (car preds)))
(iter-preds
(filter
(lambda (node)
(sxml:boolean
(curr-pred (list node)
(cons 1 1) var-binding)))
nset)
(cdr preds)))))))
(define (ddo:filter-expr-general expr-impl pred-impl-lst)
(lambda (nodeset position+size var-binding)
(let ((prim-res (expr-impl nodeset position+size var-binding)))
(cond
((not (nodeset? prim-res))
(sxml:xpointer-runtime-error
"expected - nodeset instead of " prim-res)
'())
(else
(let iter-preds ((nset prim-res)
(preds pred-impl-lst))
(if
(null? preds)
nset
(let ((size (length nset))) (let iter-nodes ((nset nset)
(res '())
(pos 1))
(if
(null? nset) (iter-preds (reverse res) (cdr preds))
(let ((val ((car preds) (list (car nset)) (cons pos size) var-binding)))
(iter-nodes (cdr nset)
(if (if (number? val)
(= val pos)
(sxml:boolean val))
(cons (car nset) res)
res)
(+ pos 1)))))))))))))
(define (ddo:filter-expr-non-pos expr-impl pred-impl-lst)
(lambda (nodeset position+size var-binding)
(let ((prim-res (expr-impl nodeset position+size var-binding)))
(cond
((not (nodeset? prim-res))
(sxml:xpointer-runtime-error
"expected - nodeset instead of " prim-res)
'())
(else
(let iter-preds ((nset prim-res)
(preds pred-impl-lst))
(if
(null? preds)
nset
(let ((curr-pred (car preds)))
(iter-preds
(filter
(lambda (node)
(sxml:boolean
(curr-pred (list node)
(cons 1 1) var-binding)))
nset)
(cdr preds))))))))))
(define (ddo:filter-expr-special-predicate expr-impl special-pred-impl)
(lambda (nodeset position+size var-binding)
(let ((prim-res (expr-impl nodeset position+size var-binding)))
(if
(not (nodeset? prim-res))
(begin
(sxml:xpointer-runtime-error
"expected - nodeset instead of " prim-res)
'())
(special-pred-impl prim-res)))))
(define (ddo:unite-2-contextsets cntset1 cntset2)
(cond
((null? cntset1) cntset2)
((null? cntset2) cntset1)
((eq? (sxml:context->node (car cntset1))
(sxml:context->node (car cntset2)))
(cons
(car cntset1)
(ddo:unite-2-contextsets (cdr cntset1) (cdr cntset2))))
(else
(let ((rev1 (reverse (sxml:context->content (car cntset1))))
(rev2 (reverse (sxml:context->content (car cntset2)))))
(if
(not (eq? (car rev1) (car rev2))) (cons (car cntset1)
(cons
(car cntset2)
(ddo:unite-2-contextsets (cdr cntset1) (cdr cntset2))))
(let iter-ancs ((parent (car rev1))
(rev1 (cdr rev1))
(rev2 (cdr rev2)))
(cond
((null? rev1) (cons
(car cntset1)
(ddo:unite-2-contextsets (cdr cntset1) cntset2)))
((null? rev2) (cons
(car cntset2)
(ddo:unite-2-contextsets cntset1 (cdr cntset2))))
((eq? (car rev1) (car rev2)) (iter-ancs (car rev1) (cdr rev1) (cdr rev2)))
((memq (car rev1) (cdr parent))
=> (lambda (foll-siblings-or-self)
(if
(memq (car rev2) foll-siblings-or-self)
(cons
(car cntset1)
(ddo:unite-2-contextsets (cdr cntset1) cntset2))
(cons
(car cntset2)
(ddo:unite-2-contextsets cntset1 (cdr cntset2))))))
(else (cons
(car cntset1)
(ddo:unite-2-contextsets (cdr cntset1) cntset2))))))))))
(define (ddo:unite-multiple-context-sets . context-sets)
(if (null? context-sets) '()
(let loop ((res (car context-sets))
(more (cdr context-sets)))
(if (null? more)
res
(loop (ddo:unite-2-contextsets res (car more))
(cdr more))))))
(define (ddo:list-tail lst k)
(if (or (null? lst) (<= k 0))
lst
(ddo:list-tail (cdr lst) (- k 1))))
(define (ddo:list-head lst k)
(if (or (null? lst) (<= k 0))
'()
(cons (car lst) (ddo:list-head (cdr lst) (- k 1)))))
(define (ddo:list-ref lst k)
(cond ((null? lst) lst)
((zero? k) (car lst))
(else (ddo:list-ref (cdr lst) (- k 1)))))
(define ddo:check-ast-position?
(let ((ddo:ast-for-position-fun-call (txp:expr->ast "position()")))
(lambda (op)
(equal? op ddo:ast-for-position-fun-call))))
(define (ddo:check4ast-number op)
(if
(eq? (car op) 'number)
(let ((number (cadr op)))
(if (and (number? number) (exact? number))
number #f))
#f))
(define (ddo:check-special-predicate op)
(if
(not (eq? (car op) 'predicate))
#f (let ((expr (cadr op)))
(cond
((ddo:check4ast-number expr)
=> (lambda (num)
(lambda (nodeset) (ddo:list-ref nodeset (- num 1)))))
((and (memq (car expr) '(= > < >= <=))
(= (length expr) 3))
(let-values*
(((cmp-op num)
(cond
((and (ddo:check-ast-position? (cadr expr))
(ddo:check4ast-number (caddr expr)))
=> (lambda (num) (values (car expr) num)))
((and (ddo:check-ast-position? (caddr expr))
(ddo:check4ast-number (cadr expr)))
=> (lambda (num)
(values
(cond ((assq (car expr) '((< . >) (> . <) (>= . <=) (<= . >=)))
=> cdr)
(else (car expr)))
num)))
(else
(values #f #f)))))
(if
(not num)
#f
(case cmp-op
((=)
(lambda (nodeset) (ddo:list-ref nodeset (- num 1))))
((>)
(lambda (nodeset) (ddo:list-tail nodeset num)))
((>=)
(lambda (nodeset) (ddo:list-tail nodeset (- num 1))))
((<)
(lambda (nodeset) (ddo:list-head nodeset (- num 1))))
((<=)
(lambda (nodeset) (ddo:list-head nodeset num)))
(else #f)))))
(else #f)))))
(define (ddo:generate-pred-id)
(string->symbol
(string-append "*predicate-" (symbol->string (gensym)) "*")))
(define (ddo:get-pred-value pred-id)
(lambda (nodeset position+size var-binding)
(cond
((not (and (nodeset? nodeset)
(null? (cdr nodeset))))
(sxml:xpointer-runtime-error
"internal DDO SXPath error - "
"a predicate is supplied with a non-singleton nodeset: " pred-id)
#f)
((assq pred-id var-binding)
=> (lambda (binding)
(cond
((assq (sxml:context->node (car nodeset))
(cdr binding))
=> (lambda (pair) (force (cdr pair)))
)
(else
(sxml:xpointer-runtime-error
"internal DDO SXPath error - predicate value not found: "
pred-id)
#f))))
(else
(sxml:xpointer-runtime-error
"internal DDO SXPath error - predicate value not found: " pred-id)
#f))))
(define (ddo:get-pred-value-pos pred-id)
(lambda (nodeset position+size var-binding)
(cond
((not (and (nodeset? nodeset)
(null? (cdr nodeset))))
(sxml:xpointer-runtime-error
"internal DDO SXPath error - "
"a predicate is supplied with a non-singleton nodeset: " pred-id)
#f)
((assq pred-id var-binding)
=> (lambda (binding)
(cond
((assq (sxml:context->node (car nodeset))
(cdr binding))
=> (lambda (size-alist)
(cond
((assq (cdr position+size) (cdr size-alist))
=> (lambda (position-alist)
(cond
((assq (car position+size) (cdr position-alist))
=> (lambda (pair) (force (cdr pair)))
)
(else
(sxml:xpointer-runtime-error
"internal DDO SXPath error - "
"alist entry for context position not found: "
pred-id)
#f))))
(else
(sxml:xpointer-runtime-error
"internal DDO SXPath error - "
"alist entry for context size not found: "
pred-id)
#f))))
(else
(sxml:xpointer-runtime-error
"internal DDO SXPath error - alist entry for node not found: "
pred-id)
#f))))
(else
(sxml:xpointer-runtime-error
"internal DDO SXPath error - predicate value not found: " pred-id)
#f))))
(define (ddo:construct-pred-values pred-id pred-impl context-set var-binding)
(cons
pred-id
(map
(lambda (context)
(cons (sxml:context->node context)
(delay
(sxml:boolean (pred-impl (list context)
(cons 1 1) var-binding)))))
context-set)))
(define (ddo:construct-pred-values-pos pred-id pred-impl context-set
var-binding max-size)
(letrec
((construct-positions-alist
(lambda (context position size)
(if
(> position size) '()
(cons
(cons
position
(delay
(let ((pred-value
(pred-impl context (cons position size) var-binding)))
(if (number? pred-value)
(= pred-value position)
(sxml:boolean pred-value)))))
(construct-positions-alist context (+ position 1) size)))))
(construct-size-alist
(lambda (context size)
(if
(> size max-size) '()
(cons
(cons size
(construct-positions-alist context 1 size))
(construct-size-alist context (+ size 1)))))))
(cons
pred-id
(map
(lambda (context)
(cons (sxml:context->node context)
(construct-size-alist (list context) 1)))
context-set))))
(define (ddo:evaluate-deep-predicates deep-predicates doc var-binding)
(let* ((context-set
(let* ((nodes ((ddo:descendant-or-self sxml:node? #f) doc))
(attrs ((draft:attribute sxml:node? #f) nodes))
(attr-values ((draft:child (ntype?? '*text*) #f) attrs)))
(append nodes attrs attr-values)))
(max-size (if
(not (null? (filter cadr deep-predicates)))
(length context-set)
1 )))
(let iter-preds ((deep-predicates deep-predicates)
(var-binding var-binding))
(if
(null? deep-predicates) var-binding
(iter-preds
(cdr deep-predicates)
(cons
(if
(cadar deep-predicates) (ddo:construct-pred-values-pos (caar deep-predicates) (caddar deep-predicates) context-set
var-binding max-size)
(ddo:construct-pred-values (caar deep-predicates) (caddar deep-predicates) context-set
var-binding))
var-binding))))))
(define (ddo:ast-axis-specifier op num-anc single-level? requires-position?)
(cond
((not (eq? (car op) 'axis-specifier)) (draft:signal-semantic-error "not an AxisSpecifier - " op))
(requires-position?
(case (caadr op) ((ancestor)
(list ddo:ancestor-pos
#f #f #t))
((ancestor-or-self)
(list ddo:ancestor-or-self-pos
#f #f #t))
((attribute)
(list draft:attribute
(draft:na-minus-nneg num-anc 1) single-level? #f))
((child)
(if single-level?
(list draft:child
(draft:na-minus-nneg num-anc 1) #t #f)
(list ddo:child-pos
(draft:na-minus-nneg num-anc 1) #f #t)))
((descendant)
(if single-level?
(list draft:descendant
(draft:na-minus-nneg num-anc 1) #f #f)
(list ddo:descendant-pos
(draft:na-minus-nneg num-anc 1) #f #t)))
((descendant-or-self)
(if single-level?
(list draft:descendant-or-self
num-anc #f #f)
(list ddo:descendant-or-self-pos
num-anc #f #t)))
((following)
(list ddo:following-single-level-pos
#f #f #t))
((following-sibling)
(list (if single-level?
ddo:following-sibling-single-level-pos
ddo:following-sibling-pos)
(draft:na-max num-anc 1) single-level? #t))
((namespace)
(list draft:namespace
(draft:na-minus-nneg num-anc 1) single-level? #f))
((parent)
(list (if single-level? ddo:parent-single-level-pos ddo:parent-pos)
(draft:na+ num-anc 1) single-level? #t))
((preceding)
(list ddo:preceding-single-level-pos
#f #f #t))
((preceding-sibling)
(list (if single-level?
ddo:preceding-sibling-single-level-pos
ddo:preceding-sibling-pos)
(draft:na-max num-anc 1) single-level? #t))
((self)
(list draft:self num-anc single-level? #f))
(else
(draft:signal-semantic-error "unknown AxisName - " op))))
(else (case (caadr op) ((ancestor)
(list ddo:ancestor #f #f))
((ancestor-or-self)
(list ddo:ancestor-or-self #f #f))
((attribute)
(list draft:attribute
(draft:na-minus-nneg num-anc 1) single-level?))
((child)
(list (if single-level? draft:child ddo:child)
(draft:na-minus-nneg num-anc 1) single-level?))
((descendant)
(list (if single-level? draft:descendant ddo:descendant)
(draft:na-minus-nneg num-anc 1) #f))
((descendant-or-self)
(list (if single-level?
draft:descendant-or-self ddo:descendant-or-self)
num-anc #f))
((following)
(list (if single-level? ddo:following-single-level ddo:following)
#f #f))
((following-sibling)
(list (if single-level?
ddo:following-sibling-single-level ddo:following-sibling)
(draft:na-max num-anc 1) single-level?))
((namespace)
(list draft:namespace
(draft:na-minus-nneg num-anc 1) single-level?))
((parent)
(list (if single-level? ddo:parent-single-level ddo:parent)
(draft:na+ num-anc 1) single-level?))
((preceding)
(list (if single-level? ddo:preceding-single-level ddo:preceding)
#f #f))
((preceding-sibling)
(list (if single-level?
ddo:preceding-sibling-single-level ddo:preceding-sibling)
(draft:na-max num-anc 1) single-level?))
((self)
(list draft:self num-anc single-level?))
(else
(draft:signal-semantic-error "unknown AxisName - " op))))))
(define (ddo:ast-location-path op num-anc single-level? pred-nesting)
(case (car op)
((absolute-location-path)
(ddo:ast-absolute-location-path op num-anc single-level? pred-nesting))
((relative-location-path)
(ddo:ast-relative-location-path op num-anc single-level? pred-nesting))
(else
(draft:signal-semantic-error "improper LocationPath - " op))))
(define (ddo:ast-absolute-location-path op num-anc single-level? pred-nesting)
(cond
((not (eq? (car op) 'absolute-location-path))
(draft:signal-semantic-error "not an AbsoluteLocationPath - " op))
((null? (cdr op)) (list
(lambda (nodeset position+size var-binding)
(draft:reach-root nodeset))
#f #t #f ddo:type-nodeset
'() ))
(else
(and-let*
((steps-res (ddo:ast-step-list (cdr op) num-anc #t pred-nesting)))
(cons
(if
(null? (cdar steps-res)) (let ((step-impl (caar steps-res)))
(lambda (nodeset position+size var-binding)
(step-impl
(draft:reach-root nodeset) position+size var-binding)))
(let ((converters (car steps-res)))
(lambda (nodeset position+size var-binding)
(let rpt ((nset (draft:reach-root nodeset))
(fs converters))
(if (null? fs)
nset
(rpt ((car fs) nset position+size var-binding)
(cdr fs)))))))
(cons #f (cddr steps-res) ))))))
(define (ddo:ast-relative-location-path op num-anc single-level? pred-nesting)
(if
(not (eq? (car op) 'relative-location-path))
(draft:signal-semantic-error "not a RelativeLocationPath - " op)
(and-let*
((steps-res
(ddo:ast-step-list (cdr op) num-anc single-level? pred-nesting)))
(cons
(if
(null? (cdar steps-res)) (caar steps-res)
(let ((converters (car steps-res)))
(lambda (nodeset position+size var-binding)
(let rpt ((nset nodeset)
(fs converters))
(if (null? fs)
nset
(rpt ((car fs) nset position+size var-binding)
(cdr fs)))))))
(cdr steps-res) ))))
(define (ddo:ast-step op num-anc single-level? pred-nesting)
(cond
((eq? (car op) 'range-to)
(draft:signal-semantic-error "range-to function not implemented"))
((eq? (car op) 'filter-expr)
(ddo:ast-filter-expr op num-anc single-level? pred-nesting))
((eq? (car op) 'lambda-step) (let ((proc (cadr op)))
(list
(if
(and num-anc (zero? num-anc)) (lambda (nodeset position+size var-binding)
(proc (draft:contextset->nodeset (as-nodeset nodeset))
var-binding))
(lambda (nodeset position+size var-binding)
(draft:find-proper-context
(proc (draft:contextset->nodeset (as-nodeset nodeset))
var-binding)
(map sxml:context->content (as-nodeset nodeset))
num-anc)))
num-anc #f #f ddo:type-any
'() )))
((eq? (car op) 'step)
(if
(null? (cdddr op)) (and-let*
((axis-lst (ddo:ast-axis-specifier
(cadr op) num-anc single-level? #f))
(ntest (draft:ast-node-test (caddr op))))
(let ((axis ((car axis-lst) ntest num-anc)))
(list
(lambda (nodeset position+size var-binding)
(axis nodeset))
(cadr axis-lst)
(caddr axis-lst)
#f
ddo:type-nodeset
'() )))
(and-let*
((preds-res (ddo:ast-predicate-list
(cdddr op) 0 #t (+ pred-nesting 1)))
(preds-res
(if (and (list-ref preds-res 3) (< pred-nesting 3)) (ddo:ast-predicate-list (cdddr op) 0 #t
(+ pred-nesting 2) )
preds-res ))
(axis-lst (ddo:ast-axis-specifier
(cadr op)
(draft:na-max num-anc (cadr preds-res))
single-level?
(list-ref preds-res 3) ))
(ntest (draft:ast-node-test (caddr op))))
(let ((axis ((car axis-lst)
ntest (draft:na-max num-anc (cadr preds-res))))
(pred-impl-lst (car preds-res)))
(list
(cond
((not (list-ref preds-res 3)) (ddo:location-step-non-pos axis pred-impl-lst))
((list-ref axis-lst 3) (ddo:location-step-pos axis pred-impl-lst))
(else (ddo:location-step-non-intersect axis pred-impl-lst)))
(cadr axis-lst) (caddr axis-lst) #f ddo:type-nodeset
(list-ref preds-res 5) )))))
(else
(draft:signal-semantic-error "not a Step - " op))))
(define (ddo:ast-step-list step-lst num-anc single-level? pred-nesting)
(let ( (calculate-single-level
(lambda (step-lst single-level?)
(let iter-steps ((steps step-lst)
(sl? single-level?)
(res '()))
(cond
((null? steps) res)
((or (memq (caar steps) '(range-to filter-expr lambda-step))
(not sl?))
(append (map
(lambda (step) #f)
steps) res))
(else (and-let*
((axis-lst (ddo:ast-axis-specifier
(cadar steps) 0 sl? #f)))
(iter-steps (cdr steps)
(caddr axis-lst) (cons sl? res)))))))))
(and-let*
((single-level-lst (calculate-single-level step-lst single-level?)))
(let loop ((steps-to-view (reverse step-lst))
(sl?-lst single-level-lst)
(res-lst '())
(num-anc num-anc)
(deep-predicates '()))
(if
(null? steps-to-view) (list res-lst
num-anc (car single-level-lst) #f
ddo:type-nodeset deep-predicates)
(and-let*
((step-res
(ddo:ast-step
(car steps-to-view) num-anc (car sl?-lst) pred-nesting)))
(loop
(cdr steps-to-view)
(cdr sl?-lst)
(cons (car step-res) res-lst)
(cadr step-res)
(append (list-ref step-res 5) deep-predicates)
)))))))
(define (ddo:ast-predicate op num-anc single-level? pred-nesting)
(if
(not (eq? (car op) 'predicate))
(draft:signal-semantic-error "not an Predicate - " op)
(and-let*
((expr-res (ddo:ast-expr (cadr op) 0 #t pred-nesting)))
(let ((requires-position?
(or (cadddr expr-res) (memq (list-ref expr-res 4) '(ddo:type-number ddo:type-any)))))
(let-values*
(((pred-impl deep-predicates)
(if
(> pred-nesting 3) (let ((pred-id (ddo:generate-pred-id)))
(values
((if requires-position?
ddo:get-pred-value-pos ddo:get-pred-value)
pred-id)
(cons
(list pred-id
requires-position?
(car expr-res) )
(list-ref expr-res 5) )))
(values (car expr-res) (list-ref expr-res 5)))))
(list pred-impl
(cadr expr-res) (caddr expr-res) requires-position?
(list-ref expr-res 4) deep-predicates))))))
(define (ddo:ast-predicate-list op-lst num-anc single-level? pred-nesting)
(let ((pred-res-lst (map
(lambda (op) (ddo:ast-predicate op 0 #t pred-nesting))
op-lst)))
(if
(member #f pred-res-lst) #f
(list (map car pred-res-lst)
(apply draft:na-max (map cadr pred-res-lst))
#t
(apply ddo:or (map cadddr pred-res-lst))
ddo:type-any
(apply append (map
(lambda (pred-res) (list-ref pred-res 5))
pred-res-lst))))))
(define (ddo:ast-expr op num-anc single-level? pred-nesting)
(case (car op)
((or)
(ddo:ast-or-expr op num-anc single-level? pred-nesting))
((and)
(ddo:ast-and-expr op num-anc single-level? pred-nesting))
((= !=)
(ddo:ast-equality-expr op num-anc single-level? pred-nesting))
((< > <= >=)
(ddo:ast-relational-expr op num-anc single-level? pred-nesting))
((+ -)
(ddo:ast-additive-expr op num-anc single-level? pred-nesting))
((* div mod)
(ddo:ast-multiplicative-expr op num-anc single-level? pred-nesting))
((union-expr)
(ddo:ast-union-expr op num-anc single-level? pred-nesting))
((path-expr)
(ddo:ast-path-expr op num-anc single-level? pred-nesting))
((filter-expr)
(ddo:ast-filter-expr op num-anc single-level? pred-nesting))
((variable-reference)
(ddo:ast-variable-reference op num-anc single-level? pred-nesting))
((literal)
(ddo:ast-literal op num-anc single-level? pred-nesting))
((number)
(ddo:ast-number op num-anc single-level? pred-nesting))
((function-call)
(ddo:ast-function-call op num-anc single-level? pred-nesting))
((absolute-location-path)
(ddo:ast-absolute-location-path op num-anc single-level? pred-nesting))
((relative-location-path)
(ddo:ast-relative-location-path op num-anc single-level? pred-nesting))
(else
(draft:signal-semantic-error "unknown Expr - " op))))
(define (ddo:ast-or-expr op num-anc single-level? pred-nesting)
(let ((expr-res-lst
(map
(lambda (expr) (ddo:ast-expr expr 0 single-level? pred-nesting))
(cdr op))))
(if
(member #f expr-res-lst) #f
(let ((expr-impls (map car expr-res-lst)))
(list
(lambda (nodeset position+size var-binding)
(let rpt ((fs expr-impls))
(cond
((null? fs) #f)
((sxml:boolean ((car fs) nodeset position+size var-binding)) #t)
(else (rpt (cdr fs))))))
(apply draft:na-max (map cadr expr-res-lst)) #t (apply ddo:or (map cadddr expr-res-lst)) ddo:type-boolean
(apply append (map
(lambda (expr-res) (list-ref expr-res 5))
expr-res-lst)))))))
(define (ddo:ast-and-expr op num-anc single-level? pred-nesting)
(let ((expr-res-lst
(map
(lambda (expr) (ddo:ast-expr expr 0 single-level? pred-nesting))
(cdr op))))
(if
(member #f expr-res-lst) #f
(let ((expr-impls (map car expr-res-lst)))
(list
(lambda (nodeset position+size var-binding)
(let rpt ((fs expr-impls))
(cond
((null? fs) #t)
((not
(sxml:boolean ((car fs) nodeset position+size var-binding)))
#f)
(else (rpt (cdr fs))))))
(apply draft:na-max (map cadr expr-res-lst)) #t (apply ddo:or (map cadddr expr-res-lst)) ddo:type-boolean
(apply append (map
(lambda (expr-res) (list-ref expr-res 5))
expr-res-lst)))))))
(define (ddo:ast-equality-expr op num-anc single-level? pred-nesting)
(and-let*
((left-lst (ddo:ast-expr (cadr op) 0 single-level? pred-nesting))
(right-lst (ddo:ast-expr (caddr op) 0 single-level? pred-nesting)))
(let ((cmp-op (cadr (assq (car op) `((= ,sxml:equal?)
(!= ,sxml:not-equal?)))))
(left (car left-lst))
(right (car right-lst)))
(list
(lambda (nodeset position+size var-binding)
(cmp-op
(draft:contextset->nodeset
(left nodeset position+size var-binding))
(draft:contextset->nodeset
(right nodeset position+size var-binding))))
(draft:na-max (cadr left-lst) (cadr right-lst)) #t (or (cadddr left-lst) (cadddr right-lst)) ddo:type-boolean
(append (list-ref left-lst 5) (list-ref right-lst 5))))))
(define (ddo:ast-relational-expr op num-anc single-level? pred-nesting)
(and-let*
((left-lst (ddo:ast-expr (cadr op) 0 single-level? pred-nesting))
(right-lst (ddo:ast-expr (caddr op) 0 single-level? pred-nesting)))
(let ((cmp-op
(sxml:relational-cmp
(cadr (assq (car op) `((< ,<) (> ,>) (<= ,<=) (>= ,>=))))))
(left (car left-lst))
(right (car right-lst)))
(list
(lambda (nodeset position+size var-binding)
(cmp-op
(draft:contextset->nodeset
(left nodeset position+size var-binding))
(draft:contextset->nodeset
(right nodeset position+size var-binding))))
(draft:na-max (cadr left-lst) (cadr right-lst)) #t (or (cadddr left-lst) (cadddr right-lst)) ddo:type-boolean
(append (list-ref left-lst 5) (list-ref right-lst 5))))))
(define (ddo:ast-additive-expr op num-anc single-level? pred-nesting)
(let ((expr-res-lst
(map
(lambda (expr) (ddo:ast-expr expr 0 single-level? pred-nesting))
(cdr op))))
(if
(member #f expr-res-lst) #f
(let ((add-op (cadr (assq (car op) `((+ ,+) (- ,-)))))
(expr-impls (map car expr-res-lst)))
(list
(lambda (nodeset position+size var-binding)
(apply
add-op
(map
(lambda (expr)
(sxml:number
(draft:contextset->nodeset
(expr nodeset position+size var-binding))))
expr-impls)))
(apply draft:na-max (map cadr expr-res-lst)) #t (apply ddo:or (map cadddr expr-res-lst)) ddo:type-number
(apply append (map
(lambda (expr-res) (list-ref expr-res 5))
expr-res-lst)))))))
(define (ddo:ast-multiplicative-expr op num-anc single-level? pred-nesting)
(and-let*
((left-lst (ddo:ast-expr (cadr op) 0 single-level? pred-nesting))
(right-lst (ddo:ast-expr (caddr op) 0 single-level? pred-nesting)))
(let ((mul-op
(sxml:relational-cmp
(cadr (assq (car op) `((* ,*) (div ,/) (mod ,remainder))))))
(left (car left-lst))
(right (car right-lst)))
(list
(lambda (nodeset position+size var-binding)
(mul-op
(sxml:number
(draft:contextset->nodeset
(left nodeset position+size var-binding)))
(sxml:number
(draft:contextset->nodeset
(right nodeset position+size var-binding)))))
(draft:na-max (cadr left-lst) (cadr right-lst)) #t (or (cadddr left-lst) (cadddr right-lst)) ddo:type-number
(append (list-ref left-lst 5) (list-ref right-lst 5))))))
(define (ddo:ast-union-expr op num-anc single-level? pred-nesting)
(let ((expr-res-lst
(map
(lambda (expr)
(let ((expr-res
(ddo:ast-expr expr #f single-level? pred-nesting)))
(if
(not (or (eq? (list-ref expr-res 4) ddo:type-nodeset)
(eq? (list-ref expr-res 4) ddo:type-any)))
(draft:signal-semantic-error
"expression to be unioned evaluates to a non-nodeset - "
expr)
expr-res)))
(cdr op))))
(if
(member #f expr-res-lst) #f
(let ((expr-impls (map car expr-res-lst)))
(list
(lambda (nodeset position+size var-binding)
(let rpt ((res '())
(fs expr-impls))
(if
(null? fs)
res
(let ((nset ((car fs) nodeset position+size var-binding)))
(rpt
(ddo:unite-2-contextsets
res
(cond
((not (nodeset? nset))
(sxml:xpointer-runtime-error
"expected - nodeset instead of " nset)
'())
(else nset)))
(cdr fs))))))
#f #f (apply ddo:or (map cadddr expr-res-lst)) ddo:type-nodeset
(apply append (map
(lambda (expr-res) (list-ref expr-res 5))
expr-res-lst)))))))
(define (ddo:ast-path-expr op num-anc single-level? pred-nesting)
(and-let*
((steps-res (ddo:ast-step-list
(cddr op) num-anc
#f pred-nesting))
(filter-lst (ddo:ast-filter-expr
(cadr op)
(cadr steps-res) single-level?
pred-nesting)))
(if
(not (or (eq? (list-ref filter-lst 4) ddo:type-nodeset)
(eq? (list-ref filter-lst 4) ddo:type-any)))
(draft:signal-semantic-error
"location steps are applied to a non-nodeset result - " (cadr op))
(let ((init-impl (car filter-lst))
(converters (car steps-res)))
(list
(lambda (nodeset position+size var-binding)
(let ((nset
(init-impl nodeset position+size var-binding)))
(let rpt ((nset
(cond
((nodeset? nset) nset)
(else
(sxml:xpointer-runtime-error
"expected - nodeset instead of " nset)
'())))
(fs converters))
(if (null? fs)
nset
(rpt ((car fs) nset position+size var-binding)
(cdr fs))))))
(cadr filter-lst) (cadddr steps-res) (cadddr filter-lst) ddo:type-nodeset
(append (list-ref filter-lst 5) (list-ref steps-res 5)))))))
(define (ddo:ast-filter-expr op num-anc single-level? pred-nesting)
(cond
((not (eq? (car op) 'filter-expr))
(draft:signal-semantic-error "not an FilterExpr - " op))
((not (eq? (caadr op) 'primary-expr))
(draft:signal-semantic-error "not an PrimaryExpr - " (cadr op)))
((null? (cddr op)) (ddo:ast-expr (cadadr op) num-anc single-level? pred-nesting))
((and (null? (cdddr op)) (ddo:check-special-predicate (caddr op)))
=> (lambda (special-pred-impl)
(and-let*
((expr-lst (ddo:ast-expr
(cadadr op)
num-anc single-level? pred-nesting)))
(list
(ddo:filter-expr-special-predicate
(car expr-lst) special-pred-impl)
(cadr expr-lst) (caddr expr-lst) (cadddr expr-lst) ddo:type-nodeset
(list-ref expr-lst 5) ))))
(else (and-let*
((preds-res (ddo:ast-predicate-list (cddr op) 0 #t (+ pred-nesting 1)))
(expr-lst (ddo:ast-expr
(cadadr op)
(draft:na-max num-anc (cadr preds-res)) single-level? pred-nesting)))
(if
(not (or (eq? (list-ref expr-lst 4) ddo:type-nodeset)
(eq? (list-ref expr-lst 4) ddo:type-any)))
(draft:signal-semantic-error
"expression to be filtered evaluates to a non-nodeset - " (cadr op))
(let ((expr-impl (car expr-lst))
(pred-impl-lst (car preds-res)))
(list
(if
(list-ref preds-res 3) (ddo:filter-expr-general expr-impl pred-impl-lst)
(ddo:filter-expr-non-pos expr-impl pred-impl-lst))
(cadr expr-lst) (caddr expr-lst) (cadddr expr-lst) ddo:type-nodeset
(append (list-ref expr-lst 5) (list-ref preds-res 5)))))))))
(define (ddo:ast-variable-reference op num-anc single-level? pred-nesting)
(let ((name (string->symbol (cadr op))))
(list
(lambda (nodeset position+size var-binding)
(cond
((assoc name var-binding)
=> cdr)
(else
(sxml:xpointer-runtime-error "unbound variable - " name)
'())))
0
#t #f
ddo:type-any '() )))
(define (ddo:ast-literal op num-anc single-level? pred-nesting)
(let ((literal (cadr op)))
(list
(lambda (nodeset position+size var-binding) literal)
0 #t #f ddo:type-string '())))
(define (ddo:ast-number op num-anc single-level? pred-nesting)
(let ((number (cadr op)))
(list
(lambda (nodeset position+size var-binding) number)
0 #t #f ddo:type-number '())))
(define (ddo:ast-function-call op num-anc single-level? pred-nesting)
(let ((core-alist
`((last 0 0 0 ,draft:core-last
#t #t ,ddo:type-number)
(position 0 0 0 ,draft:core-position
#t #t ,ddo:type-number)
(count 1 1 0 ,draft:core-count
#t #f ,ddo:type-number)
(id 1 1 #f ,draft:core-id
#f #f ,ddo:type-nodeset)
(local-name 0 1 0 ,draft:core-local-name
#t #f ,ddo:type-string)
(namespace-uri 0 1 0 ,draft:core-namespace-uri
#t #f ,ddo:type-string)
(name 0 1 0 ,draft:core-name
#t #f ,ddo:type-string)
(string 0 1 0 ,draft:core-string
#t #f ,ddo:type-string)
(concat 2 -1 0 ,draft:core-concat
#t #f ,ddo:type-string)
(starts-with 2 2 0 ,draft:core-starts-with
#t #f ,ddo:type-boolean)
(contains 2 2 0 ,draft:core-contains
#t #f ,ddo:type-boolean)
(substring-before 2 2 0 ,draft:core-substring-before
#t #f ,ddo:type-boolean)
(substring-after 2 2 0 ,draft:core-substring-after
#t #f ,ddo:type-boolean)
(substring 2 3 0 ,draft:core-substring
#t #f ,ddo:type-boolean)
(string-length 0 1 0 ,draft:core-string-length
#t #f ,ddo:type-number)
(normalize-space 0 1 0 ,draft:core-normalize-space
#t #f ,ddo:type-string)
(translate 3 3 0 ,draft:core-translate
#t #f ,ddo:type-string)
(boolean 1 1 0 ,draft:core-boolean
#t #f ,ddo:type-boolean)
(not 1 1 0 ,draft:core-not
#t #f ,ddo:type-boolean)
(true 0 0 0 ,draft:core-true
#t #f ,ddo:type-boolean)
(false 0 0 0 ,draft:core-false
#t #f ,ddo:type-boolean)
(lang 1 1 #f ,draft:core-lang
#t #f ,ddo:type-boolean)
(number 0 1 0 ,draft:core-number
#t #f ,ddo:type-number)
(sum 1 1 0 ,draft:core-sum
#t #f ,ddo:type-number)
(floor 1 1 0 ,draft:core-floor
#t #f ,ddo:type-number)
(ceiling 1 1 0 ,draft:core-ceiling
#t #f ,ddo:type-number)
(round 1 1 0 ,draft:core-round
#t #f ,ddo:type-number))))
(cond
((not (eq? (caadr op) 'function-name))
(draft:signal-semantic-error "not an FunctionName - " (cadr op)))
((assq (string->symbol (cadadr op)) core-alist)
=> (lambda (description) (cond
((< (length (cddr op)) (cadr description))
(draft:signal-semantic-error
"too few arguments for the Core Function call - "
(cadadr op)))
((and (>= (caddr description) 0)
(> (length (cddr op)) (caddr description)))
(draft:signal-semantic-error
"too many arguments for the Core Function call - "
(cadadr op)))
(else (and-let*
((args-impl-lst (ddo:ast-function-arguments
(cddr op) single-level? pred-nesting)))
(list
(apply (list-ref description 4)
num-anc
(map car args-impl-lst))
(apply draft:na-max
(cons
(list-ref description 3) (map cadr args-impl-lst) ))
(list-ref description 5) (or (list-ref description 6) (not (null?
(filter cadddr args-impl-lst))))
(list-ref description 7) (apply append (map
(lambda (arg-res) (list-ref arg-res 5))
args-impl-lst))))))))
(else (draft:signal-semantic-error
"function call to an unknown function - " (cadadr op))))))
(define (ddo:ast-function-arguments op-lst single-level? pred-nesting)
(let ((arg-res-lst
(map
(lambda (op)
(if
(not (eq? (car op) 'argument))
(draft:signal-semantic-error "not an Argument - " op)
(ddo:ast-expr (cadr op) 0 single-level? pred-nesting)))
op-lst)))
(if
(member #f arg-res-lst) #f
arg-res-lst)))
(define (ddo:api-helper grammar-parser ast-parser)
(lambda (xpath-string . ns+na)
(let-values*
(((ns-binding num-anc) (draft:arglist->ns+na ns+na)))
(and-let*
((ast (grammar-parser xpath-string ns-binding))
(impl-lst (ast-parser ast num-anc
#t 0 )))
(let ((impl-lambda
(if
(and num-anc (zero? num-anc))
(let ((impl-car (car impl-lst)))
(lambda (node position+size var-binding)
(draft:contextset->nodeset
(impl-car node position+size var-binding))))
(car impl-lst))))
(if
(null? (list-ref impl-lst 5)) (lambda (node . var-binding) (impl-lambda
(as-nodeset node)
(cons 1 1)
(if (null? var-binding) var-binding (car var-binding))))
(let ((deep-predicates (reverse (list-ref impl-lst 5))))
(lambda (node . var-binding)
(impl-lambda
(as-nodeset node)
(cons 1 1)
(ddo:evaluate-deep-predicates
deep-predicates
node
(if (null? var-binding)
var-binding (car var-binding))))))))))))
(define ddo:txpath (ddo:api-helper txp:xpath->ast ddo:ast-location-path))
(define ddo:xpath-expr (ddo:api-helper txp:expr->ast ddo:ast-expr))
(define ddo:sxpath (ddo:api-helper txp:sxpath->ast ddo:ast-expr))
(provide (all-defined)))