feat: add column number

This commit is contained in:
ErosZy 2022-11-12 22:53:03 +08:00
parent 2788d71e82
commit 00ed5215e2
7 changed files with 623 additions and 49 deletions

View File

@ -303,6 +303,16 @@ int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
return c;
}
int utf8_str_len(const uint8_t *p_start, const uint8_t *p_end) {
int count = 0;
while (p_start < p_end) {
if (!unicode_from_utf8(p_start, UTF8_CHAR_LEN_MAX, &p_start))
break;
count += 1;
}
return count;
}
#if 0
#if defined(EMSCRIPTEN) || defined(__ANDROID__)

View File

@ -277,6 +277,7 @@ static inline void dbuf_set_error(DynBuf *s)
int unicode_to_utf8(uint8_t *buf, unsigned int c);
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
int utf8_str_len(const uint8_t *p_start, const uint8_t *p_end);
static inline int from_hex(int c)
{

View File

@ -81,6 +81,7 @@ DEF(empty_string, "")
DEF(length, "length")
DEF(fileName, "fileName")
DEF(lineNumber, "lineNumber")
DEF(columnNumber, "columnNumber")
DEF(message, "message")
DEF(errors, "errors")
DEF(stack, "stack")

View File

@ -284,6 +284,7 @@ def(scope_put_private_field, 7, 1, 1, atom_u16) /* obj value ->, emitted in phas
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */
def( column_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */
#if SHORT_OPCODES
DEF( push_minus1, 1, 0, 1, none_int)

418
quickjs.c

File diff suppressed because it is too large Load Diff

View File

@ -407,6 +407,7 @@ typedef struct JSMemoryUsage {
int64_t shape_count, shape_size;
int64_t js_func_count, js_func_size, js_func_code_size;
int64_t js_func_pc2line_count, js_func_pc2line_size;
int64_t js_func_pc2column_count, js_func_pc2column_size;
int64_t c_func_count, array_count;
int64_t fast_array_count, fast_array_elements;
int64_t binary_object_count, binary_object_size;

240
tests/test_line_column.js Normal file
View File

@ -0,0 +1,240 @@
"use strict";
function assert(actual, expected, message) {
if (arguments.length == 1) expected = true;
if (actual === expected) return;
if (actual !== null && expected !== null && typeof actual == 'object' &&
typeof expected == 'object' && actual.toString() === expected.toString())
return;
throw Error(
'assertion failed: got |' + actual + '|' +
', expected |' + expected + '|' + (message ? ' (' + message + ')' : ''));
}
/** id not exists -> should be located at id */
function test_line_column1() {
try {
eval(`'【';A;`);
} catch (e) {
assert(e.lineNumber, 1, 'test_line_column1');
assert(e.columnNumber, 5, 'test_line_column1');
}
}
/**
* memeber call should be located at id:
* a.b.c() and c is null -> c will be located
*/
function test_line_column2() {
try {
eval(`
var a = { b: { c: { d: null }} };
a.b.c.d();
`);
} catch (e) {
assert(e.lineNumber, 3, 'test_line_column2');
assert(e.columnNumber, 7, 'test_line_column2');
}
}
/**
* memeber call should be located at id:
* a.b.c() and b is null -> c will be located
*/
function test_line_column3() {
try {
eval(`
var a = { b: { c: { d: null }} };
a.f.c.d();
`);
} catch (e) {
assert(e.lineNumber, 3, 'test_line_column3');
assert(e.columnNumber, 5, 'test_line_column3');
}
}
/** if id not exists -> should be located at id */
function test_line_column4() {
try {
eval(`(function(){'use strict';a;}());`);
} catch (e) {
assert(e.lineNumber, 1, 'test_line_column4');
assert(e.columnNumber, 26, 'test_line_column4');
}
}
/** if id not exists -> should be located at id */
function test_line_column5() {
try {
eval(`'【';1+1;new A();`);
} catch (e) {
assert(e.lineNumber, 1, 'test_line_column5');
assert(e.columnNumber, 13, 'test_line_column5');
}
}
/** new call should be located at 'new' */
function test_line_column6() {
try {
eval(`'【';1+1;throw new Error();`);
} catch (e) {
assert(e.lineNumber, 1, 'test_line_column6');
assert(e.columnNumber, 15, 'test_line_column6');
}
}
/**
* normal call should be located at function name:
* a() and a is null or occur error -> a will be located
*/
function test_line_column7() {
try {
eval(`1+1;a();`);
} catch (e) {
assert(e.lineNumber, 1, 'test_line_column7');
assert(e.columnNumber, 5, 'test_line_column7');
}
}
/**
* if comment is first line,
* the line number of one line should be locate at next line
*/
function test_line_column8() {
try {
eval(`
/**
* something
* comment
* here
*/
1+1;a();
`);
} catch (e) {
assert(e.lineNumber, 7, 'test_line_column8');
assert(e.columnNumber, 5, 'test_line_column8');
}
}
/** nest function call */
function test_line_column9() {
try {
eval(`(function(){'【'(function(){'use strict';a;}())}())`);
} catch (e) {
assert(e.lineNumber, 1, 'test_line_column9');
assert(e.columnNumber, 41, 'test_line_column9');
}
}
/** multi function call */
function test_line_column10() {
try {
eval(`
function a(){
throw new Error();
}
function b(){
a();
}
b();
`);
} catch (e) {
assert(e.lineNumber, 3, 'test_line_column10');
assert(e.columnNumber, 11, 'test_line_column10');
}
}
/** syntax error should be located at latest token position */
function test_line_column11() {
try {
eval(`
var a = {
b: if(1){}
}
`);
} catch (e) {
assert(e.lineNumber, 3, 'test_line_column11');
assert(e.columnNumber, 7, 'test_line_column11');
}
}
/** string template cases */
function test_line_column12() {
// case 1
try {
eval(`
var a = \`\$\{b;\}
1+1
\`;
`);
} catch (e) {
assert(e.lineNumber, 2, 'test_line_column12');
assert(e.columnNumber, 12, 'test_line_column12');
}
// case 2
try {
eval(`
var a = \`1+1
\$\{b;\}
2+2
\`;
`);
} catch (e) {
assert(e.lineNumber, 3, 'test_line_column12');
assert(e.columnNumber, 3, 'test_line_column12');
}
// case 3
try {
eval(`
var a = \`1+1
2+2
\${b\}\`;
`);
} catch (e) {
assert(e.lineNumber, 4, 'test_line_column12');
assert(e.columnNumber, 3, 'test_line_column12');
}
// case 4
try {
eval(`
var a = \`1+1
2+2
\${3+3\}\`;b;
`);
} catch (e) {
assert(e.lineNumber, 4, 'test_line_column12');
assert(e.columnNumber, 9, 'test_line_column12');
}
}
/** dynamic Function parse error should be located the latest token */
function test_line_column13() {
try {
eval(`Function("===>", "a");`);
} catch (e) {
assert(e.lineNumber, 1, 'test_line_column13');
assert(e.columnNumber, 20, 'test_line_column13');
}
}
test_line_column1();
test_line_column2();
test_line_column3();
test_line_column4();
test_line_column5();
test_line_column6();
test_line_column7();
test_line_column8();
test_line_column9();
test_line_column10();
test_line_column11();
test_line_column12();
test_line_column13();