-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsexpr.cpp
187 lines (137 loc) · 5.13 KB
/
sexpr.cpp
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include "sexpr.hpp"
#include "parse.hpp"
#include <algorithm>
template<char ... c>
static int matches(int x) {
static const char data[] = {c..., 0};
for(const char* i = data; *i; ++i) {
if(*i == x) return true;
}
return false;
}
const char selection_prefix = '.';
const char injection_prefix = '|';
template<class T>
static const std::ios::pos_type try_parse(std::istream& in) {
const parser::stream_state backup(in);
T t;
in >> t;
return parser::stream_state(in).pos;
}
maybe<sexpr> sexpr::parse(std::istream& in) {
using namespace parser;
static const auto separator_parser = // parser::debug("sep") |=
noskip(chr<std::isspace>());
static const auto integer_parser = // parser::debug("real") |=
value<integer>();
static const auto real_parser = // parser::debug("real") |=
value<double>();
static const auto semicolon = chr<matches<';'>>();
static const auto endl = chr<matches<'\n'>>();
static const auto comment_parser = debug("comment") |=
semicolon >> then(noskip(*!endl >> then(endl)));
static const auto skip_parser = debug("skip") |=
+comment_parser;
static const auto as_expr = parser::cast<sexpr>();
static const auto number_parser = [](std::istream& in) {
const auto pr = try_parse<real>(in);
const auto pi = try_parse<integer>(in);
if(pr == pi) return (integer_parser >> as_expr)(in);
return (real_parser >> as_expr)(in);
};
static const auto initial_parser = chr<std::isalpha>() | chr<matches<'_'>>();
static const auto rest_parser = chr<std::isalnum>() | chr<matches<'-', '_'>>();
static const auto op_parser =
(token("!=") | token("<=") | token(">=") | token("->") | token("=>")
| token(">>=") )
>> [](const char* s) {
return pure(symbol(s));
} | chr<matches<'+', '-', '*', '/', '=', '<', '>', '%' >>() >> [](char c) {
return pure(symbol(std::string(1, c)));
};
static const auto identifier_parser = initial_parser >> [](char c) {
return noskip(*rest_parser >> [c](std::deque<char>&& rest) {
const std::string tmp = c + std::string(rest.begin(), rest.end());
return pure(symbol(tmp));
});
};
static const auto symbol_parser = identifier_parser | op_parser;
static const auto qualified_parser =
(symbol_parser % chr<matches<selection_prefix>>()) >>
[](std::deque<symbol> parts) {
sexpr res = parts.front();
parts.pop_front();
for(symbol s : parts) {
res = symbol(std::string(1, selection_prefix) + s.get())
>>= res >>= sexpr::list();
}
return pure(res);
};
static const auto selection_parser =
chr<matches<selection_prefix>>() >> [](char c) {
return symbol_parser >> [c](symbol s) {
return pure(symbol(c + std::string(s.get())));
};
};
static const auto injection_parser =
chr<matches<injection_prefix>>() >> [](char c) {
return symbol_parser >> [c](symbol s) {
return pure(symbol(c + std::string(s.get())));
};
};
static const auto backslash = chr<matches<'\\'>>();
static const auto quote = chr<matches<'"'>>();
static const auto escaped =
noskip(backslash >> then(chr<matches<'\\', 'n', '"', 't'>>() >> [](char c) {
switch(c) {
case 'n': return pure('\n');
case 't': return pure('\t');
case '"': return pure('"');
case '\\': return pure('\\');
default: return pure(char(0));
}
}));
static const auto string_parser =
quote >> then(noskip( *(escaped | !quote) >>
[](std::deque<char> data) {
return pure(string(data.begin(), data.end()));
}
>> drop(quote)));
static auto expr_parser = any<sexpr>();
static const auto lparen = // debug("lparen") |=
token("(");
static const auto rparen = // debug("rparen") |=
skip(skip_parser, token(")"));
static const auto exprs_parser = // debug("exprs") |=
parser::ref(expr_parser) % separator_parser;
static const auto list_parser = // debug("list") |=
lparen >>= (exprs_parser | pure<std::deque<sexpr>>()) >> drop(rparen)
>> [](std::deque<sexpr>&& es) {
return pure(make_list(es.begin(), es.end()));
};
static const auto once =
(expr_parser =
skip(skip_parser,
debug("expr") |=
(qualified_parser >> as_expr)
| (selection_parser >> as_expr)
| (injection_parser >> as_expr)
| (op_parser >> as_expr)
| (string_parser >> as_expr)
| number_parser
| (list_parser >> as_expr))
, 0); (void) once;
// debug::stream = &std::clog;
return expr_parser(in);
}
void sexpr::iter(std::istream& in, std::function<void(sexpr)> cont) {
using namespace parser;
using exprs_type = std::deque<sexpr>;
static const auto program_parser = debug("prog") |=
kleene(parse) >> drop(debug("eof") |= eof())
| parser::error<exprs_type>("parse error");
(program_parser >> [cont](exprs_type es) {
std::for_each(es.begin(), es.end(), cont);
return pure(unit());
})(in);
}