
information representation. This should make datalog work better with compiled files and it should also avoid an O(n^2) problem in the way it expands
224 lines
6.9 KiB
Racket
224 lines
6.9 KiB
Racket
#lang racket/base
|
|
(require (for-syntax racket/base
|
|
syntax/parse
|
|
racket/local
|
|
racket/function
|
|
racket/list)
|
|
racket/list
|
|
racket/match
|
|
datalog/ast
|
|
datalog/eval)
|
|
|
|
(define-syntax (:- stx)
|
|
(raise-syntax-error ':- "only allowed inside ! and ~" stx))
|
|
(define-syntax (! stx)
|
|
(raise-syntax-error '! "only allowed inside datalog" stx))
|
|
(define-syntax (~ stx)
|
|
(raise-syntax-error '~ "only allowed inside datalog" stx))
|
|
(define-syntax (? stx)
|
|
(raise-syntax-error '? "only allowed inside datalog" stx))
|
|
|
|
(define (->substitutions sel ls)
|
|
(if (void? ls) empty
|
|
(map sel ls)))
|
|
|
|
(define literal->sexp
|
|
(match-lambda
|
|
[(external _ pred-sym _ args anss)
|
|
`(,pred-sym ,@(map term->datum args)
|
|
:-
|
|
,@(map term->datum anss))]
|
|
[(literal _ pred ts)
|
|
(list* (if '(predicate-sym? pred)
|
|
'(predicate-sym-sym pred)
|
|
pred)
|
|
(map term->datum ts))]))
|
|
|
|
(define term->datum
|
|
(match-lambda
|
|
[(constant _ v)
|
|
v]))
|
|
|
|
(define-syntax (datalog stx)
|
|
(syntax-case stx ()
|
|
[(_ thy-expr stmt ...)
|
|
(syntax/loc stx
|
|
(parameterize ([current-theory thy-expr])
|
|
(void)
|
|
(->substitutions
|
|
(datalog-stmt-var-selector stmt)
|
|
(eval-statement (datalog-stmt stmt)))
|
|
...))]))
|
|
|
|
(define-syntax (datalog! stx)
|
|
(syntax-case stx ()
|
|
[(_ thy-expr stmt ...)
|
|
(syntax/loc stx
|
|
(parameterize ([current-theory thy-expr])
|
|
(void)
|
|
(eval-top-level-statement (datalog-stmt stmt))
|
|
...))]))
|
|
|
|
(define-syntax (datalog-stmt stx)
|
|
(syntax-parse
|
|
stx
|
|
#:literals (! ~ ?)
|
|
[(_ (~and tstx (! c)))
|
|
(quasisyntax/loc #'tstx
|
|
(assertion #,(srcloc-list #'tstx) (datalog-clause c)))]
|
|
[(_ (~and tstx (~ c)))
|
|
(quasisyntax/loc #'tstx
|
|
(retraction #,(srcloc-list #'tstx) (datalog-clause c)))]
|
|
[(_ (~and tstx (? l)))
|
|
(quasisyntax/loc #'tstx
|
|
(query #,(srcloc-list #'tstx) (datalog-literal/ref l)))]))
|
|
|
|
(define-syntax (datalog-stmt-var-selector stx)
|
|
(syntax-parse
|
|
stx
|
|
#:literals (! ~ ?)
|
|
[(_ (~and tstx (! c)))
|
|
(quasisyntax/loc #'tstx (λ (l) (hasheq)))]
|
|
[(_ (~and tstx (~ c)))
|
|
(quasisyntax/loc #'tstx (λ (l) (hasheq)))]
|
|
[(_ (~and tstx (? l)))
|
|
(quasisyntax/loc #'tstx (datalog-literal-var-selector l))]))
|
|
|
|
(define-syntax (datalog-clause stx)
|
|
(syntax-parse
|
|
stx
|
|
#:literals (:-)
|
|
[(_ (~and tstx (:- head body ...)))
|
|
(local [(define (datalog-literal-variables stx)
|
|
(syntax-parse
|
|
stx
|
|
#:literals (:-)
|
|
[sym:id
|
|
empty]
|
|
[(~and tstx (sym:id arg ... :- ans ...))
|
|
(append-map datalog-term-variables
|
|
(syntax->list #'(arg ... ans ...)))]
|
|
[(~and tstx (sym:id e ...))
|
|
(append-map datalog-term-variables
|
|
(syntax->list #'(e ...)))]))
|
|
(define (datalog-term-variables stx)
|
|
(syntax-parse
|
|
stx
|
|
[sym:id
|
|
(cond
|
|
[(identifier-binding #'sym 0)
|
|
empty]
|
|
[(char-upper-case? (string-ref (symbol->string (syntax->datum #'sym)) 0))
|
|
(list #'sym)]
|
|
[else
|
|
empty])]
|
|
[sym:expr
|
|
empty]))
|
|
(define head-vars (datalog-literal-variables #'head))
|
|
(define body-vars
|
|
(append-map datalog-literal-variables (syntax->list #'(body ...))))
|
|
(define body-vars-in-head
|
|
(filter
|
|
(λ (bv)
|
|
(findf (curry bound-identifier=? bv)
|
|
head-vars))
|
|
body-vars))
|
|
(define fake-lam
|
|
(quasisyntax/loc #'tstx
|
|
(lambda #,head-vars
|
|
(void #,@body-vars-in-head))))]
|
|
(syntax-local-lift-expression
|
|
fake-lam))
|
|
(quasisyntax/loc #'tstx
|
|
(clause #,(srcloc-list #'tstx) (datalog-literal/bind head)
|
|
(list (datalog-literal/ref body) ...)))]
|
|
[(_ e)
|
|
(quasisyntax/loc #'e
|
|
(clause #,(srcloc-list #'e) (datalog-literal/bind e) empty))]))
|
|
|
|
(define-syntax (datalog-literal/bind stx) (datalog-literal/b stx #t))
|
|
(define-syntax (datalog-literal/ref stx) (datalog-literal/b stx #f))
|
|
|
|
(define-for-syntax (datalog-literal/b stx binding?)
|
|
(syntax-parse
|
|
stx
|
|
#:literals (:-)
|
|
[(_ sym:id)
|
|
(syntax-property
|
|
(quasisyntax/loc #'sym
|
|
(literal #,(srcloc-list #'sym) 'sym empty))
|
|
(if binding? 'disappeared-binding 'disappeared-use)
|
|
(syntax-local-introduce #'sym))]
|
|
[(_ (~and tstx (sym:id arg ... :- ans ...)))
|
|
(quasisyntax/loc #'tstx
|
|
(external #,(srcloc-list #'tstx) 'sym sym
|
|
(list (datalog-term arg) ...)
|
|
(list (datalog-term ans) ...)))]
|
|
[(_ (~and tstx (sym:id e ...)))
|
|
(syntax-property
|
|
(quasisyntax/loc #'tstx
|
|
(literal #,(srcloc-list #'tstx) 'sym
|
|
(list (datalog-term e)
|
|
...)))
|
|
(if binding? 'disappeared-binding 'disappeared-use)
|
|
(syntax-local-introduce #'sym))]))
|
|
|
|
(define-syntax (datalog-literal-var-selector stx)
|
|
(syntax-parse
|
|
stx
|
|
#:literals (:-)
|
|
[(_ sym:id)
|
|
(quasisyntax/loc #'sym (λ (l) (hasheq)))]
|
|
[(_ (~and tstx (sym:id arg ... :- ans ...)))
|
|
(quasisyntax/loc #'tstx
|
|
(match-lambda
|
|
[(external _srcloc _predsym _pred args anss)
|
|
(terms->hasheq (list (datalog-term arg) ...
|
|
(datalog-term ans) ...)
|
|
(append args anss))]))]
|
|
[(_ (~and tstx (sym:id e ...)))
|
|
(quasisyntax/loc #'tstx
|
|
(match-lambda
|
|
[(literal _srcloc _predsym ts)
|
|
(terms->hasheq (list (datalog-term e) ...)
|
|
ts)]))]))
|
|
|
|
(define (terms->hasheq src-ts res-ts)
|
|
(for/fold ([h (hasheq)])
|
|
([src (in-list src-ts)]
|
|
[res (in-list res-ts)])
|
|
(if (variable? src)
|
|
(hash-set h (variable-sym src) (constant-value res))
|
|
h)))
|
|
|
|
(define-syntax (datalog-term stx)
|
|
(syntax-parse
|
|
stx
|
|
[(_ sym:id)
|
|
(cond
|
|
[(identifier-binding #'sym 0)
|
|
(quasisyntax/loc #'sym
|
|
(constant #,(srcloc-list #'sym) sym))]
|
|
[(char-upper-case? (string-ref (symbol->string (syntax->datum #'sym)) 0))
|
|
(quasisyntax/loc #'sym
|
|
(variable #,(srcloc-list #'sym) 'sym))]
|
|
[else
|
|
(quasisyntax/loc #'sym
|
|
(constant #,(srcloc-list #'sym) 'sym))])]
|
|
[(_ sym:expr)
|
|
(quasisyntax/loc #'sym
|
|
(constant #,(srcloc-list #'sym) sym))]))
|
|
|
|
(define-for-syntax (srcloc-list stx)
|
|
(define src (syntax-source stx))
|
|
`(list ,(if (path? src)
|
|
`(bytes->path ,(path->bytes src))
|
|
`',src)
|
|
',(syntax-line stx)
|
|
',(syntax-column stx)
|
|
',(syntax-position stx)
|
|
',(syntax-span stx)))
|
|
|
|
(provide datalog datalog!
|
|
:- ! ~ ?)
|