-
Notifications
You must be signed in to change notification settings - Fork 19
/
parser.cljc
80 lines (69 loc) · 2.54 KB
/
parser.cljc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
(ns naga.lang.parser
"Parser for Pabu, which is a Prolog-like syntax for Naga."
(:require [clojure.string :as string]
#?(:clj [the.parsatron :refer [defparser let->> >> always between many attempt ch string run]]
:cljs [the.parsatron :refer [always between many attempt ch string run]
:refer-macros [defparser let->> >>]])
[naga.lang.basic :refer
[whitespace-char opt-whitespace separator open-paren close-paren
get-vars arg-list elt
choice* either*]]
[naga.lang.expression :refer [fn-symbol relation expression]]))
(defn vars-for
"Returns the vars of an expression"
[x]
(if (sequential? x)
(get-vars x)
(if (symbol? x) [x])))
(defparser relational-expr []
(let->> [lhs expression
c-type (>> opt-whitespace relation)
rhs (>> opt-whitespace expression)]
(let [vars (-> #{}
(into (vars-for lhs))
(into (vars-for rhs)))
expr (with-meta
(list (fn-symbol c-type) lhs rhs)
{:vars vars})]
(always expr))))
;; a structure is a predicate with arguments, like foo(bar)
(defparser structure []
(let->> [p (elt)
args (between open-paren close-paren (arg-list))]
(always [p args])))
;; a list of predicates or expressions
(defparser structures []
(let->> [s (structure)
ss (many
(attempt
(>> separator
(either*
(relational-expr)
(structure)))))]
(always (cons s ss))))
;; a clause with a rule
(defparser nonbase-clause []
(let->> [head (>> opt-whitespace (structures))
_ (>> opt-whitespace (string ":-") opt-whitespace)
body (structures)
_ (>> opt-whitespace (ch \.) opt-whitespace)]
(always {:type :rule
:head head
:body body})))
;; an axiom
(defparser base-clause []
(let->> [structure (>> opt-whitespace (structure))
_ (>> opt-whitespace (ch \.) opt-whitespace)]
(always {:type :axiom
:axiom structure})))
(def program (many (either* (nonbase-clause) (base-clause))))
(def dblquotes (apply str (map clojure.core/char [733 8220 8221 8223 8243 10077 10078])))
(def dblquote-pattern (re-pattern (str "[" dblquotes "]")))
(defn clean-quotes
"Convert smart quotes into standard ascii character 34"
[s]
(string/replace s dblquote-pattern "\""))
(defn parse
"Parse a string"
[s]
(run program (clean-quotes s)))