-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalue.hpp
More file actions
229 lines (196 loc) · 6.99 KB
/
Copy pathvalue.hpp
File metadata and controls
229 lines (196 loc) · 6.99 KB
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
// Çalışma zamanı değer temsili.
//
// Burada AST'nin aksine std::variant DOĞRU araç: alternatifler az, özyineleme
// shared_ptr ile kırılıyor ve tip üzerinde switch yapmak (std::visit) tam olarak
// yorumlayıcının ihtiyacı. AST'de 36 alternatif vardı, burada 12.
//
// Bellek: Faz 1'de shared_ptr. Çöp toplayıcı Faz 3'te gelecek — döngüsel
// referanslar (a.b = a) şimdilik sızdırır, bilinen ve kabul edilen sınırlama.
#pragma once
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <variant>
#include <vector>
#include "ast.hpp"
namespace rs {
struct Nil {
bool operator==(const Nil&) const noexcept { return true; }
};
struct ListObj;
struct MapObj;
struct FnObj;
struct NativeObj;
struct ClassObj;
struct InstanceObj;
struct BoundObj;
using Str = std::shared_ptr<const std::string>; // string değişmez (SPEC §2)
using Value = std::variant<Nil,
bool,
std::int64_t,
double,
Str,
std::shared_ptr<ListObj>,
std::shared_ptr<MapObj>,
std::shared_ptr<FnObj>,
std::shared_ptr<NativeObj>,
std::shared_ptr<ClassObj>,
std::shared_ptr<InstanceObj>,
std::shared_ptr<BoundObj>>;
struct ListObj {
std::vector<Value> items;
};
// Ekleme sırasını korur — 'for k, v in harita.items()' öngörülebilir olsun diye.
// Arama doğrusal; Faz 3'te hash tablosuna geçilecek.
struct MapObj {
std::vector<std::pair<Value, Value>> entries;
};
class Environment;
struct FnObj {
std::string name = "<anonim>";
const std::vector<Param>* params = nullptr;
const Stmt* body = nullptr; // blok gövde
const Expr* bodyExpr = nullptr; // '(x) => x*2' tek ifade gövdesi
std::shared_ptr<Environment> closure;
bool isMethod = false;
std::shared_ptr<ClassObj> owner; // 'super' çözümü için
};
// std::function, ham işaretçi değil: yerleşik metotların alıcıyı ('merhaba'.upper()
// içindeki string'i) ve yorumlayıcıyı yakalaması gerekiyor.
using NativeFn = std::function<Value(std::vector<Value>&)>;
struct NativeObj {
std::string name;
int arityMin = 0;
int arityMax = -1; // -1 = sınırsız
NativeFn fn;
};
struct ClassObj {
std::string name;
std::shared_ptr<ClassObj> base;
std::unordered_map<std::string, std::shared_ptr<FnObj>> methods;
const ClassDecl* decl = nullptr;
std::shared_ptr<Environment> closure;
[[nodiscard]] std::shared_ptr<FnObj> findMethod(const std::string& ad) const {
const ClassObj* c = this;
while (c != nullptr) {
const auto it = c->methods.find(ad);
if (it != c->methods.end()) {
return it->second;
}
c = c->base.get();
}
return nullptr;
}
[[nodiscard]] bool isSubclassOf(const ClassObj* other) const {
const ClassObj* c = this;
while (c != nullptr) {
if (c == other) {
return true;
}
c = c->base.get();
}
return false;
}
};
struct InstanceObj {
std::shared_ptr<ClassObj> cls;
std::vector<std::pair<std::string, Value>> fields; // sıra korunur
[[nodiscard]] Value* find(const std::string& ad) {
for (auto& [k, v] : fields) {
if (k == ad) {
return &v;
}
}
return nullptr;
}
void set(const std::string& ad, Value v) {
if (auto* p = find(ad)) {
*p = std::move(v);
return;
}
fields.emplace_back(ad, std::move(v));
}
};
// 'gemi.ateş' — metot, ait olduğu örnekle bağlanmış hâlde taşınabilir.
struct BoundObj {
Value self;
std::shared_ptr<FnObj> fn;
};
// --- kapsam ---
class Environment : public std::enable_shared_from_this<Environment> {
public:
explicit Environment(std::shared_ptr<Environment> parent = nullptr)
: parent_(std::move(parent)) {}
void define(const std::string& ad, Value v) { vars_[ad] = std::move(v); }
[[nodiscard]] Value* find(const std::string& ad) {
Environment* e = this;
while (e != nullptr) {
const auto it = e->vars_.find(ad);
if (it != e->vars_.end()) {
return &it->second;
}
e = e->parent_.get();
}
return nullptr;
}
// 'outer x = ...' — mevcut kapsamı ATLAYIP dışarıda arar.
[[nodiscard]] Value* findOuter(const std::string& ad) {
return parent_ ? parent_->find(ad) : nullptr;
}
[[nodiscard]] const std::shared_ptr<Environment>& parent() const noexcept { return parent_; }
private:
std::unordered_map<std::string, Value> vars_;
std::shared_ptr<Environment> parent_;
};
// --- yardımcılar ---
// Dize SPEC §2'ye göre değişmez, görünen tip bu yüzden 'const string'. Ama
// nesne const OLARAK yaratılmıyor: tek sahibi kalan bir dizeyi yerinde
// büyütebilmek için (bkz. yerindeTampon). Gerçekten const bir nesneyi
// değiştirmek tanımsız davranıştır — burada değil.
inline Str makeStr(std::string s) {
return std::make_shared<std::string>(std::move(s));
}
// Yerinde büyütme izni. 'sahip', bu dizeyi tutan ve birazdan zaten üstüne
// yazılacak olan kopyaların sayısı; sayı tutmuyorsa dizeyi görebilecek başka
// biri var demektir ve nullptr döner (çağıran kopyalar). Metin biriktirmenin
// karesel olmaması buna bağlı — tek kullanıcısı interp.cpp'deki atama yolu.
[[nodiscard]] inline std::string* yerindeTampon(const Str& s, long sahip) noexcept {
if (!s || s.use_count() != sahip) {
return nullptr;
}
return const_cast<std::string*>(s.get());
}
// SPEC §2: SADECE nil ve false yanlıştır. 0 ve "" DOĞRUdur.
// Bu, 'if count:' klasik hatasını kökten siler.
inline bool truthy(const Value& v) noexcept {
if (std::holds_alternative<Nil>(v)) {
return false;
}
if (const auto* b = std::get_if<bool>(&v)) {
return *b;
}
return true;
}
// Gömme sınırında (C API) her şey double taşınır. Sayı olmayanlar için:
// nil ve false -> 0, true -> 1, geri kalan -> 0. Kayıpsız değil, kasıtlı —
// sınır skaler, tip taşımıyor (bkz. capi.h).
inline double toDouble(const Value& v) noexcept {
if (const auto* i = std::get_if<std::int64_t>(&v)) {
return static_cast<double>(*i);
}
if (const auto* d = std::get_if<double>(&v)) {
return *d;
}
if (const auto* b = std::get_if<bool>(&v)) {
return *b ? 1.0 : 0.0;
}
return 0.0;
}
[[nodiscard]] std::string typeName(const Value& v);
[[nodiscard]] std::string toDisplay(const Value& v); // print için
[[nodiscard]] std::string toRepr(const Value& v); // iç içe gösterim için
[[nodiscard]] bool valueEquals(const Value& a, const Value& b);
} // namespace rs