@@ -0,0 +1,115 @@
1+let String = { mempty = ""; mappend = a: b: a + b; };
2+ List = { singleton = x: [x]; };
3+ pair = a: b: { _1 = a; _2 = b; };
4+ Pair = { pure = s: pair String.mempty s;
5+ mappend = a: b: pair (String.mappend a._1 b._1) b._2;
6+ map = f: p: pair (f p._1) p._2;
7+ };
8+ compose = f: g: x: f (g x);
9+in with builtins; rec {
10+ # Parser a = String -> [(a, String)]
11+ string = str: s:
12+ let strL = stringLength str;
13+ sL = stringLength s;
14+ in if str == substring 0 strL s
15+ then [ (pair str (substring strL sL s)) ]
16+ else [];
17+
18+ regex = capture_groups: re: s:
19+ let result = match "(${re})(.*)" s;
20+ in if result == null
21+ then []
22+ else [ (pair (elemAt result 0) (elemAt result (1 + capture_groups))) ];
23+
24+ # Left-biased choice
25+ choice = cs: s:
26+ if cs == []
27+ then []
28+ else let c = head cs;
29+ cs' = tail cs;
30+ result = c s;
31+ in if result == []
32+ then choice cs' s
33+ else result;
34+
35+ optional = p: s:
36+ let result = p s;
37+ in if result == []
38+ then [ (Pair.pure s) ]
39+ else result;
40+
41+ chain = ps: s:
42+ if ps == []
43+ then [ (Pair.pure s) ]
44+ else let p = head ps;
45+ ps' = tail ps;
46+ result = p s;
47+ in if result == []
48+ then []
49+ else let r = head result;
50+ rest = chain ps' r._2;
51+ in if rest == []
52+ then []
53+ else let r' = head rest;
54+ in [ (Pair.mappend r r') ];
55+
56+ idstring = regex 0 "[-\.0-9a-zA-Z]+";
57+
58+ license-ref = let documentref = chain [ (string "DocumentRef-")
59+ idstring
60+ (string ":")
61+ ];
62+ in chain [
63+ (optional documentref)
64+ (string "LicenseRef-")
65+ idstring
66+ ];
67+
68+ simple-expression = choice [ license-ref
69+ (chain [ idstring (string "+") ])
70+ idstring
71+ ];
72+
73+ compound-expression = let wrap = compose (map (Pair.map List.singleton));
74+ in choice [
75+ (s: let result = simple-expression s;
76+ in if result == []
77+ then []
78+ else let r = head result;
79+ rest = chain [(string " WITH ") idstring ] r._2;
80+ in if rest == []
81+ then []
82+ else [(pair r._1 (head rest)._2)]
83+ )
84+ (s: let result = simple-expression s;
85+ in if result == []
86+ then []
87+ else let r = head result;
88+ firstLicense = r._1;
89+ operator = choice [ (string " AND ")
90+ (string " OR ")
91+ ]
92+ r._2;
93+ in if operator == []
94+ then []
95+ else let s' = (head operator)._2;
96+ licenses = compound-expression s';
97+ in if licenses == []
98+ then []
99+ else let ls = head licenses;
100+ in [(pair ([firstLicense] ++ ls._1) ls._2)]
101+ )
102+ (wrap simple-expression)
103+ (s: let openParen = string "(" s;
104+ in if openParen == []
105+ then []
106+ else let result = compound-expression (head openParen)._2;
107+ in if result == []
108+ then []
109+ else let r = head result;
110+ closeParen = string ")" r._2;
111+ in if closeParen == []
112+ then []
113+ else [(pair r._1 (head closeParen)._2)])
114+ ];
115+}