-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.cpp
141 lines (123 loc) · 4.73 KB
/
parser.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
#include "parser.h"
#include <vector>
#include <iostream>
std::shared_ptr<Object> Read(Tokenizer* tokenizer) {
if (tokenizer->IsEnd()) {
throw SyntaxError{"in Read: empty list"};
}
Token token;
token = tokenizer->GetToken();
tokenizer->Next();
if (QuoteToken* _ = std::get_if<QuoteToken>(&token)) {
if (tokenizer->IsEnd()) {
throw SyntaxError{"there should be something after quote"};
}
Token next_token = tokenizer->GetToken();
if (BracketToken* x = std::get_if<BracketToken>(&next_token)) {
if (*x != BracketToken::OPEN) {
throw SyntaxError{"there can not be ) after quote"};
}
tokenizer->Next();
auto list = ReadList(tokenizer);
if (!list) {
return std::make_shared<Cell>(std::make_shared<Symbol>("quote"), nullptr);
}
return std::make_shared<Cell>(std::make_shared<Symbol>("quote"),
std::make_shared<Cell>(list, nullptr));
} else {
return std::make_shared<Cell>(std::make_shared<Symbol>("quote"), Read(tokenizer));
}
} else if (ConstantToken* x = std::get_if<ConstantToken>(&token)) {
return std::make_shared<Number>(x->value);
} else if (BooleanToken* x = std::get_if<BooleanToken>(&token)) {
return std::make_shared<Boolean>(x->value);
} else if (SymbolToken* x = std::get_if<SymbolToken>(&token)) {
return std::make_shared<Symbol>(x->name);
} else if (BracketToken* x = std::get_if<BracketToken>(&token)) {
if (*x != BracketToken::OPEN) {
throw SyntaxError{"in Read: expected ("};
}
return ReadList(tokenizer);
}
throw SyntaxError{"in Read: bad pattern"};
}
std::shared_ptr<Object> ReadList(Tokenizer* tokenizer) {
std::vector<std::shared_ptr<Object>> list;
size_t number_of_dots = 0;
size_t dot_pos;
size_t curr_pos = 0;
while (true) {
if (tokenizer->IsEnd()) {
throw SyntaxError{"in ReadList: expected )"};
}
Token token = tokenizer->GetToken();
if (BracketToken* x = std::get_if<BracketToken>(&token)) {
if (*x == BracketToken::CLOSE) {
tokenizer->Next();
break;
}
}
if (DotToken* _ = std::get_if<DotToken>(&token)) {
number_of_dots += 1;
if (number_of_dots > 1) {
throw SyntaxError{"in ReadList: incorrect list"};
}
dot_pos = curr_pos;
curr_pos += 1;
tokenizer->Next();
list.emplace_back(nullptr);
continue;
}
list.emplace_back(Read(tokenizer));
curr_pos += 1;
}
size_t sz = list.size();
if (number_of_dots == 0) {
if (list.empty()) {
return nullptr;
}
std::shared_ptr<Object> cell = std::make_shared<Cell>(list[sz - 1], nullptr);
for (int i = sz - 2; i >= 0; --i) {
cell = std::make_shared<Cell>(list[i], cell);
}
if (auto symb = As<Symbol>(list.front())) {
if (symb->GetName() == "if" && !(sz == 3 || sz == 4)) {
throw SyntaxError{"if should have condition and 1 or 2 statements"};
}
if (symb->GetName() == "define" || symb->GetName() == "set!") {
if (sz == 4) {
if (!Is<Cell>(list[1])) {
throw SyntaxError{symb->GetName() +
" with more than 2 arguments should define lambda"};
}
return cell;
}
if (sz != 3) {
throw SyntaxError{symb->GetName() + " should have 2 arguments"};
}
}
if (symb->GetName() == "lambda") {
if (sz < 3) {
throw SyntaxError{symb->GetName() + " should have at least 2 arguments"};
}
}
}
return cell;
} else {
if (dot_pos + 2 != sz) {
throw SyntaxError{"in ReadList: incorrect improper list with dot_pos = " +
std::to_string(dot_pos) + " and sz = " + std::to_string(sz)};
}
if (sz < 3) {
throw SyntaxError{"in ReadList: incorrect improper list with dot_pos = " +
std::to_string(dot_pos) + " and sz = " + std::to_string(sz)};
}
std::shared_ptr<Object> cell = std::make_shared<Cell>(list[sz - 3], list[sz - 1]);
if (sz > 3) {
for (int i = sz - 4; i >= 0; --i) {
cell = std::make_shared<Cell>(list[i], cell);
}
}
return cell;
}
}