/src/moddable/xs/sources/xsSourceMap.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2016-2022 Moddable Tech, Inc. |
3 | | * |
4 | | * This file is part of the Moddable SDK Runtime. |
5 | | * |
6 | | * The Moddable SDK Runtime is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * The Moddable SDK Runtime is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License |
17 | | * along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | * This file incorporates work covered by the following copyright and |
20 | | * permission notice: |
21 | | * |
22 | | * Copyright (C) 2010-2016 Marvell International Ltd. |
23 | | * Copyright (C) 2002-2010 Kinoma, Inc. |
24 | | * |
25 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
26 | | * you may not use this file except in compliance with the License. |
27 | | * You may obtain a copy of the License at |
28 | | * |
29 | | * http://www.apache.org/licenses/LICENSE-2.0 |
30 | | * |
31 | | * Unless required by applicable law or agreed to in writing, software |
32 | | * distributed under the License is distributed on an "AS IS" BASIS, |
33 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
34 | | * See the License for the specific language governing permissions and |
35 | | * limitations under the License. |
36 | | */ |
37 | | |
38 | | #include "xsScript.h" |
39 | | |
40 | | static void fxSourceMapLines(txParser* parser, txString mappings); |
41 | | static txInteger fxSourceMapValue(txParser* parser, txString* p); |
42 | | |
43 | 0 | #define mxAssert(ASSERTION,MESSAGE) if (!(ASSERTION)) { fxReportParserError(parser, parser->states[0].line, MESSAGE); return; } |
44 | | |
45 | | void fxParserSourceMap(txParser* parser, void* theStream, txGetter theGetter, txUnsigned flags, txString* name) |
46 | 0 | { |
47 | 0 | txInteger line = parser->states[0].line; |
48 | 0 | txNode* root = parser->root; |
49 | 0 | txNode* object; |
50 | 0 | txNode* item; |
51 | 0 | txNode* node; |
52 | 0 | txPropertyAtNode* property; |
53 | 0 | txString id; |
54 | 0 | txInteger version = 0; |
55 | 0 | txString source = NULL; |
56 | 0 | txString mappings = NULL; |
57 | | |
58 | 0 | parser->states[0].line = 0; |
59 | 0 | parser->root = NULL; |
60 | 0 | parser->stream = theStream; |
61 | 0 | parser->getter = theGetter; |
62 | | |
63 | 0 | parser->states[2].line = 1; |
64 | 0 | parser->states[2].crlf = 0; |
65 | 0 | parser->states[2].escaped = 0; |
66 | 0 | parser->states[2].integer = 0; |
67 | 0 | parser->states[2].modifierLength = 0; |
68 | 0 | parser->states[2].modifier = parser->emptyString; |
69 | 0 | parser->states[2].number = 0; |
70 | 0 | parser->states[2].stringLength = 0; |
71 | 0 | parser->states[2].string = parser->emptyString; |
72 | 0 | parser->states[2].symbol = C_NULL; |
73 | 0 | parser->states[2].token = XS_NO_TOKEN; |
74 | | |
75 | 0 | parser->lookahead = 0; |
76 | 0 | #if mxCESU8 |
77 | 0 | parser->surrogate = 0; |
78 | 0 | #endif |
79 | 0 | fxGetNextCharacter(parser); |
80 | 0 | fxGetNextCharacter(parser); |
81 | 0 | fxGetNextTokenJSON(parser); |
82 | 0 | fxGetNextTokenJSON(parser); |
83 | 0 | fxJSONValue(parser); |
84 | 0 | if (parser->errorCount) |
85 | 0 | return; |
86 | 0 | object = parser->root; |
87 | 0 | parser->states[0].line = line; |
88 | 0 | parser->root = root; |
89 | | |
90 | 0 | mxAssert(object->description->token == XS_TOKEN_OBJECT, "source map: no object"); |
91 | 0 | mxAssert(((txObjectNode*)object)->items, "source map: no properties"); |
92 | 0 | item = ((txObjectNode*)object)->items->first; |
93 | 0 | while (item) { |
94 | 0 | mxAssert(item->description->token == XS_TOKEN_PROPERTY_AT, "source map: no property"); |
95 | 0 | property = (txPropertyAtNode*)item; |
96 | 0 | mxAssert(property->at->description->token == XS_TOKEN_STRING, "source map: no property name"); |
97 | 0 | id = ((txStringNode*)(property->at))->value; |
98 | 0 | if (!c_strcmp(id, "version")) { |
99 | 0 | mxAssert(property->value->description->token == XS_TOKEN_INTEGER, "source map: version is no integer"); |
100 | 0 | version = ((txIntegerNode*)(property->value))->value; |
101 | 0 | } |
102 | 0 | else if (!c_strcmp(id, "sources")) { |
103 | 0 | mxAssert(property->value->description->token == XS_TOKEN_ARRAY, "source map: sources is no array"); |
104 | 0 | node = ((txArrayNode*)(property->value))->items->first; |
105 | 0 | mxAssert(node->description->token == XS_TOKEN_STRING, "source map: sources[0] is no string"); |
106 | 0 | source = ((txStringNode*)(node))->value; |
107 | 0 | } |
108 | 0 | else if (!c_strcmp(id, "mappings")) { |
109 | 0 | mxAssert(property->value->description->token == XS_TOKEN_STRING, "source map: mappings is no string"); |
110 | 0 | mappings = ((txStringNode*)(property->value))->value; |
111 | 0 | } |
112 | 0 | item = item->next; |
113 | 0 | } |
114 | 0 | mxAssert(version == 3, "source map: version is not 3"); |
115 | 0 | mxAssert(source, "source map: no source"); |
116 | 0 | mxAssert(mappings, "source map: no mappings"); |
117 | | |
118 | 0 | parser->lines = fxNewParserChunkClear(parser, (1 + line) * sizeof(txInteger)); |
119 | |
|
120 | 0 | fxSourceMapLines(parser, mappings); |
121 | 0 | *name = source; |
122 | 0 | } |
123 | | |
124 | | void fxSourceMapLines(txParser* parser, txString mappings) |
125 | 0 | { |
126 | 0 | enum { BEGIN, SOURCE, LINE, COLUMN, NAME, END }; |
127 | 0 | txInteger generatedLine = 0; |
128 | | // txInteger generatedColumn = 0; |
129 | | // txInteger name = 0; |
130 | | // txInteger source = 0; |
131 | 0 | txInteger sourceLine = 0; |
132 | | // txInteger sourceColumn = 0; |
133 | 0 | txInteger state = BEGIN; |
134 | 0 | txString p = mappings; |
135 | 0 | char c; |
136 | 0 | while ((c = *p)) { |
137 | 0 | if (c == ';') { |
138 | 0 | p++; |
139 | 0 | if ((state >= NAME) && (generatedLine < parser->states[0].line)) |
140 | 0 | parser->lines[1 + generatedLine] = 1 + sourceLine; |
141 | 0 | generatedLine++; |
142 | | // generatedColumn = 0; |
143 | 0 | state = BEGIN; |
144 | 0 | } |
145 | 0 | else if (c == ',') { |
146 | 0 | p++; |
147 | 0 | if ((state >= NAME) && (generatedLine < parser->states[0].line)) |
148 | 0 | parser->lines[1 + generatedLine] = 1 + sourceLine; |
149 | 0 | state = BEGIN; |
150 | 0 | } |
151 | 0 | else { |
152 | 0 | txInteger value = fxSourceMapValue(parser, &p); |
153 | 0 | switch(state) { |
154 | 0 | case BEGIN: |
155 | | // generatedColumn += value; |
156 | 0 | state = SOURCE; |
157 | 0 | break; |
158 | 0 | case SOURCE: |
159 | | // source += value; |
160 | 0 | state = LINE; |
161 | 0 | break; |
162 | 0 | case LINE: |
163 | 0 | sourceLine += value; |
164 | 0 | state = COLUMN; |
165 | 0 | break; |
166 | 0 | case COLUMN: |
167 | | // sourceColumn += value; |
168 | 0 | state = NAME; |
169 | 0 | break; |
170 | 0 | case NAME: |
171 | | // name += value; |
172 | 0 | state = END; |
173 | 0 | break; |
174 | 0 | } |
175 | 0 | } |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | 0 | #define VLQ_SHIFT 5 |
180 | | // binary: 100000 |
181 | 0 | #define VLQ_CONTINUATION_BIT (1 << VLQ_SHIFT) |
182 | | // binary: 011111 |
183 | 0 | #define VLQ_MASK_BITS (VLQ_CONTINUATION_BIT - 1) |
184 | | |
185 | | txInteger fxSourceMapValue(txParser* parser, txString* p) |
186 | 0 | { |
187 | 0 | txInteger continuation, digit, result = 0, shift = 0; |
188 | 0 | txString q = *p; |
189 | 0 | do { |
190 | 0 | char c = *q++; |
191 | 0 | if (('A' <= c) && (c <= 'Z')) |
192 | 0 | digit = c - 'A'; |
193 | 0 | else if (('a' <= c) && (c <= 'z')) |
194 | 0 | digit = c - 'a' + 26; |
195 | 0 | else if (('0' <= c) && (c <= '9')) |
196 | 0 | digit = c - '0' + 52; |
197 | 0 | else if (c == '+') |
198 | 0 | digit = 62; |
199 | 0 | else if (c == '/') |
200 | 0 | digit = 63; |
201 | 0 | else |
202 | 0 | fxReportParserError(parser, parser->states[0].line, "source map: unexpected character"); |
203 | 0 | continuation = digit & VLQ_CONTINUATION_BIT; |
204 | 0 | digit &= VLQ_MASK_BITS; |
205 | 0 | result += (digit << shift); |
206 | 0 | shift += VLQ_SHIFT; |
207 | 0 | } while (continuation); |
208 | 0 | *p = q; |
209 | 0 | shift = result >> 1; |
210 | 0 | return ((result & 1) == 1) ? -shift : shift; |
211 | 0 | } |
212 | | |
213 | | |
214 | | |
215 | | |
216 | | |
217 | | |
218 | | |