10 #include "position.hpp"
11 #include "source_map.hpp"
14 SourceMap::SourceMap() : current_position(0, 0, 0), file("stdin") { }
15 SourceMap::SourceMap(const std::string& file) : current_position(0, 0, 0), file(file) { }
17 std::string SourceMap::render_srcmap(Context &ctx) {
19 const bool include_sources = ctx.c_options.source_map_contents;
20 const std::vector<std::string> links = ctx.srcmap_links;
21 const std::vector<Resource>& sources(ctx.resources);
23 JsonNode* json_srcmap = json_mkobject();
25 json_append_member(json_srcmap, "version", json_mknumber(3));
27 const char *include = file.c_str();
28 JsonNode *json_include = json_mkstring(include);
29 json_append_member(json_srcmap, "file", json_include);
31 // pass-through sourceRoot option
32 if (!ctx.source_map_root.empty()) {
33 JsonNode* root = json_mkstring(ctx.source_map_root.c_str());
34 json_append_member(json_srcmap, "sourceRoot", root);
37 JsonNode *json_includes = json_mkarray();
38 for (size_t i = 0; i < source_index.size(); ++i) {
39 std::string include(links[source_index[i]]);
40 if (ctx.c_options.source_map_file_urls) {
41 include = File::rel2abs(include);
42 // check for windows abs path
43 if (include[0] == '/') {
44 // ends up with three slashes
45 include = "file://" + include;
47 // needs an additional slash
48 include = "file:///" + include;
51 const char* inc = include.c_str();
52 JsonNode *json_include = json_mkstring(inc);
53 json_append_element(json_includes, json_include);
55 json_append_member(json_srcmap, "sources", json_includes);
57 if (include_sources) {
58 JsonNode *json_contents = json_mkarray();
59 for (size_t i = 0; i < source_index.size(); ++i) {
60 const Resource& resource(sources[source_index[i]]);
61 JsonNode *json_content = json_mkstring(resource.contents);
62 json_append_element(json_contents, json_content);
64 if (json_contents->children.head)
65 json_append_member(json_srcmap, "sourcesContent", json_contents);
68 JsonNode *json_names = json_mkarray();
69 // so far we have no implementation for names
70 // no problem as we do not alter any identifiers
71 json_append_member(json_srcmap, "names", json_names);
73 std::string mappings = serialize_mappings();
74 JsonNode *json_mappings = json_mkstring(mappings.c_str());
75 json_append_member(json_srcmap, "mappings", json_mappings);
77 char *str = json_stringify(json_srcmap, "\t");
78 std::string result = std::string(str);
80 json_delete(json_srcmap);
84 std::string SourceMap::serialize_mappings() {
85 std::string result = "";
87 size_t previous_generated_line = 0;
88 size_t previous_generated_column = 0;
89 size_t previous_original_line = 0;
90 size_t previous_original_column = 0;
91 size_t previous_original_file = 0;
92 for (size_t i = 0; i < mappings.size(); ++i) {
93 const size_t generated_line = mappings[i].generated_position.line;
94 const size_t generated_column = mappings[i].generated_position.column;
95 const size_t original_line = mappings[i].original_position.line;
96 const size_t original_column = mappings[i].original_position.column;
97 const size_t original_file = mappings[i].original_position.file;
99 if (generated_line != previous_generated_line) {
100 previous_generated_column = 0;
101 if (generated_line > previous_generated_line) {
102 result += std::string(generated_line - previous_generated_line, ';');
103 previous_generated_line = generated_line;
111 result += base64vlq.encode(static_cast<int>(generated_column) - static_cast<int>(previous_generated_column));
112 previous_generated_column = generated_column;
114 result += base64vlq.encode(static_cast<int>(original_file) - static_cast<int>(previous_original_file));
115 previous_original_file = original_file;
117 result += base64vlq.encode(static_cast<int>(original_line) - static_cast<int>(previous_original_line));
118 previous_original_line = original_line;
120 result += base64vlq.encode(static_cast<int>(original_column) - static_cast<int>(previous_original_column));
121 previous_original_column = original_column;
127 void SourceMap::prepend(const OutputBuffer& out)
129 Offset size(out.smap.current_position);
130 for (Mapping mapping : out.smap.mappings) {
131 if (mapping.generated_position.line > size.line) {
132 throw(std::runtime_error("prepend sourcemap has illegal line"));
134 if (mapping.generated_position.line == size.line) {
135 if (mapping.generated_position.column > size.column) {
136 throw(std::runtime_error("prepend sourcemap has illegal column"));
140 // will adjust the offset
141 prepend(Offset(out.buffer));
142 // now add the new mappings
143 VECTOR_UNSHIFT(mappings, out.smap.mappings);
146 void SourceMap::append(const OutputBuffer& out)
148 append(Offset(out.buffer));
151 void SourceMap::prepend(const Offset& offset)
153 if (offset.line != 0 || offset.column != 0) {
154 for (Mapping& mapping : mappings) {
155 // move stuff on the first old line
156 if (mapping.generated_position.line == 0) {
157 mapping.generated_position.column += offset.column;
159 // make place for the new lines
160 mapping.generated_position.line += offset.line;
163 if (current_position.line == 0) {
164 current_position.column += offset.column;
166 current_position.line += offset.line;
169 void SourceMap::append(const Offset& offset)
171 current_position += offset;
174 void SourceMap::add_open_mapping(const AST_Node_Ptr node)
176 mappings.push_back(Mapping(node->pstate(), current_position));
179 void SourceMap::add_close_mapping(const AST_Node_Ptr node)
181 mappings.push_back(Mapping(node->pstate() + node->pstate().offset, current_position));
184 ParserState SourceMap::remap(const ParserState& pstate) {
185 for (size_t i = 0; i < mappings.size(); ++i) {
187 mappings[i].generated_position.file == pstate.file &&
188 mappings[i].generated_position.line == pstate.line &&
189 mappings[i].generated_position.column == pstate.column
190 ) return ParserState(pstate.path, pstate.src, mappings[i].original_position, pstate.offset);
192 return ParserState(pstate.path, pstate.src, Position(-1, -1, -1), Offset(0, 0));