From 246974441fb5dc155260c273c61757cbc90469a8 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sun, 12 Jun 2011 02:56:58 +0300 Subject: Move scm/conjugator.scm to src/ellinika --- src/ellinika/conjugator.scm | 657 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 657 insertions(+) create mode 100644 src/ellinika/conjugator.scm (limited to 'src') diff --git a/src/ellinika/conjugator.scm b/src/ellinika/conjugator.scm new file mode 100644 index 0000000..edc649e --- /dev/null +++ b/src/ellinika/conjugator.scm @@ -0,0 +1,657 @@ +(use-modules (srfi srfi-1) + (ellinika elmorph) + (ellinika i18n) + (ellinika cgi) + (ellinika tenses) + (xmltools dict) + (gamma sql)) + +(use-syntax (ice-9 syncase)) + +; FIXME: +(ellinika-cgi-init dict-template-file-name) + +(define (mk-dict-connect) + (let ((db-connection #f)) + (lambda (. rest) + (cond + ((null? rest) + (if (not db-connection) + (begin + (set! db-connection + (sql-open-connection + ellinika-sql-connection)) + (sql-query db-connection "SET NAMES utf8") + ))) + (else + (if db-connection + (sql-close-connection db-connection)) + (set! db-connection #f))) + db-connection))) + +(define dict-connect (mk-dict-connect)) + +(define (q-my-sql-query conn query) + (catch #t + (lambda () + (sql-query conn query)) + (lambda args + '()))) + +(define (my-sql-query conn query) +; (format #t "Q: ~A~%" query) + (let ((res (sql-query conn query))) +; (format #t "R: ~A~%" res) + res)) + + +(define (sql-error-handler key func fmt fmtargs data) + (format #t "

~A

\n" + (_ "ΣΦΆΛΜΑ: σύνδεση με το λέξικο απέτυχε.")) + (apply format (current-error-port) fmt fmtargs)) + +(define verb-info-template + (list + (list "A" + #f + "ε" + #f + #f + #f) + (list "B1" + #f + #f + #f + #f + #f) + (list "B2" + #f + #f + #f + #f + #f))) + +(define (guess-verb-info verb) + (cond + ;; FIXME + ((elstr-suffix? verb "άω") + (assoc "B1" verb-info-template)) + ((elstr-suffix? verb "ώ") + (assoc "B2" verb-info-template)) + ;; FIXME: deponentia? + (else + (assoc "A" verb-info-template)))) + +(define (get-verb-info verb . rest) + (let ((conn (dict-connect)) + (class (if (null? rest) + "" + (string-append " AND conj='" (car rest) "'")))) + (let ((vdb (my-sql-query + conn + (string-append + "SELECT conj,accmap,augment,suffix FROM verb \ +WHERE verb='" (force-string verb) "'" + class)))) + (cond + ((and vdb (not (null? vdb))) + (let ((x (car vdb))) + (list + (list-ref x 0) + (list-ref x 1) + (or (list-ref x 2) "ε") + (list-ref x 3) + #f + '(class)))) + ((elstr-suffix? verb "άω") + (get-verb-info (elstr-append + (elstr-trim verb -2) "ώ") "B1")) + ((null? rest) + (guess-verb-info verb)) + (else + (assoc (car rest) verb-info-template)))))) + +(define (thema-aoristoy-mesapathitikis root) + (cond + ((elstr-suffix? root "αίν") + (elstr-append (elstr-trim root -3) "ανθ")) ;; FIXME: Also αθ, ηθ + ((and + (elstr-suffix? root "ν") + (logand (elstr-char-prop-bitmask root -2) elmorph:vowel)) + (elstr-append (elstr-trim root -1) "θ")) ;; FIXME: also στ, νθ, θ + ((and + (elstr-suffix? root "δ" "θ" "ζ" "ν") ;; FIXME: see above + (logand (elstr-char-prop-bitmask root -2) elmorph:vowel)) + (elstr-append (elstr-trim root -1) "στ")) + ((elstr-suffix? root "γγ" "σσ" "ττ" "χν" "γ" "ζ" "κ" "χ") => + (lambda (suf) + (elstr-append (elstr-trim root (- 0 (elstr-length (string->elstr suf)))) + "χτ"))) ;; also χθ + ((elstr-suffix? root "π" "β" "φ" "πτ" "φτ") => + (lambda (suf) + (elstr-append (elstr-trim root (- 0 (elstr-length (string->elstr suf)))) + "φτ"))) ;; also φθ + ((elstr-suffix? root "αύ" "εύ") => + (lambda (suf) + (elstr-append root "τ"))) + ((elstr-suffix? root "άρ" "ίρ") + ((elstr-append root "ιστ"))) + ((logand (elstr-char-prop-bitmask root -1) elmorph:vowel) + (elstr-append root "θ")) + (else + #f))) + +(define (lookup-verb-info verb voice thema) + (my-sql-query + (dict-connect) + (string-append + "SELECT root FROM irregular_root \ +WHERE verb='" verb "' AND voice='" voice "' AND thema='" thema "'"))) + +(define (verb-A-root verb) + (cond + ((elstr-suffix? verb "ω") + (elstr-trim verb -1)) + ((elstr-suffix? verb "ομαι") + (elstr-trim verb -4)) + (else + (error "cannot handle ~A~%" verb)))) + +(define (complement-verb-info vinfo verb voice thema) +; (format #t "COMPLEMENT ~A~%" thema) + (let ((elverb (string->elstr verb)) + (result (let ((tmpres (lookup-verb-info verb voice thema))) + (if (and (null? tmpres) (string=? thema "sub")) + (lookup-verb-info verb voice "aor") + tmpres)))) + (verb-info-set! #:root vinfo + (cond + ((not (null? result)) + (verb-info-set! #:attested vinfo 'root) + (caar result)) + ((string=? (verb-info #:conj vinfo) "A") + (let ((root (verb-A-root elverb))) + (cond + ((string=? thema "pres") + (verb-info-set! #:attested vinfo 'root) + root) + ((or (string=? thema "aor") (string=? thema "sub")) + (if (string=? voice "act") + (elstr-thema-aoristoy root) + (thema-aoristoy-mesapathitikis root))) + (else + #f)))) + ((string=? (verb-info #:conj vinfo) "A-depon") + (let ((root (verb-A-root elverb))) + (cond + ((string=? thema "pres") + (verb-info-set! #:attested vinfo 'root) + root) + ((or (string=? thema "aor") (string=? thema "sub")) + #f) ; FIXME + (else + #f)))) + ((string=? (verb-info #:conj vinfo) "B1") + (let ((root (if (elstr-suffix? elverb "άω") + (elstr-trim elverb -2) + (elstr-trim elverb -1)))) + (cond + ((or (string=? voice "act") (string=? thema "pres")) + (verb-info-set! #:attested vinfo 'root) + root) + ((or (string=? thema "aor") (string=? thema "sub")) + (elstr-append root "ηθ")) ;; FIXME: guesswork + (else + #f)))) + ((string=? (verb-info #:conj vinfo) "B2") + (let ((root (elstr-trim elverb -1))) + (cond + ((or (string=? voice "act") (string=? thema "pres")) + (verb-info-set! #:attested vinfo 'root) + root) + ((or (string=? thema "aor") (string=? thema "sub")) + (elstr-append root "ηθ")) ;; FIXME: guesswork + (else + #f)))) + (else + #f))))) + +(define-syntax verb-info + (syntax-rules () + ((verb-info #:conj v) + (list-ref v 0)) + ((verb-info #:accmap v) + (list-ref v 1)) + ((verb-info #:augment v) + (list-ref v 2)) + ((verb-info #:suffix v) + (list-ref v 3)) + ((verb-info #:root v) + (list-ref v 4)) + ((verb-info #:attested v) + (list-ref v 5)))) + +(define-syntax verb-info-set! + (syntax-rules () + ((verb-info-set! #:root v val) + (list-set! v 4 val)) + ((verb-info-set! #:attested v val) + (list-set! v 5 + (if (not val) + val + (let ((oldval (list-ref v 5))) + (cond + ((not oldval) + (list val)) + ((boolean? oldval) + (list val)) + ((member val oldval) + oldval) + (else + (cons val oldval))))))))) + +(define-syntax conj-info + (syntax-rules () + ((conj-info #:thema v) + (list-ref v 0)) + ((conj-info #:suffix v) + (list-ref v 1)) + ((conj-info #:accmap v) + (list-ref v 2)) + ((conj-info #:particle v) + (list-ref v 3)) + ((conj-info #:aux v) + (list-ref v 4)) + ((conj-info #:auxtense v) + (list-ref v 5)) + ((conj-info #:fold v) + (list-ref v 6)) + ((conj-info #:flect v) + (list-tail v 7)) + ((conj-info #:sing 1 v) + (list-ref v 8)) + ((conj-info #:sing 2 v) + (list-ref v 9)) + ((conj-info #:sing 3 v) + (list-ref v 10)) + ((conj-info #:plur 1 v) + (list-ref v 11)) + ((conj-info #:plur 1 v) + (list-ref v 12)) + ((conj-info #:plur 1 v) + (list-ref v 13)))) + +(define-syntax conj-info-set! + (syntax-rules () + ((conj-info-set! #:particle v val) + (list-set! v 3 val)))) + +(define (get-conj-info conj voice mood tense) + (let ((conn (dict-connect))) + (let ((answer (my-sql-query + conn + (string-append + "SELECT c.thema,c.suffix,c.accmap,c.particle,c.aux,c.auxtense,c.fold AS fold,\ +f.sing1,f.sing2,f.sing3,f.plur1,f.plur2,f.plur3 \ +FROM conjugation c, verbflect f \ +WHERE c.conj='" conj "' AND c.voice='" voice "' AND c.mood='" mood +"' AND c.tense='" tense "' AND c.flect = f.ident ORDER by fold")))) + (if (null? answer) + #f + answer)))) + +(define (force-string str) + (if (elstr? str) + (elstr->string str) + str)) + +(define (force-elstr str) + (if (string? str) + (string->elstr str) + str)) + +(define (accented-syllable-0 str) + (let ((syl (elstr-accented-syllable str)) + (len (elstr-number-of-syllables str))) + (if (= syl 0) + syl + (+ (- len syl) 1)))) + +(define (apply-flect conj vinfo verb) +; (format #t "VINFO ~A~%" vinfo) + (let ((root (verb-info #:root vinfo)) + (suffix (let ((s (conj-info #:suffix conj))) + (if s + (or (verb-info #:suffix vinfo) s) + ""))) + (accmap (string->list (or (verb-info #:accmap vinfo) + (conj-info #:accmap conj) + "000000"))) + (augment "")) +; (format #t "ROOT ~S, ACCMAP ~S, SUFFIX: ~S~%" root accmap suffix) + (cond + ((> (length accmap) 6) + (set! accmap (list-head accmap 6)) + (set! augment (verb-info #:augment vinfo)))) + (let ((forms + (map + (lambda (flect acc) + (cond + ((not flect) #f) + ((char=? acc #\0) + (let* ((rs (force-elstr root)) + (suf (elstr-deaccent (elstr-append suffix flect))) + (result (elstr-append rs suf)) + (nsyl (elstr-number-of-syllables result)) + (acc-syl (+ (- nsyl + (let ((n (accented-syllable-0 rs))) + (if (= 0 n) + (accented-syllable-0 verb) + n))) 1))) + (cond + ((= nsyl 1) + (elstr-deaccent result)) + ((> acc-syl 3) + (elstr-set-accent result 3)) ; FIXME + (else + (elstr-set-accent result acc-syl))))) + ((char=? acc #\f) + (elstr-append + (elstr-deaccent (elstr-append root suffix)) + flect)) + ((char=? acc #\s) + (elstr-append + (elstr-deaccent root) + suffix + (elstr-deaccent flect))) + ((char=? acc #\-) + #f) + ((char-numeric? acc) + (let ((num (- (char->integer acc) (char->integer #\0)))) + (let ((obj (elstr-append + root suffix flect))) + (if (and augment (= (+ (elstr-number-of-syllables obj) 1) + num)) + (set! obj (elstr-append augment obj))) + (let ((nsyl (elstr-number-of-syllables obj))) + (elstr-set-accent! obj (cond + ((< num nsyl) num) + ((< nsyl 3) nsyl) + (else 3))) + obj)))) + (else + (error "invalid accent character" acc)))) + (conj-info #:flect conj) + accmap))) + (if (conj-info #:particle conj) + (map + (lambda (w) + (if w + (string-append + (conj-info #:particle conj) " " (force-string w)))) + forms) + (map force-string forms))))) + +(define (individual-verb verb voice mood tense) + (let ((res (my-sql-query + (dict-connect) + (string-append + "SELECT f.sing1,f.sing2,f.sing3,f.plur1,f.plur2,f.plur3 \ +FROM individual_verb i,verbflect f \ +WHERE i.verb='" verb "' AND i.voice='" voice "' AND i.mood='" mood +"' AND i.tense = '" tense "' AND i.ident=f.ident")))) + (if (not (null? res)) + (append (car res) + (list "I" + '(class root))) + #f))) + +(define (merge-conjugated-forms lista listb) + (map + (lambda (a b) + (or a b)) + lista listb)) + +(define (conjugate verb voice mood tense . rest) + (cond + ((individual-verb verb voice mood tense) => + (lambda (res) + (list res))) + (else + (map car + (let* ((vinfo (get-verb-info verb)) + (conj-list (get-conj-info (verb-info #:conj vinfo) voice mood + tense))) + (if (not conj-list) + (error "cannot obtain conjugation information for " + (verb-info #:conj vinfo) voice mood tense)) + (fold-right + (lambda (elt prev) +; (format #t "ELT ~A~%" elt) + (if (null? prev) + (list elt) + (let ((top (car prev))) + (if (let ((a (cdr elt)) + (b (cdr top))) + (and (string? a) (string? b) (string=? a b))) + (cons (cons + (merge-conjugated-forms (car top) (car elt)) + (cdr top)) + (cdr prev)) + (cons elt prev))))) + '() + (map + (lambda (conj) +; (format #t "CONJ ~S~%" conj) + (if (member #:nopart rest) + (conj-info-set! #:particle conj #f)) + (cons + (cond + ((string=? (conj-info #:thema conj) "synt") + (let* ((verb-conj + (car (conjugate verb voice "sub" "Αόριστος" #:nopart))) + (form (list-ref verb-conj 2)) + (part (conj-info #:particle conj))) + (cond + (form +; (format #t "FORM ~A FROM ~A~%" form verb-conj);;FIXME + (append + (map + (lambda (aux flag) + (if (char=? flag #\-) + #f + (elstr->string + (if part + (elstr-append part " " aux " " form) + (elstr-append aux " " form))))) + (conjugation:table + (car (conjugate (conj-info #:aux conj) "act" "ind" + (conj-info #:auxtense conj)))) + (string->list (or (verb-info #:accmap vinfo) + (conj-info #:accmap conj) + "000000"))) + (list (verb-info #:conj vinfo) + (conjugation:attested verb-conj)))) + (else + #f)))) + (else + (let ((thema (string-split (conj-info #:thema conj) #\:))) +; (format #t "THEMA ~A~%" thema) + (complement-verb-info vinfo verb + (if (null? (cdr thema)) + voice + (car (cdr thema))) + (car thema)) +; (format #t "VINFO ~A~%" vinfo) + (append (apply-flect conj vinfo verb) + (list (verb-info #:conj vinfo) + (verb-info #:attested vinfo)))))) + (conj-info #:fold conj))) + conj-list))))))) + +(define (conjugation:table conj) + (cond + ((not conj) + #f) + (else + (list-head conj 6)))) + + +(define (conjugation:class conj) + (cond + ((not conj) + #f) + (else + (list-ref conj 6)))) + +(define (conjugation:attested conj) + (cond + ((not conj) + #f) + (else (list-ref conj 7)))) + +(define (empty-conjugation? conj) + (or + (not conj) + (call-with-current-continuation + (lambda (return) + (for-each + (lambda (x) + (if x + (return #f))) + conj) + (return #t))))) + +;; +;(display (verb-info "βρίσκω")) +;(newline) +;(display (verb-info "ανοίγω")) +;(newline) + +(define transtab + '(("act" . "Ενεργητηκή φωνή") + ("pas" . "Μεσοπαθητική φωνή") + ("ind" . "Οριστική") + ("sub" . "Υποτακτική") + ("imp" . "Προστακτική"))) + +(define (term x) + (or (assoc-ref transtab x) x)) + +(define (test-conjugation verb voice mood tense) + (for-each + (lambda (result) + (format #t "~A ~A/~A/~A: " verb (term voice) (term mood) tense) + (let ((conj (conjugation:table result))) + (cond + ((empty-conjugation? conj) + (display "#f")) + (else + (let ((att (conjugation:attested result))) + (cond + ((not att) + (display "*")) + (else + (if (not (member 'class att)) + (display "*")) + (if (not (member 'root att)) + (display "!")))) + (display conj))))) + (newline)) + (conjugate verb voice mood tense)) + (gc)) + +(define (test-voice voice verb) + (for-each + (lambda (mood-tenses) + (let ((mood (car mood-tenses))) + (for-each + (lambda (tense) + (test-conjugation verb voice mood tense)) + (cdr mood-tenses)))) + ellinika-tense-list)) + +;(test-conjugation "διαβάζω" "act" "imp" "Αόριστος") +;; (test-conjugation "είμαι" "act" "ind" "Ενεστώτας") +;; (test-conjugation "είμαι" "act" "ind" "Παρατατίκος") +;; (test-conjugation "είμαι" "act" "ind" "Μέλλοντας διαρκείας") +;; (test-conjugation "είμαι" "act" "sub" "Ενεστώτας") +;; (test-conjugation "είμαι" "act" "imp" "Ενεστώτας") +;; (test-conjugation "είμαι" "act" "ind" "Αόριστος") + +;; (test-conjugation "έχω" "act" "ind" "Ενεστώτας") +(test-conjugation "έχω" "act" "ind" "Παρατατίκος") +;; (test-conjugation "έχω" "act" "ind" "Μέλλοντας διαρκείας") +;; (test-conjugation "έχω" "act" "sub" "Ενεστώτας") +;; (test-conjugation "έχω" "act" "imp" "Ενεστώτας") +;; (test-conjugation "έχω" "act" "imp" "Αόριστος") + +;; (test-conjugation "ανοίγω" "act" "ind" "Ενεστώτας") +;; (test-conjugation "ανοίγω" "act" "ind" "Αόριστος") +;; (test-conjugation "ανοίγω" "pas" "ind" "Αόριστος") +;; (test-conjugation "δένω" "act" "ind" "Αόριστος") +;; (test-conjugation "θέλω" "act" "ind" "Αόριστος") +;; (test-conjugation "θέλω" "act" "ind" "Παρατατικός") +;; (test-conjugation "βρίσκω" "act" "ind" "Ενεστώτας") +;; (test-conjugation "βρίσκω" "act" "ind" "Αόριστος") +;; (test-conjugation "βρίσκω" "act" "ind" "Μέλλοντας στιγμιαίος") +;; (test-conjugation "βρίσκω" "pas" "ind" "Αόριστος") +;; (test-conjugation "βρίσκω" "act" "sub" "Ενεστώτας") +;; (test-conjugation "βρίσκω" "act" "sub" "Αόριστος") +;; (test-conjugation "βρίσκω" "act" "ind" "Παρακείμενος") +;; (test-conjugation "βρίσκω" "act" "sub" "Παρακείμενος") +;; (test-conjugation "βρίσκω" "act" "imp" "Αόριστος") + +;; (test-conjugation "νικάω" "act" "ind" "Ενεστώτας") +;; (test-conjugation "νικάω" "act" "ind" "Αόριστος") +;; (test-conjugation "νικώ" "act" "ind" "Ενεστώτας") +;; (test-conjugation "νικώ" "act" "ind" "Αόριστος") +;; (test-conjugation "νικώ" "pas" "ind" "Αόριστος") +;; (test-conjugation "κρεμάω" "act" "ind" "Αόριστος") +;; (test-conjugation "κιτάω" "act" "ind" "Αόριστος") +;; (test-conjugation "τραβάω" "act" "ind" "Αόριστος") + +;; (test-conjugation "αγγέλω" "act" "ind" "Αόριστος") +;; (test-conjugation "αγγέλω" "act" "sub" "Αόριστος") +;; (test-conjugation "άγω" "act" "ind" "Αόριστος") +;; (test-conjugation "άγω" "act" "sub" "Αόριστος") +;; (test-conjugation "ανεβαίνω" "act" "ind" "Αόριστος") +;; (test-conjugation "ανεβαίνω" "act" "sub" "Αόριστος") +;; (test-conjugation "απονέμω" "act" "ind" "Αόριστος") +;; (test-conjugation "απονέμω" "act" "sub" "Αόριστος") +;; (test-conjugation "αρέσω" "act" "ind" "Αόριστος") +;; (test-conjugation "αρέσω" "act" "sub" "Αόριστος") +;; (test-conjugation "βάλλω" "act" "ind" "Αόριστος") +;; (test-conjugation "βάλλω" "act" "sub" "Αόριστος") +;; (test-conjugation "βγαίνω" "act" "ind" "Αόριστος") +;; (test-conjugation "βγαίνω" "act" "sub" "Αόριστος") +;; (test-conjugation "βλέπω" "act" "ind" "Αόριστος") +;; (test-conjugation "βλέπω" "act" "sub" "Αόριστος") +;; (test-conjugation "βλέπω" "act" "imp" "Αόριστος") +;; (test-conjugation "πηγαίνω" "act" "ind" "Μέλλοντας στιγμιαίος") +;; (test-conjugation "πίνω" "act" "ind" "Αόριστος") +;; (test-conjugation "πίνω" "act" "sub" "Αόριστος") +;; (test-conjugation "πίνω" "act" "imp" "Αόριστος") + +;(test-conjugation "έρχομαι" "pas" "ind" "Παρατατικός") +;(test-conjugation "έρχομαι" "pas" "ind" "Αόριστος") +;(test-conjugation "έρχομαι" "pas" "sub" "Αόριστος") +;; (test-conjugation "έρχομαι" "pas" "ind" "Συντελεσμένος Μέλλοντας") +;; (test-conjugation "έρχομαι" "act" "sub" "Αόριστος" ) +;; (test-conjugation "έρχομαι" "pas" "sub" "Αόριστος" ) +;; (test-conjugation "έρχομαι" "pas" "ind" "Ενεστώτας");FIXME! +;; (test-conjugation "έρχομαι" "pas" "ind" "Υπερσυντέλικος") + +;(test-voice "pas" "ντύνω") +(test-voice "pas" "έρχομαι") + +;(display (conjugate "ντύνω" "pas" "ind" "Ενεστώτας")) +;(newline) +;(display (conjugate "ντύνω" "pas" "imp" "Αόριστος")) +;(newline) +;(display (conjugate "ντύνω" "pas" "ind" "Συντελεσμένος Μέλλοντας")) +;(newline) +;(display (conjugate "τραβάω" "act" "ind" "Παρατατικός")) +;(newline) + +(newline) -- cgit v1.2.1