diff --git a/src/parseTools.mjs b/src/parseTools.mjs index 786c028d5a902..2b6c3865ee666 100644 --- a/src/parseTools.mjs +++ b/src/parseTools.mjs @@ -331,14 +331,39 @@ function splitI64(value) { export function indentify(text, indent) { // Don't try to indentify huge strings - we may run out of memory if (text.length > 1024 * 1024) return text; - if (typeof indent == 'number') { - const len = indent; - indent = ''; - for (let i = 0; i < len; i++) { - indent += ' '; + + indent = ' '.repeat(indent); + + // Perform indentation in a smart fashion that does not leak indentation + // inside multiline strings enclosed in `` characters. + let out = ''; + for (let i = 0; i < text.length; ++i) { + // Output a C++ comment as-is, don't get confused by ` inside a C++ comment. + if (text[i] == '/' && text[i + 1] == '/') { + for (; i < text.length && text[i] != '\n'; ++i) { + out += text[i]; + } + } + + if (text[i] == '/' && text[i + 1] == '*') { + // Skip /* so that /*/ won't be mistaken as start& end of a /* */ comment. + out += text[i++]; + out += text[i++]; + for (; i < text.length && !(text[i - 1] == '*' && text[i] == '/'); ++i) { + out += text[i]; + } + } + + if (text[i] == '`') { + out += text[i++]; // Emit ` + for (; i < text.length && text[i] != '`'; ++i) { + out += text[i]; + } } + out += text[i]; + if (text[i] == '\n') out += indent; } - return text.replace(/\n/g, `\n${indent}`); + return out; } // Correction tools diff --git a/test/test_multiline_string.c b/test/test_multiline_string.c new file mode 100644 index 0000000000000..d997d69956828 --- /dev/null +++ b/test/test_multiline_string.c @@ -0,0 +1,10 @@ +#include +#include + +char *test_multiline_string(void); + +int main() { + char *str = test_multiline_string(); + printf("%s\n", str); + free(str); +} diff --git a/test/test_multiline_string.js b/test/test_multiline_string.js new file mode 100644 index 0000000000000..d101a6f9b65c8 --- /dev/null +++ b/test/test_multiline_string.js @@ -0,0 +1,15 @@ +mergeInto(LibraryManager.library, { + test_multiline_string__deps: ['$stringToNewUTF8'], + test_multiline_string__sig: 'p', + test_multiline_string: function() { + // do not get confused by ` inside a comment. + var a = `abc +def +ghi`; + /* or a ` inside a C comment. */ + var b = `abc +def +ghi`; + return stringToNewUTF8(a + b); + } +}); diff --git a/test/test_multiline_string.out b/test/test_multiline_string.out new file mode 100644 index 0000000000000..bc7e0a2c6ed6a --- /dev/null +++ b/test/test_multiline_string.out @@ -0,0 +1,5 @@ +abc +def +ghiabc +def +ghi diff --git a/test/test_other.py b/test/test_other.py index f648b5681e4d9..436789efb82f5 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -15283,3 +15283,12 @@ def test_binary_encode(self, extra): console.log('OK');''' write_file('test.js', read_file(path_from_root('src/binaryDecode.js')) + '\nvar src = ' + binary_encoded + ';\n' + test_js) self.assertContained('OK', self.run_js('test.js')) + + # Tests that JS library functions containing multiline strings are not disturbed by e.g. inserting indentation into the output. + @parameterized({ + '': ([],), + 'single_file': (['-sSINGLE_FILE'],), + 'closure': (['--closure', '1'],), + }) + def test_multiline_string(self, args): + self.do_run_in_out_file_test('test_multiline_string.c', cflags=['--js-library', test_file('test_multiline_string.js')] + args)