History

SBL file reader. Create and implement basic symbol interface used during debugging.

arr committed 9 years ago

Commit a3c184b1 parent 3b54d824 files · +852 −1Browse files

Unified · Split

4 files
  1. limbo/sbl-format-grammar.txt +61 −0
  2. src/asm/asm.gyp +1 −0
  3. src/asm/sbl_reader.cpp +710 −0
  4. src/include/vm_asm.h +80 −1
limbo/sbl-format-grammar.txt+61−0
@@ -0,0 +1,61 @@
1sbl: header file-table pc-table type-table func-table data-table
2
3header: <magic> '\n' <module> '\n'
4module: <string>
5
6file-table: <count> '\n' file*
7file: <string> '\n'
8
9pc-table: <count> '\n' pc-item*
10pc-item: src stmt '\n'
11src: pos ',' pos ' '
12pos: file':'? line'.'? char
13stmt: <int>
14file: <int>
15line: <int>
16char: <int>
17
18type-table: <count> '\n' type*
19type:
20 '@' type-index '\n' # Type table reference
21 'a' adt-item # ADT
22 'p' adt-item tag-table # ADT-Pick
23 't' size '.' id-table # Tuple
24 'm' module '\n' src # Module
25 'A' type # Array
26 'C' type # Channel
27 'F' fn-name type # Function
28 'L' type # List
29 'R' type # Ref
30 'n' # No type
31 'N' # Nil
32 'B' # Big
33 'b' # Byte
34 'i' # Int
35 'f' # Real
36 's' # String
37type-index: <int>
38
39adt-item: adt-name ' ' src size '\n' id-table
40adt-name: <string>
41size: <int>
42
43id-table: <count> '\n' id-item*
44id-item: id-offset ':' id-name ':' src type '\n'
45id-offset: <int>
46id-name: <string>
47
48tag-table: <count> '\n' tag-item*
49tag-item: tag-name ':' src size '\n' id-table
50 | tag-name ':' src '\n'
51tag-name: <string>
52
53func-table: <count> '\n' fn-item*
54fn-item: fn-pc ':' fn-name '\n' args locals return
55fn-pc: <int>
56fn-name: <string>
57args: id-table
58locals: id-table
59return: type
60
61data-table: id-table
src/asm/asm.gyp+1−0
@@ -7,6 +7,7 @@ · 6 unmodified lines
7 'opcode_tokens.cpp',7 'opcode_tokens.cpp',
8 'print_to_stream.cpp',8 'print_to_stream.cpp',
9 'type_signature.cpp',9 'type_signature.cpp',
10 'sbl_reader.cpp',
10 'rfc1321/md5c.c'11 'rfc1321/md5c.c'
11 ],12 ],
12 'include_dirs': [13 'include_dirs': [
src/asm/sbl_reader.cpp+710−0
@@ -0,0 +1,710 @@
1//
2// Dis VM
3// File: sbl_reader.cpp
4// Author: arr
5//
6
7#include <cassert>
8#include <string>
9#include <vector>
10#include <cerrno>
11#include <memory>
12#include <vm_asm.h>
13#include <utils.h>
14#include <buffered_reader.h>
15
16using namespace disvm;
17using namespace disvm::symbol;
18
19namespace
20{
21 enum class sbl_version_t
22 {
23 unknown,
24 sbl_2_0,
25 sbl_2_1,
26 };
27
28 struct header_t
29 {
30 sbl_version_t version_id;
31 std::string module_name;
32 };
33
34 using file_table_t = std::vector<std::string>;
35
36 struct sbl_read_context_t
37 {
38 int32_t pc_count;
39 int32_t last_file;
40 int32_t last_line;
41 };
42
43 struct pc_item_t
44 {
45 source_ref_t source;
46 int32_t debug_statement;
47 };
48
49 using pc_table_t = std::vector<pc_item_t>;
50
51 struct type_t
52 {
53 type_class_t type_class;
54 int32_t value_index_1;
55 int32_t value_index_2;
56 };
57
58 struct id_item_t
59 {
60 uint32_t offset;
61 std::string name;
62 source_ref_t source;
63 type_t type;
64 };
65
66 using id_table_t = std::vector<id_item_t>;
67
68 struct func_item_t
69 {
70 runtime::vm_pc_t entry_pc;
71 runtime::vm_pc_t limit_pc;
72 std::string name;
73 id_table_t args;
74 id_table_t locals;
75 type_t return_type;
76 };
77
78 using func_table_t = std::vector<func_item_t>;
79
80 struct name_source_size_t
81 {
82 std::string name;
83 source_ref_t source;
84 int32_t size_in_bytes;
85 id_table_t id_table;
86 std::unique_ptr<std::vector<name_source_size_t>> tag_table;
87 };
88
89 using adt_item_t = name_source_size_t;
90
91 struct tuple_item_t
92 {
93 int32_t size_in_bytes;
94 id_table_t id_table;
95 };
96
97 struct type_table_t
98 {
99 static const uint32_t string_table_mask = 0x80000000;
100 static const uint32_t inner_type_table_mask = 0x40000000;
101 static const uint32_t source_table_mask = 0x20000000;
102 static const uint32_t adt_table_mask = 0x10000000;
103 static const uint32_t tuple_type_mask = 0x08000000;
104 static const uint32_t types_mask = 0;
105
106 std::vector<type_t> types;
107 std::vector<std::string> strings_table;
108 std::vector<type_t> inner_type_table;
109 std::vector<source_ref_t> source_table;
110 std::vector<name_source_size_t> adt_table;
111 std::vector<tuple_item_t> tuple_table;
112
113 template<typename T>
114 const T &resolve_table_index(int32_t idx) const;
115 };
116
117 template<>
118 const std::string &type_table_t::resolve_table_index<std::string>(int32_t idx) const
119 {
120 const auto idx_local = idx & ~string_table_mask;
121 if (0 > idx_local || idx_local >= strings_table.size())
122 throw std::out_of_range{ "Invalid string table index" };
123
124 return strings_table[idx_local];
125 }
126
127 template<>
128 const type_t &type_table_t::resolve_table_index<type_t>(int32_t idx) const
129 {
130 const auto idx_local = idx & ~inner_type_table_mask;
131 if (0 > idx_local || idx_local >= inner_type_table.size())
132 throw std::out_of_range{ "Invalid inner type table index" };
133
134 return inner_type_table[idx_local];
135 }
136
137 template<>
138 const source_ref_t &type_table_t::resolve_table_index<source_ref_t>(int32_t idx) const
139 {
140 const auto idx_local = idx & ~source_table_mask;
141 if (0 > idx_local || idx_local >= source_table.size())
142 throw std::out_of_range{ "Invalid source table index" };
143
144 return source_table[idx_local];
145 }
146
147 template<>
148 const name_source_size_t &type_table_t::resolve_table_index<name_source_size_t>(int32_t idx) const
149 {
150 const auto idx_local = idx & ~adt_table_mask;
151 if (0 > idx_local || idx_local >= adt_table.size())
152 throw std::out_of_range{ "Invalid adt table index" };
153
154 return adt_table[idx_local];
155 }
156
157 template<>
158 const tuple_item_t &type_table_t::resolve_table_index<tuple_item_t>(int32_t idx) const
159 {
160 const auto idx_local = idx & ~tuple_type_mask;
161 if (0 > idx_local || idx_local >= tuple_table.size())
162 throw std::out_of_range{ "Invalid tuple table index" };
163
164 return tuple_table[idx_local];
165 }
166
167 // sbl: header file-table pc-table type-table func-table data-table
168 struct sbl_file_t final
169 {
170 header_t header;
171
172 file_table_t file_table;
173 pc_table_t pc_table;
174 type_table_t type_table;
175 func_table_t func_table;
176 id_table_t data_table;
177 };
178
179 // header: <magic> '\n' module '\n'
180 // module: <string>
181 header_t read_header(util::buffered_reader_t &r)
182 {
183 header_t header;
184 auto v = r.get_as_string_until('\n');
185 if (v.compare("limbo .sbl 2.1") == 0)
186 header.version_id = sbl_version_t::sbl_2_1;
187 else if (v.compare("limbo .sbl 2.0") == 0)
188 header.version_id = sbl_version_t::sbl_2_0;
189 else
190 throw std::runtime_error{ "Unknown symbol file version" };
191
192 header.module_name = r.get_as_string_until('\n');
193
194 return header;
195 }
196
197 // file-table: <count> '\n' file*
198 // file: <string> '\n'
199 file_table_t read_file_table(util::buffered_reader_t &r)
200 {
201 auto count_str = r.get_as_string_until('\n');
202
203 file_table_t file_table;
204 const auto count = std::stoi(count_str);
205 file_table.resize(count);
206 for (auto i = 0; i < count; ++i)
207 {
208 auto file = r.get_as_string_until('\n');
209 file_table[i] = std::move(file);
210 }
211
212 return file_table;
213 }
214
215 // src: pos ',' pos
216 // pos: file':'? line'.'? char
217 // file: <int>
218 // line: <int>
219 // char: <int>
220 source_ref_t read_src_entry(const std::string &src_str, sbl_read_context_t &fc)
221 {
222 auto src_parts = util::split(src_str, ",");
223 if (src_parts.size() != 2)
224 throw std::runtime_error{ "Invalid source item" };
225
226 source_ref_t src;
227
228 // Initialize the source with the last state
229 src.source_id = fc.last_file;
230 src.begin_line = fc.last_line;
231 src.end_line = fc.last_line;
232 for (auto i = std::size_t{ 0 }; i < src_parts.size(); ++i)
233 {
234 const auto &pos = src_parts[i];
235 const auto len = pos.length();
236
237 // Parse position
238 for (auto j = std::size_t{ 0 }; j < len; ++j)
239 {
240 auto consumed = std::size_t{ 0 };
241 auto v = std::stoi(pos.data() + j, &consumed);
242 j += consumed;
243 if (j >= len)
244 {
245 if (i == 0)
246 src.begin_column = v;
247
248 src.end_column = v;
249 }
250 else if (pos[j] == '.')
251 {
252 if (i == 0)
253 src.begin_line = v;
254
255 src.end_line = v;
256 fc.last_line = v;
257 }
258 else if (pos[j] == ':')
259 {
260 assert((i == 0 || src.source_id == v) && "Source position should not change across statements");
261 src.source_id = v;
262 fc.last_file = v;
263 }
264 }
265 }
266
267 return src;
268 }
269
270 // pc-table: <count> '\n' pc-item*
271 // pc-item: src ' ' stmt '\n'
272 // stmt: <int>
273 pc_table_t read_pc_table(util::buffered_reader_t &r, sbl_read_context_t &fc)
274 {
275 auto count_str = r.get_as_string_until('\n');
276
277 uint32_t last_source = 0;
278 uint32_t last_line = 0;
279
280 pc_table_t pc_table;
281 const auto count = std::stoi(count_str);
282 pc_table.resize(count);
283 for (auto i = 0; i < count; ++i)
284 {
285 auto item = r.get_as_string_until('\n');
286
287 auto pc_item_parts = util::split(item);
288 if (pc_item_parts.size() != 2)
289 throw std::runtime_error{ "Invalid PC item" };
290
291 pc_item_t curr_item;
292 curr_item.source = read_src_entry(pc_item_parts[0], fc);
293 curr_item.debug_statement = std::stoi(pc_item_parts[1]);
294
295 // Record the current source and line ID since those are the new default values
296 last_source = curr_item.source.source_id;
297 last_line = curr_item.source.end_line;
298
299 pc_table[i] = std::move(curr_item);
300 }
301
302 fc.pc_count = count;
303 return pc_table;
304 }
305
306 // Forward declaration
307 type_t read_type(util::buffered_reader_t &, type_table_t &, sbl_read_context_t &);
308
309 // id-table: <count> '\n' id-item*
310 // id-item: id-offset ':' id-name ':' src ' ' type '\n'
311 // id-offset: <int>
312 // id-name: <string>
313 id_table_t read_id_table(util::buffered_reader_t &r, type_table_t &tt, sbl_read_context_t &fc)
314 {
315 auto count_str = r.get_as_string_until('\n');
316 int32_t count = std::stoi(count_str);
317
318 bool success;
319 uint8_t tmp;
320 id_table_t id_table;
321 id_table.resize(count);
322 for (auto i = 0; i < count; ++i)
323 {
324 const auto offset_part = r.get_as_string_until(':');
325 if (offset_part.empty())
326 throw std::runtime_error{ "Invalid ID table item (offset)" };
327
328 const auto name_part = r.get_as_string_until(':');
329 if (name_part.empty())
330 throw std::runtime_error{ "Invalid ID table item (name)" };
331
332 const auto source_part = r.get_as_string_until(' ');
333 if (source_part.empty())
334 throw std::runtime_error{ "Invalid ID table item (source)" };
335
336 id_item_t e;
337 e.offset = std::stoul(offset_part);
338 e.name = std::move(name_part);
339 e.source = read_src_entry(source_part, fc);
340 e.type = read_type(r, tt, fc);
341
342 std::tie(success, tmp) = r.get_next_byte();
343 if (!success || tmp != '\n')
344 throw std::runtime_error{ "Invalid ID table item" };
345
346 id_table[i] = std::move(e);
347 }
348
349 return id_table;
350 }
351
352 // adt-item: adt-name ' ' src ' ' size '\n' id-table
353 // adt-name: <string>
354 // size: <int>
355 //
356 // tag-table: <count> '\n' tag-item*
357 // tag-item: tag-name ':' src ' ' size '\n' id-table
358 // | tag-name ':' src '\n'
359 // tag-name: <string>
360 name_source_size_t create_name_source_size(std::vector<std::string> &parts, util::buffered_reader_t &r, type_table_t &tt, sbl_read_context_t &fc)
361 {
362 assert(parts.size() == 2 || parts.size() == 3);
363 name_source_size_t item;
364 item.name = std::move(parts[0]);
365 item.source = read_src_entry(parts[1], fc);
366
367 if (parts.size() == 3)
368 {
369 item.size_in_bytes = std::strtol(parts[2].c_str(), nullptr, 10);
370 if (item.size_in_bytes == 0 && errno != 0)
371 throw std::runtime_error{ "Invalid adt size" };
372
373 item.id_table = read_id_table(r, tt, fc);
374 }
375
376 return item;
377 }
378
379 // type:
380 // '@' type-index '\n' # Type table reference
381 // 'a' adt-item # ADT
382 // 'p' adt-item tag-table # ADT-Pick
383 // 't' size '.' id-table # Tuple
384 // 'm' module '\n' src # Module
385 // 'F' fn-name ' ' type # Function
386 // 'A' type # Array
387 // 'C' type # Channel
388 // 'L' type # List
389 // 'R' type # Ref
390 // 'n' # No type
391 // 'N' # Nil
392 // 'B' # Big
393 // 'b' # Byte
394 // 'i' # Int
395 // 'f' # Real
396 // 's' # String
397 // type-index: <int>
398 type_t read_type(util::buffered_reader_t &r, type_table_t &tt, sbl_read_context_t &fc)
399 {
400 bool success;
401 uint8_t tc_byte;
402 std::tie(success, tc_byte) = r.get_next_byte();
403 if (!success)
404 throw std::runtime_error{ "Invalid type" };
405
406 const type_class_t tc = static_cast<type_class_t>(tc_byte);
407 type_t t{ tc, 0, 0 };
408 switch (t.type_class)
409 {
410 case type_class_t::none:
411 case type_class_t::nil:
412 case type_class_t::big:
413 case type_class_t::byte:
414 case type_class_t::integer:
415 case type_class_t::real:
416 case type_class_t::string:
417 case type_class_t::poly:
418 break;
419
420 case type_class_t::array:
421 case type_class_t::channel:
422 case type_class_t::list:
423 case type_class_t::ref:
424 t.value_index_1 = type_table_t::inner_type_table_mask | tt.inner_type_table.size();
425 tt.inner_type_table.push_back(read_type(r, tt, fc));
426 break;
427
428 case type_class_t::type_index:
429 {
430 auto type_index = r.get_as_string_until('\n');
431 const auto idx = std::stoi(type_index);
432 if (idx == 0)
433 throw std::runtime_error{ "Invalid type index" };
434
435 t.value_index_1 = type_table_t::types_mask | idx;
436 break;
437 }
438 case type_class_t::adt:
439 case type_class_t::adt_pick:
440 {
441 auto adt_line = r.get_as_string_until('\n');
442 auto adt_parts = util::split(adt_line);
443 if (adt_parts.size() != 3)
444 throw std::runtime_error{ "Invalid adt item" };
445
446 auto adt_item = create_name_source_size(adt_parts, r, tt, fc);
447
448 // Check if the adt has a tag table
449 if (t.type_class == type_class_t::adt_pick)
450 {
451 adt_item.tag_table = std::make_unique<std::vector<name_source_size_t>>();
452 auto tmp = r.get_as_string_until('\n');
453
454 const auto count = std::stoi(tmp);
455 for (auto i = 0; i < count; ++i)
456 {
457 tmp = r.get_as_string_until('\n');
458 auto tag_parts = util::split(tmp, " :");
459 if (tag_parts.size() != 2 && tag_parts.size() != 3)
460 throw std::runtime_error{ "Invalid tag item" };
461
462 auto tag = create_name_source_size(tag_parts, r, tt, fc);
463 adt_item.tag_table->push_back(std::move(tag));
464 }
465 }
466
467 t.value_index_1 = type_table_t::adt_table_mask | tt.adt_table.size();
468 tt.adt_table.push_back(std::move(adt_item));
469 break;
470 }
471 case type_class_t::tuple:
472 {
473 // Record tuple size
474 t.value_index_1 = type_table_t::tuple_type_mask | tt.tuple_table.size();
475
476 tuple_item_t tuple{};
477 auto size_str = r.get_as_string_until('.');
478 tuple.size_in_bytes = std::stoi(size_str);
479
480 tuple.id_table = read_id_table(r, tt, fc);
481 tt.tuple_table.push_back(std::move(tuple));
482 break;
483 }
484 case type_class_t::module:
485 {
486 // Record module name
487 t.value_index_1 = type_table_t::string_table_mask | tt.strings_table.size();
488 tt.strings_table.push_back(r.get_as_string_until('\n'));
489
490 auto src_str = r.get_as_string_until('\n');
491 t.value_index_2 = type_table_t::source_table_mask | tt.source_table.size();
492 tt.source_table.push_back(read_src_entry(src_str, fc));
493 break;
494 }
495
496 case type_class_t::function:
497 {
498 // Record function name
499 t.value_index_1 = type_table_t::string_table_mask | tt.strings_table.size();
500 auto name = r.get_as_string_until(' ');
501 if (name.empty())
502 throw std::runtime_error{ "Invalid function type" };
503
504 tt.strings_table.push_back(std::move(name));
505
506 // Record return type
507 t.value_index_2 = type_table_t::inner_type_table_mask | tt.inner_type_table.size();
508 tt.inner_type_table.push_back(read_type(r, tt, fc));
509 break;
510 }
511
512 default:
513 throw std::runtime_error{ "Invalid type value" };
514 }
515
516 return t;
517 }
518
519 // type-table: <count> '\n' type*
520 type_table_t read_type_table(util::buffered_reader_t &r, sbl_read_context_t &fc)
521 {
522 auto count_str = r.get_as_string_until('\n');
523
524 type_table_t type_table;
525 const auto count = std::stoi(count_str);
526 type_table.types.resize(count);
527 for (auto i = 0; i < count; ++i)
528 type_table.types[i] = read_type(r, type_table, fc);
529
530 return type_table;
531 }
532
533 // func-table: <count> '\n' fn-item*
534 // fn-item: fn-pc ':' fn-name '\n' args locals return
535 // fn-pc: <int>
536 // fn-name: <string>
537 // args: id-table
538 // locals: id-table
539 // return: type
540 func_table_t read_func_table(util::buffered_reader_t &r, type_table_t &tt, sbl_read_context_t &fc)
541 {
542 auto count_str = r.get_as_string_until('\n');
543
544 const auto last_pc = fc.pc_count - 1;
545 func_table_t func_table;
546 const auto count = std::stoi(count_str);
547 func_table.resize(count);
548 for (auto i = 0; i < count; ++i)
549 {
550 func_item_t func;
551 func.entry_pc = std::stoi(r.get_as_string_until(':'));
552 func.limit_pc = last_pc;
553 func.name = std::move(r.get_as_string_until('\n'));
554 func.args = read_id_table(r, tt, fc);
555 func.locals = read_id_table(r, tt, fc);
556 func.return_type = read_type(r, tt, fc);
557
558 // Update the previous functions limit
559 if (i > 0)
560 {
561 assert(func_table[i - 1].entry_pc < func.entry_pc && "Function table in sbl file is assumed to be in pc order");
562 func_table[i - 1].limit_pc = func.entry_pc - 1;
563 }
564
565 func_table[i] = std::move(func);
566 }
567
568 return func_table;
569 }
570
571 // data-table: id-table
572 id_table_t read_data_table(util::buffered_reader_t &r, type_table_t &tt, sbl_read_context_t &fc)
573 {
574 return read_id_table(r, tt, fc);
575 }
576}
577
578namespace
579{
580 class sbl_symbol_debug final : public symbol_debug_t
581 {
582 public:
583 sbl_symbol_debug(std::shared_ptr<sbl_file_t> f)
584 : _current_pc{ 0 }
585 , _file{ f }
586 {
587 assert(_file != nullptr);
588 }
589
590 public: // symbol_debug_t
591 void set_current_pc(disvm::runtime::vm_pc_t pc) override
592 {
593 assert(0 <= pc && pc < static_cast<int32_t>(_file->pc_table.size()));
594 _current_pc = pc;
595 }
596
597 bool try_advance_pc(advance_pc_t adv, disvm::runtime::vm_pc_t *pc_after_advance) override
598 {
599 runtime::vm_pc_t new_pc = _current_pc;
600 switch (adv)
601 {
602 case advance_pc_t::next_debug_statement:
603 {
604 auto iter = std::next(std::cbegin(_file->pc_table), new_pc);
605 const auto current_dbg = iter->debug_statement;
606
607 // Iterate until the next pc entry that is not the same debug statement or the end.
608 while (iter != std::cend(_file->pc_table) && iter->debug_statement == current_dbg)
609 {
610 ++iter;
611 }
612
613 if (iter == std::cend(_file->pc_table))
614 return false;
615
616 new_pc = std::distance(std::cbegin(_file->pc_table), iter);
617 break;
618 }
619
620 case advance_pc_t::next_pc:
621 if (new_pc + 1 >= static_cast<runtime::vm_pc_t>(_file->pc_table.size()))
622 return false;
623 ++new_pc;
624 break;
625
626 case advance_pc_t::current:
627 assert(pc_after_advance != nullptr);
628 break;
629
630 default:
631 throw std::runtime_error{ "Invalid advance value" };
632 }
633
634 if (pc_after_advance != nullptr)
635 *pc_after_advance = new_pc;
636
637 _current_pc = new_pc;
638 return true;
639 }
640
641 const std::string &current_function_name() const override
642 {
643 for (auto &e : _file->func_table)
644 {
645 if (e.entry_pc <= _current_pc && _current_pc <= e.limit_pc)
646 return e.name;
647 }
648
649 throw std::runtime_error{ "Unknown function" };
650 }
651
652 source_ref_t current_source_location() const override
653 {
654 assert(0 <= _current_pc && _current_pc < static_cast<int32_t>(_file->pc_table.size()));
655 return _file->pc_table[_current_pc].source;
656 }
657
658 const std::string &get_source_by_id(int32_t source_id) const override
659 {
660 assert(0 <= source_id && source_id < static_cast<int32_t>(_file->file_table.size()));
661 return _file->file_table[source_id];
662 }
663
664 private:
665 runtime::vm_pc_t _current_pc;
666 std::shared_ptr<sbl_file_t> _file;
667 };
668
669 class sbl_symbol_data final : public symbol_data_t
670 {
671 public:
672 sbl_symbol_data(std::shared_ptr<sbl_file_t> f)
673 : _file{ f }
674 {
675 assert(_file != nullptr);
676 }
677
678 public: // symbol_data_t
679 const std::string & get_module_name() const override
680 {
681 return _file->header.module_name;
682 }
683
684 std::unique_ptr<symbol_debug_t> get_debug() override
685 {
686 return std::make_unique<sbl_symbol_debug>(_file);
687 }
688
689 private:
690 std::shared_ptr<sbl_file_t> _file;
691 };
692}
693
694std::unique_ptr<symbol_data_t> disvm::symbol::read(std::istream &f)
695{
696 auto file = std::make_shared<sbl_file_t>();
697
698 util::buffered_reader_t reader{ f };
699
700 file->header = read_header(reader);
701 file->file_table = read_file_table(reader);
702
703 sbl_read_context_t fc{};
704 file->pc_table = read_pc_table(reader, fc);
705 file->type_table = read_type_table(reader, fc);
706 file->func_table = read_func_table(reader, file->type_table, fc);
707 file->data_table = read_data_table(reader, file->type_table, fc);
708
709 return std::make_unique<sbl_symbol_data>(file);
710}
src/include/vm_asm.h+80−1
@@ -34,7 +34,7 @@ namespace disvm · 33 unmodified lines
34 // If the supplied string cannot be resolved or if it is null, the 'invalid' opcode is returned.34 // If the supplied string cannot be resolved or if it is null, the 'invalid' opcode is returned.
35 disvm::opcode_t token_to_opcode(const char *);35 disvm::opcode_t token_to_opcode(const char *);
36 36
37 // Namedspace named after enum type in Limbo compiler37 // Namespace named after enum type in Limbo compiler
38 // Source: limbo/types.c38 // Source: limbo/types.c
39 namespace sigkind39 namespace sigkind
40 {40 {
@@ -369,6 +369,85 @@ namespace disvm · 328 unmodified lines
369 }369 }
370 }370 }
371 371
372 namespace symbol
373 {
374 // Type class enum for symbols is unrelated to signature types enum.
375 // The historical reason for this isn't recorded but is found in
376 // the official Limbo compiler.
377 enum class type_class_t : uint8_t
378 {
379 type_index = '@',
380 adt = 'a',
381 adt_pick = 'p',
382 tuple = 't',
383 module = 'm',
384 function = 'F',
385 array = 'A',
386 channel = 'C',
387 list = 'L',
388 ref = 'R',
389 none = 'n',
390 nil = 'N',
391 big = 'B',
392 byte = 'b',
393 integer = 'i',
394 real = 'f',
395 string = 's',
396 poly = 'P',
397 };
398
399 // Reference into source code
400 struct source_ref_t
401 {
402 int32_t source_id;
403 int32_t begin_line;
404 int32_t begin_column;
405 int32_t end_line;
406 int32_t end_column;
407 };
408
409 class symbol_debug_t
410 {
411 public:
412 // Set the current pc
413 virtual void set_current_pc(disvm::runtime::vm_pc_t) = 0;
414
415 // Enumeration for advancing the pc
416 enum class advance_pc_t
417 {
418 current, // Return the current pc
419 next_pc,
420 next_debug_statement, // Advance to the next debug statement (i.e. source language statement)
421 };
422
423 // Advance the current pc.
424 // Returns 'true' if the function was successful, otherwise 'false'.
425 virtual bool try_advance_pc(advance_pc_t, disvm::runtime::vm_pc_t *pc_after_advance = nullptr) = 0;
426
427 // Return the name of the function encompassing the current pc.
428 // This function will throw a 'std::runtime_error' if a function doesn't exist at the current pc.
429 virtual const std::string & current_function_name() const = 0;
430
431 // Return the source location for the current pc
432 virtual source_ref_t current_source_location() const = 0;
433
434 // Get source file name based on ID
435 virtual const std::string &get_source_by_id(int32_t source_id) const = 0;
436 };
437
438 class symbol_data_t
439 {
440 public:
441 // Get name of the module
442 virtual const std::string& get_module_name() const = 0;
443
444 // Get interface over symbol data targeted for debugging
445 virtual std::unique_ptr<symbol_debug_t> get_debug() = 0;
446 };
447
448 std::unique_ptr<symbol_data_t> read(std::istream &);
449 }
450
372 namespace runtime451 namespace runtime
373 {452 {
374 // Operators for printing bytecode instructions453 // Operators for printing bytecode instructions