haskell_match 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +98 -0
- data/LICENSE-APACHE +202 -0
- data/LICENSE-MIT +21 -0
- data/README.md +1484 -0
- data/ext/haskell_match/Cargo.lock +33 -0
- data/ext/haskell_match/Cargo.toml +22 -0
- data/ext/haskell_match/extconf.rb +41 -0
- data/ext/haskell_match/src/core/ast.rs +190 -0
- data/ext/haskell_match/src/core/error.rs +52 -0
- data/ext/haskell_match/src/core/exhaust.rs +699 -0
- data/ext/haskell_match/src/core/hs/ast.rs +256 -0
- data/ext/haskell_match/src/core/hs/json.rs +225 -0
- data/ext/haskell_match/src/core/hs/layout.rs +346 -0
- data/ext/haskell_match/src/core/hs/lexer.rs +688 -0
- data/ext/haskell_match/src/core/hs/mod.rs +14 -0
- data/ext/haskell_match/src/core/hs/parser.rs +1945 -0
- data/ext/haskell_match/src/core/lexer.rs +590 -0
- data/ext/haskell_match/src/core/mod.rs +19 -0
- data/ext/haskell_match/src/core/parser.rs +1116 -0
- data/ext/haskell_match/src/core/pretty.rs +373 -0
- data/ext/haskell_match/src/core/resolve.rs +336 -0
- data/ext/haskell_match/src/core/tree.rs +921 -0
- data/ext/haskell_match/src/core/typecheck.rs +226 -0
- data/ext/haskell_match/src/core/types.rs +404 -0
- data/ext/haskell_match/src/lib.rs +19 -0
- data/ext/haskell_match/src/ruby/mod.rs +1195 -0
- data/ext/haskell_match/src/ruby/runtime.rs +1045 -0
- data/lib/haskell_match/binding_plan.rb +84 -0
- data/lib/haskell_match/case_of.rb +71 -0
- data/lib/haskell_match/clauses.rb +354 -0
- data/lib/haskell_match/data.rb +417 -0
- data/lib/haskell_match/deep_call.rb +98 -0
- data/lib/haskell_match/deriving.rb +130 -0
- data/lib/haskell_match/dsl.rb +71 -0
- data/lib/haskell_match/errors.rb +85 -0
- data/lib/haskell_match/field_types.rb +140 -0
- data/lib/haskell_match/function.rb +240 -0
- data/lib/haskell_match/haskell/compiler.rb +961 -0
- data/lib/haskell_match/haskell.rb +326 -0
- data/lib/haskell_match/inspect.rb +45 -0
- data/lib/haskell_match/lazy_list.rb +210 -0
- data/lib/haskell_match/native_loader.rb +64 -0
- data/lib/haskell_match/pattern.rb +75 -0
- data/lib/haskell_match/pattern_ast.rb +394 -0
- data/lib/haskell_match/prelude.rb +448 -0
- data/lib/haskell_match/scope.rb +44 -0
- data/lib/haskell_match/version.rb +5 -0
- data/lib/haskell_match.rb +41 -0
- metadata +124 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
//! AST of the Haskell subset, plus rendering of patterns back to text (the
|
|
2
|
+
//! Ruby code generator hands patterns to the pattern compiler as strings).
|
|
3
|
+
|
|
4
|
+
use crate::core::ast::{Lit, RawPat};
|
|
5
|
+
use crate::core::parser::DataDecl;
|
|
6
|
+
|
|
7
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
8
|
+
pub enum Literal {
|
|
9
|
+
Int(String),
|
|
10
|
+
Float(String),
|
|
11
|
+
Char(char),
|
|
12
|
+
Str(String),
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
16
|
+
pub enum Expr {
|
|
17
|
+
Var(String),
|
|
18
|
+
Con(String),
|
|
19
|
+
Lit(Literal),
|
|
20
|
+
App(Box<Expr>, Vec<Expr>),
|
|
21
|
+
BinOp(String, Box<Expr>, Box<Expr>),
|
|
22
|
+
Neg(Box<Expr>),
|
|
23
|
+
If(Box<Expr>, Box<Expr>, Box<Expr>),
|
|
24
|
+
Case(Box<Expr>, Vec<Alt>),
|
|
25
|
+
Let(Vec<Decl>, Box<Expr>),
|
|
26
|
+
Lambda(Vec<RawPat>, Box<Expr>),
|
|
27
|
+
List(Vec<Expr>),
|
|
28
|
+
Tuple(Vec<Expr>),
|
|
29
|
+
Range {
|
|
30
|
+
from: Box<Expr>,
|
|
31
|
+
then: Option<Box<Expr>>,
|
|
32
|
+
to: Option<Box<Expr>>,
|
|
33
|
+
},
|
|
34
|
+
Comp(Box<Expr>, Vec<Qual>),
|
|
35
|
+
/// `(e op)`
|
|
36
|
+
SectionL(String, Box<Expr>),
|
|
37
|
+
/// `(op e)`
|
|
38
|
+
SectionR(String, Box<Expr>),
|
|
39
|
+
/// `(op)`
|
|
40
|
+
OpFun(String),
|
|
41
|
+
/// MultiWayIf: `if | quals -> e | quals -> e`
|
|
42
|
+
MultiIf(Vec<(Vec<Qual>, Expr)>),
|
|
43
|
+
/// Record construction `Con { f = e, ... }`
|
|
44
|
+
RecCon(String, Vec<(String, Expr)>),
|
|
45
|
+
/// Record update `e { f = e, ... }`
|
|
46
|
+
RecUpdate(Box<Expr>, Vec<(String, Expr)>),
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
50
|
+
pub enum Qual {
|
|
51
|
+
Gen(RawPat, Expr),
|
|
52
|
+
Guard(Expr),
|
|
53
|
+
Let(Vec<Decl>),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// A guarded right-hand side: each alternative is a list of qualifiers (a
|
|
57
|
+
/// boolean guard, a pattern guard `p <- e`, or `let` bindings) and a body.
|
|
58
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
59
|
+
pub enum Rhs {
|
|
60
|
+
Plain(Expr),
|
|
61
|
+
Guarded(Vec<(Vec<Qual>, Expr)>),
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
65
|
+
pub struct Alt {
|
|
66
|
+
pub pat: RawPat,
|
|
67
|
+
pub rhs: Rhs,
|
|
68
|
+
pub wheres: Vec<Decl>,
|
|
69
|
+
pub line: usize,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
73
|
+
pub struct Equation {
|
|
74
|
+
pub name: String,
|
|
75
|
+
pub pats: Vec<RawPat>,
|
|
76
|
+
pub rhs: Rhs,
|
|
77
|
+
pub wheres: Vec<Decl>,
|
|
78
|
+
pub line: usize,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
82
|
+
pub enum Decl {
|
|
83
|
+
Data {
|
|
84
|
+
decl: DataDecl,
|
|
85
|
+
deriving: Vec<String>,
|
|
86
|
+
line: usize,
|
|
87
|
+
},
|
|
88
|
+
Sig {
|
|
89
|
+
names: Vec<String>,
|
|
90
|
+
arity: usize,
|
|
91
|
+
line: usize,
|
|
92
|
+
},
|
|
93
|
+
Fun(Vec<Equation>),
|
|
94
|
+
PatBind {
|
|
95
|
+
pat: RawPat,
|
|
96
|
+
rhs: Rhs,
|
|
97
|
+
wheres: Vec<Decl>,
|
|
98
|
+
line: usize,
|
|
99
|
+
},
|
|
100
|
+
/// `import [qualified] M [as A] [hiding] [(items)]`
|
|
101
|
+
Import {
|
|
102
|
+
module: String,
|
|
103
|
+
qualified: bool,
|
|
104
|
+
alias: Option<String>,
|
|
105
|
+
hiding: bool,
|
|
106
|
+
/// Named items (functions, operators, types); `None` imports everything.
|
|
107
|
+
items: Option<Vec<String>>,
|
|
108
|
+
line: usize,
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
#[derive(Clone, Debug, PartialEq)]
|
|
113
|
+
pub struct Module {
|
|
114
|
+
pub name: Option<String>,
|
|
115
|
+
/// Names in the export list (functions, operators, types); `None` when
|
|
116
|
+
/// there is no list, meaning everything is exported.
|
|
117
|
+
pub exports: Option<Vec<String>>,
|
|
118
|
+
pub decls: Vec<Decl>,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/// Mangle a Haskell identifier into a name that is a valid Haskell *and* Ruby
|
|
122
|
+
/// identifier and cannot clash with Ruby keywords or methods: `x'` → `hs_x_q`.
|
|
123
|
+
pub fn mangle(name: &str) -> String {
|
|
124
|
+
let mut s = String::from("hs_");
|
|
125
|
+
for c in name.chars() {
|
|
126
|
+
if c == '\'' {
|
|
127
|
+
s.push_str("_q");
|
|
128
|
+
} else {
|
|
129
|
+
s.push(c);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
s
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/// Render a pattern as Haskell text with variables mangled, for the pattern
|
|
136
|
+
/// compiler.
|
|
137
|
+
pub fn render_pat(p: &RawPat) -> String {
|
|
138
|
+
render(p, false)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
fn render(p: &RawPat, atomic: bool) -> String {
|
|
142
|
+
match p {
|
|
143
|
+
RawPat::Wild => "_".into(),
|
|
144
|
+
RawPat::Var(v) => mangle(v),
|
|
145
|
+
RawPat::As(v, inner) => format!("{}@{}", mangle(v), render(inner, true)),
|
|
146
|
+
RawPat::Lazy(inner) => format!("~{}", render(inner, true)),
|
|
147
|
+
RawPat::Bang(inner) => format!("!{}", render(inner, true)),
|
|
148
|
+
RawPat::Lit(l) => render_lit(l, atomic),
|
|
149
|
+
RawPat::Tuple(items) => format!(
|
|
150
|
+
"({})",
|
|
151
|
+
items
|
|
152
|
+
.iter()
|
|
153
|
+
.map(|i| render(i, false))
|
|
154
|
+
.collect::<Vec<_>>()
|
|
155
|
+
.join(", ")
|
|
156
|
+
),
|
|
157
|
+
RawPat::List(items) => format!(
|
|
158
|
+
"[{}]",
|
|
159
|
+
items
|
|
160
|
+
.iter()
|
|
161
|
+
.map(|i| render(i, false))
|
|
162
|
+
.collect::<Vec<_>>()
|
|
163
|
+
.join(", ")
|
|
164
|
+
),
|
|
165
|
+
RawPat::Cons(h, t) => format!("({}:{})", render(h, true), render(t, true)),
|
|
166
|
+
RawPat::Hash(fields) => format!(
|
|
167
|
+
"{{{}}}",
|
|
168
|
+
fields
|
|
169
|
+
.iter()
|
|
170
|
+
.map(|(k, p)| format!("{} = {}", k, render(p, false)))
|
|
171
|
+
.collect::<Vec<_>>()
|
|
172
|
+
.join(", ")
|
|
173
|
+
),
|
|
174
|
+
RawPat::Con(name, args) if name.starts_with(':') => {
|
|
175
|
+
if args.len() == 2 {
|
|
176
|
+
format!(
|
|
177
|
+
"({} {} {})",
|
|
178
|
+
render(&args[0], true),
|
|
179
|
+
name,
|
|
180
|
+
render(&args[1], true)
|
|
181
|
+
)
|
|
182
|
+
} else if args.is_empty() {
|
|
183
|
+
format!("({})", name)
|
|
184
|
+
} else {
|
|
185
|
+
format!(
|
|
186
|
+
"(({}) {})",
|
|
187
|
+
name,
|
|
188
|
+
args.iter()
|
|
189
|
+
.map(|a| render(a, true))
|
|
190
|
+
.collect::<Vec<_>>()
|
|
191
|
+
.join(" ")
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
RawPat::Con(name, args) => {
|
|
196
|
+
if args.is_empty() {
|
|
197
|
+
name.clone()
|
|
198
|
+
} else {
|
|
199
|
+
let s = format!(
|
|
200
|
+
"{} {}",
|
|
201
|
+
name,
|
|
202
|
+
args.iter()
|
|
203
|
+
.map(|a| render(a, true))
|
|
204
|
+
.collect::<Vec<_>>()
|
|
205
|
+
.join(" ")
|
|
206
|
+
);
|
|
207
|
+
if atomic {
|
|
208
|
+
format!("({})", s)
|
|
209
|
+
} else {
|
|
210
|
+
s
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
RawPat::Record(name, fields, rest) => {
|
|
215
|
+
let mut parts: Vec<String> = fields
|
|
216
|
+
.iter()
|
|
217
|
+
.map(|(f, p)| format!("{} = {}", f, render(p, false)))
|
|
218
|
+
.collect();
|
|
219
|
+
if *rest {
|
|
220
|
+
parts.push("..".into());
|
|
221
|
+
}
|
|
222
|
+
format!("{} {{{}}}", name, parts.join(", "))
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
fn render_lit(l: &Lit, atomic: bool) -> String {
|
|
228
|
+
let s = l.to_string();
|
|
229
|
+
let negative = s.starts_with('-');
|
|
230
|
+
if negative && atomic {
|
|
231
|
+
format!("({})", s)
|
|
232
|
+
} else {
|
|
233
|
+
s
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/// Variables bound by a pattern, in order of appearance (unmangled).
|
|
238
|
+
pub fn pat_vars(p: &RawPat, out: &mut Vec<String>) {
|
|
239
|
+
match p {
|
|
240
|
+
RawPat::Wild | RawPat::Lit(_) => {}
|
|
241
|
+
RawPat::Var(v) => out.push(v.clone()),
|
|
242
|
+
RawPat::As(v, inner) => {
|
|
243
|
+
out.push(v.clone());
|
|
244
|
+
pat_vars(inner, out);
|
|
245
|
+
}
|
|
246
|
+
RawPat::Lazy(inner) | RawPat::Bang(inner) => pat_vars(inner, out),
|
|
247
|
+
RawPat::Tuple(items) | RawPat::List(items) => items.iter().for_each(|i| pat_vars(i, out)),
|
|
248
|
+
RawPat::Cons(h, t) => {
|
|
249
|
+
pat_vars(h, out);
|
|
250
|
+
pat_vars(t, out);
|
|
251
|
+
}
|
|
252
|
+
RawPat::Con(_, args) => args.iter().for_each(|a| pat_vars(a, out)),
|
|
253
|
+
RawPat::Record(_, fields, _) => fields.iter().for_each(|(_, p)| pat_vars(p, out)),
|
|
254
|
+
RawPat::Hash(fields) => fields.iter().for_each(|(_, p)| pat_vars(p, out)),
|
|
255
|
+
}
|
|
256
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
//! JSON serialisation of the AST for the Ruby code generator.
|
|
2
|
+
|
|
3
|
+
use super::ast::*;
|
|
4
|
+
use crate::core::ast::RawPat;
|
|
5
|
+
|
|
6
|
+
fn esc(s: &str) -> String {
|
|
7
|
+
let mut out = String::with_capacity(s.len() + 2);
|
|
8
|
+
out.push('"');
|
|
9
|
+
for c in s.chars() {
|
|
10
|
+
match c {
|
|
11
|
+
'"' => out.push_str("\\\""),
|
|
12
|
+
'\\' => out.push_str("\\\\"),
|
|
13
|
+
'\n' => out.push_str("\\n"),
|
|
14
|
+
'\r' => out.push_str("\\r"),
|
|
15
|
+
'\t' => out.push_str("\\t"),
|
|
16
|
+
c if (c as u32) < 0x20 => out.push_str(&format!("\\u{:04x}", c as u32)),
|
|
17
|
+
c => out.push(c),
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
out.push('"');
|
|
21
|
+
out
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
fn arr(items: Vec<String>) -> String {
|
|
25
|
+
format!("[{}]", items.join(","))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
fn pat(p: &RawPat) -> String {
|
|
29
|
+
let mut vars = Vec::new();
|
|
30
|
+
pat_vars(p, &mut vars);
|
|
31
|
+
format!(
|
|
32
|
+
"{{\"text\":{},\"vars\":{}}}",
|
|
33
|
+
esc(&render_pat(p)),
|
|
34
|
+
arr(vars.iter().map(|v| esc(v)).collect())
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
fn literal(l: &Literal) -> String {
|
|
39
|
+
match l {
|
|
40
|
+
Literal::Int(s) => format!("[\"int\",{}]", esc(s)),
|
|
41
|
+
Literal::Float(s) => format!("[\"float\",{}]", esc(s)),
|
|
42
|
+
Literal::Char(c) => format!("[\"char\",{}]", esc(&c.to_string())),
|
|
43
|
+
Literal::Str(s) => format!("[\"str\",{}]", esc(s)),
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn expr(e: &Expr) -> String {
|
|
48
|
+
match e {
|
|
49
|
+
Expr::Var(v) => format!("[\"var\",{}]", esc(v)),
|
|
50
|
+
Expr::RecCon(c, fields) => format!(
|
|
51
|
+
"[\"reccon\",{},{}]",
|
|
52
|
+
esc(c),
|
|
53
|
+
arr(fields.iter().map(field_bind).collect())
|
|
54
|
+
),
|
|
55
|
+
Expr::RecUpdate(e, fields) => format!(
|
|
56
|
+
"[\"recupd\",{},{}]",
|
|
57
|
+
expr(e),
|
|
58
|
+
arr(fields.iter().map(field_bind).collect())
|
|
59
|
+
),
|
|
60
|
+
Expr::Con(c) => format!("[\"con\",{}]", esc(c)),
|
|
61
|
+
Expr::Lit(l) => format!("[\"lit\",{}]", literal(l)),
|
|
62
|
+
Expr::App(f, args) => format!(
|
|
63
|
+
"[\"app\",{},{}]",
|
|
64
|
+
expr(f),
|
|
65
|
+
arr(args.iter().map(expr).collect())
|
|
66
|
+
),
|
|
67
|
+
Expr::BinOp(op, l, r) => format!("[\"op\",{},{},{}]", esc(op), expr(l), expr(r)),
|
|
68
|
+
Expr::Neg(x) => format!("[\"neg\",{}]", expr(x)),
|
|
69
|
+
Expr::If(c, t, f) => format!("[\"if\",{},{},{}]", expr(c), expr(t), expr(f)),
|
|
70
|
+
Expr::Case(s, alts) => format!(
|
|
71
|
+
"[\"case\",{},{}]",
|
|
72
|
+
expr(s),
|
|
73
|
+
arr(alts.iter().map(alt).collect())
|
|
74
|
+
),
|
|
75
|
+
Expr::Let(decls, body) => format!(
|
|
76
|
+
"[\"let\",{},{}]",
|
|
77
|
+
arr(decls.iter().map(decl).collect()),
|
|
78
|
+
expr(body)
|
|
79
|
+
),
|
|
80
|
+
Expr::Lambda(pats, body) => format!(
|
|
81
|
+
"[\"lam\",{},{}]",
|
|
82
|
+
arr(pats.iter().map(pat).collect()),
|
|
83
|
+
expr(body)
|
|
84
|
+
),
|
|
85
|
+
Expr::List(items) => format!("[\"list\",{}]", arr(items.iter().map(expr).collect())),
|
|
86
|
+
Expr::Tuple(items) => format!("[\"tuple\",{}]", arr(items.iter().map(expr).collect())),
|
|
87
|
+
Expr::Range { from, then, to } => format!(
|
|
88
|
+
"[\"range\",{},{},{}]",
|
|
89
|
+
expr(from),
|
|
90
|
+
then.as_ref()
|
|
91
|
+
.map(|t| expr(t))
|
|
92
|
+
.unwrap_or_else(|| "null".into()),
|
|
93
|
+
to.as_ref()
|
|
94
|
+
.map(|t| expr(t))
|
|
95
|
+
.unwrap_or_else(|| "null".into())
|
|
96
|
+
),
|
|
97
|
+
Expr::Comp(body, quals) => format!(
|
|
98
|
+
"[\"comp\",{},{}]",
|
|
99
|
+
expr(body),
|
|
100
|
+
arr(quals.iter().map(qual).collect())
|
|
101
|
+
),
|
|
102
|
+
Expr::SectionL(op, x) => format!("[\"section_l\",{},{}]", esc(op), expr(x)),
|
|
103
|
+
Expr::SectionR(op, x) => format!("[\"section_r\",{},{}]", esc(op), expr(x)),
|
|
104
|
+
Expr::OpFun(op) => format!("[\"opfun\",{}]", esc(op)),
|
|
105
|
+
Expr::MultiIf(arms) => format!(
|
|
106
|
+
"[\"multiif\",{}]",
|
|
107
|
+
arr(arms.iter().map(guarded_arm).collect())
|
|
108
|
+
),
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fn field_bind((f, e): &(String, Expr)) -> String {
|
|
113
|
+
format!("[{},{}]", esc(f), expr(e))
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fn guarded_arm((quals, e): &(Vec<Qual>, Expr)) -> String {
|
|
117
|
+
format!("[{},{}]", arr(quals.iter().map(qual).collect()), expr(e))
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fn qual(q: &Qual) -> String {
|
|
121
|
+
match q {
|
|
122
|
+
Qual::Gen(p, e) => format!("[\"gen\",{},{}]", pat(p), expr(e)),
|
|
123
|
+
Qual::Guard(e) => format!("[\"guard\",{}]", expr(e)),
|
|
124
|
+
Qual::Let(ds) => format!("[\"let\",{}]", arr(ds.iter().map(decl).collect())),
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
fn rhs(r: &Rhs) -> String {
|
|
129
|
+
match r {
|
|
130
|
+
Rhs::Plain(e) => format!("{{\"body\":{}}}", expr(e)),
|
|
131
|
+
Rhs::Guarded(gs) => format!(
|
|
132
|
+
"{{\"guards\":{}}}",
|
|
133
|
+
arr(gs.iter().map(guarded_arm).collect())
|
|
134
|
+
),
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
fn alt(a: &Alt) -> String {
|
|
139
|
+
format!(
|
|
140
|
+
"{{\"pat\":{},\"rhs\":{},\"where\":{},\"line\":{}}}",
|
|
141
|
+
pat(&a.pat),
|
|
142
|
+
rhs(&a.rhs),
|
|
143
|
+
arr(a.wheres.iter().map(decl).collect()),
|
|
144
|
+
a.line
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
fn equation(e: &Equation) -> String {
|
|
149
|
+
format!(
|
|
150
|
+
"{{\"pats\":{},\"rhs\":{},\"where\":{},\"line\":{}}}",
|
|
151
|
+
arr(e.pats.iter().map(pat).collect()),
|
|
152
|
+
rhs(&e.rhs),
|
|
153
|
+
arr(e.wheres.iter().map(decl).collect()),
|
|
154
|
+
e.line
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
pub fn decl(d: &Decl) -> String {
|
|
159
|
+
match d {
|
|
160
|
+
Decl::Data { decl, deriving, line } => format!(
|
|
161
|
+
"{{\"kind\":\"data\",\"name\":{},\"tyvars\":{},\"cons\":{},\"deriving\":{},\"line\":{}}}",
|
|
162
|
+
esc(&decl.name),
|
|
163
|
+
arr(decl.tyvars.iter().map(|v| esc(v)).collect()),
|
|
164
|
+
arr(decl
|
|
165
|
+
.cons
|
|
166
|
+
.iter()
|
|
167
|
+
.map(|c| format!(
|
|
168
|
+
"{{\"name\":{},\"arity\":{},\"fields\":{}}}",
|
|
169
|
+
esc(&c.name),
|
|
170
|
+
c.arity,
|
|
171
|
+
c.fields.as_ref().map(|fs| arr(fs.iter().map(|f| esc(f)).collect())).unwrap_or_else(|| "null".into())
|
|
172
|
+
))
|
|
173
|
+
.collect()),
|
|
174
|
+
arr(deriving.iter().map(|v| esc(v)).collect()),
|
|
175
|
+
line
|
|
176
|
+
),
|
|
177
|
+
Decl::Sig { names, arity, line } => format!(
|
|
178
|
+
"{{\"kind\":\"sig\",\"names\":{},\"arity\":{},\"line\":{}}}",
|
|
179
|
+
arr(names.iter().map(|v| esc(v)).collect()),
|
|
180
|
+
arity,
|
|
181
|
+
line
|
|
182
|
+
),
|
|
183
|
+
Decl::Fun(eqs) => format!(
|
|
184
|
+
"{{\"kind\":\"fun\",\"name\":{},\"arity\":{},\"equations\":{},\"line\":{}}}",
|
|
185
|
+
esc(&eqs[0].name),
|
|
186
|
+
eqs[0].pats.len(),
|
|
187
|
+
arr(eqs.iter().map(equation).collect()),
|
|
188
|
+
eqs[0].line
|
|
189
|
+
),
|
|
190
|
+
Decl::PatBind { pat: p, rhs: r, wheres, line } => format!(
|
|
191
|
+
"{{\"kind\":\"bind\",\"pat\":{},\"rhs\":{},\"where\":{},\"line\":{}}}",
|
|
192
|
+
pat(p),
|
|
193
|
+
rhs(r),
|
|
194
|
+
arr(wheres.iter().map(decl).collect()),
|
|
195
|
+
line
|
|
196
|
+
),
|
|
197
|
+
Decl::Import { module, qualified, alias, hiding, items, line } => format!(
|
|
198
|
+
"{{\"kind\":\"import\",\"module\":{},\"qualified\":{},\"as\":{},\"hiding\":{},\"items\":{},\"line\":{}}}",
|
|
199
|
+
esc(module),
|
|
200
|
+
qualified,
|
|
201
|
+
alias.as_ref().map(|a| esc(a)).unwrap_or_else(|| "null".into()),
|
|
202
|
+
hiding,
|
|
203
|
+
items
|
|
204
|
+
.as_ref()
|
|
205
|
+
.map(|is| arr(is.iter().map(|i| esc(i)).collect()))
|
|
206
|
+
.unwrap_or_else(|| "null".into()),
|
|
207
|
+
line
|
|
208
|
+
),
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
pub fn module(m: &Module) -> String {
|
|
213
|
+
format!(
|
|
214
|
+
"{{\"name\":{},\"exports\":{},\"decls\":{}}}",
|
|
215
|
+
m.name
|
|
216
|
+
.as_ref()
|
|
217
|
+
.map(|n| esc(n))
|
|
218
|
+
.unwrap_or_else(|| "null".into()),
|
|
219
|
+
m.exports
|
|
220
|
+
.as_ref()
|
|
221
|
+
.map(|es| arr(es.iter().map(|e| esc(e)).collect()))
|
|
222
|
+
.unwrap_or_else(|| "null".into()),
|
|
223
|
+
arr(m.decls.iter().map(decl).collect())
|
|
224
|
+
)
|
|
225
|
+
}
|