1 /** This module implements the DebugInfo class
2 
3 ────────────────────────────────────────────────────────────────────────────────
4 
5 Copyright (C) 2021 pillager86.rf.gd
6 
7 This program is free software: you can redistribute it and/or modify it under 
8 the terms of the GNU General Public License as published by the Free Software 
9 Foundation, either version 3 of the License, or (at your option) any later 
10 version.
11 
12 This program is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14 PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License along with 
17 this program.  If not, see <https://www.gnu.org/licenses/>.
18 */
19 module mildew.vm.debuginfo;
20 
21 import std..string;
22 import std.typecons;
23 
24 /// Alias for a hash map that associates DebugInfos to specific blocks of raw bytecode.
25 alias DebugMap = DebugInfo[ubyte[]];
26 
27 /**
28  * Holds debug information to be associated with completed ubyte[] code.
29  */
30 class DebugInfo
31 {
32 public:
33     alias LineData = Tuple!(size_t, "ip", size_t, "lineNumber");
34 
35     /// constructor
36     this(string src, string name = "")
37     {
38         _source = splitLines(src);
39         _name = name;
40     }
41 
42     /// Add an ip-lineNumber pair
43     void addLine(size_t ip, size_t lineNumber)
44     {
45         _lines ~= tuple!(size_t, "ip", size_t, "lineNumber")(ip, lineNumber);
46     }
47 
48     /// get line associated with ip
49     size_t getLineNumber(size_t ip)
50     {   
51         long index = 0;
52         while(index < cast(long)_lines.length - 1)
53         {
54             if(ip >= _lines[index].ip && ip < _lines[index+1].ip)
55                 return _lines[index].lineNumber;
56             ++index;
57         }
58         // if we get to this point assume the error was on the last line if it exists
59         if(_lines.length >= 1)
60         {
61             return _lines[$-1].lineNumber;
62         }
63         // else the line info is missing so just return 0
64         return 0;
65     }
66 
67     /// get a line of source starting at 1 if it exists
68     string getSourceLine(size_t lineNum)
69     {
70         if(lineNum-1 >= _source.length)
71             return "";
72         return _source[lineNum-1];
73     }
74 
75     /// name property
76     string name() const { return _name; }
77 
78     override string toString() const 
79     {
80         import std.format: format;
81         return format("#lines=%s, #source=%s, name=`%s`", _lines.length, _source.length, _name);
82     }
83 
84 private:
85     /// represents the source code as lines for error reporting
86     string[] _source;
87     /// line data array
88     LineData[] _lines;
89     /// optional name
90     string _name;
91 }