diff --git a/es2panda/lexer/lexer.cpp b/es2panda/lexer/lexer.cpp index 6ba93184a8ab0b29a85f653806371e3f17bf61f4..cab220dbb139f18dbb5fb01cc5f9966bcc61b11b 100644 --- a/es2panda/lexer/lexer.cpp +++ b/es2panda/lexer/lexer.cpp @@ -204,6 +204,13 @@ void Lexer::ThrowError(std::string_view message) throw es2panda::Error(es2panda::ErrorType::SYNTAX, message, pos_.line, Iterator().Index()); } +void Lexer::ThrowErrorIndex(std::string_view message, size_t index) +{ + lexer::LineIndex lineIndex = parserContext_->GetProgram()->GetLineIndex(); + SourceLocation pos = lineIndex.GetLocation(index); + throw es2panda::Error(es2panda::ErrorType::SYNTAX, message, pos.line, pos.col); +} + void Lexer::CheckNumberLiteralEnd() { if (Iterator().Peek() == LEX_CHAR_LOWERCASE_N) { @@ -1240,6 +1247,13 @@ void Lexer::SkipWhiteSpaces() Iterator().Forward(1); cp = Iterator().Peek(); if (cp == LEX_CHAR_EXCLAMATION) { + if (Iterator().Index() != 1) { + /* + * according to ECMA-262 specification item 12.5 Hashbang Comments are location-sensitive. + * only allowed occurs at the beginning of files, other position is illegal. + */ + ThrowErrorIndex("Invalid or unexpected token", Iterator().Index() - 1); + } Iterator().Forward(1); SkipSingleLineComment(); continue; diff --git a/es2panda/lexer/lexer.h b/es2panda/lexer/lexer.h index 8e56da6ed23d1c25d7e6a9a3cce75474f5087611..5d46e36dd4726b334b40cf91282db96052e0e556 100644 --- a/es2panda/lexer/lexer.h +++ b/es2panda/lexer/lexer.h @@ -99,6 +99,7 @@ private: RegExpFlags ScanRegExpFlags(); void ThrowError(std::string_view message); + void ThrowErrorIndex(std::string_view message, size_t index); void SetTokenStart(); void SetTokenEnd(); diff --git a/es2panda/lexer/token/sourceLocation.cpp b/es2panda/lexer/token/sourceLocation.cpp index 8cb80a458b57af428afa223140b1145cf7b6ec38..8e13aefe7676d8008b4aeff76c74e8f49fc2ba33 100644 --- a/es2panda/lexer/token/sourceLocation.cpp +++ b/es2panda/lexer/token/sourceLocation.cpp @@ -40,6 +40,11 @@ void OffsetEntry::AddCol(size_t offset) } } +size_t OffsetEntry::GetOffset() +{ + return offset_; +} + LineIndex::LineIndex(const util::StringView &source) noexcept { auto iter = util::StringView::Iterator(source); @@ -99,4 +104,17 @@ SourceLocation LineIndex::GetLocation(SourcePosition pos) noexcept return SourceLocation(line + 1, col + 1); } +SourceLocation LineIndex::GetLocation(size_t index) noexcept +{ + SourcePosition sp; + ASSERT(index < entrys_.back().lineStart); // EOF + for (size_t line = 0; line < entrys_.size(); ++line) { + if (index >= entrys_[line].lineStart && index < entrys_[line].GetOffset()) { // line ends with newline punctuator + sp.index = index; + sp.line = line; + break; + } + } + return GetLocation(sp); +} } // namespace panda::es2panda::lexer diff --git a/es2panda/lexer/token/sourceLocation.h b/es2panda/lexer/token/sourceLocation.h index a9c193ed169fe1a4b493fb860f07b10cd849736c..9f1004871a9146c4a37c3466f9e49232e39053f8 100644 --- a/es2panda/lexer/token/sourceLocation.h +++ b/es2panda/lexer/token/sourceLocation.h @@ -87,6 +87,7 @@ public: ~OffsetEntry() = default; void AddCol(size_t offset); + size_t GetOffset(); std::vector ranges {}; size_t lineStart {}; @@ -104,6 +105,7 @@ public: ~LineIndex() = default; SourceLocation GetLocation(SourcePosition pos) noexcept; + SourceLocation GetLocation(size_t index) noexcept; private: std::vector entrys_; diff --git a/es2panda/test/parser/js/test-hashbang-comment-1-expected.txt b/es2panda/test/parser/js/test-hashbang-comment-1-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e9a0690b09bdb9e8b7e146307b994b479183587 --- /dev/null +++ b/es2panda/test/parser/js/test-hashbang-comment-1-expected.txt @@ -0,0 +1,72 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "CallExpression", + "callee": { + "type": "Identifier", + "name": "print", + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 6 + } + } + }, + "arguments": [ + { + "type": "StringLiteral", + "value": "hello world", + "loc": { + "start": { + "line": 18, + "column": 7 + }, + "end": { + "line": 18, + "column": 20 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 21 + } + } + }, + "loc": { + "start": { + "line": 18, + "column": 1 + }, + "end": { + "line": 18, + "column": 21 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 18, + "column": 21 + } + } +} diff --git a/es2panda/test/parser/js/test-hashbang-comment-1.js b/es2panda/test/parser/js/test-hashbang-comment-1.js new file mode 100644 index 0000000000000000000000000000000000000000..68746e07803ffac2f16a429becd63a10019d1d43 --- /dev/null +++ b/es2panda/test/parser/js/test-hashbang-comment-1.js @@ -0,0 +1,18 @@ +#! Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. +/** + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// slash comment +print('hello world') \ No newline at end of file diff --git a/es2panda/test/parser/js/test-hashbang-comment-2-expected.txt b/es2panda/test/parser/js/test-hashbang-comment-2-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb5b1a5c255c74f9c9bb8e6384206c6e9fd8cee5 --- /dev/null +++ b/es2panda/test/parser/js/test-hashbang-comment-2-expected.txt @@ -0,0 +1 @@ +SyntaxError: Invalid or unexpected token [test-hashbang-comment-2.js:16:1] diff --git a/es2panda/test/parser/js/test-hashbang-comment-2.js b/es2panda/test/parser/js/test-hashbang-comment-2.js new file mode 100644 index 0000000000000000000000000000000000000000..c035e60ac92b19f53827daec105bc14eff83293e --- /dev/null +++ b/es2panda/test/parser/js/test-hashbang-comment-2.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#! Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. +// slash comment +print('hello world') \ No newline at end of file diff --git a/es2panda/test/parser/js/test-hashbang-comment-3-expected.txt b/es2panda/test/parser/js/test-hashbang-comment-3-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd7c0a615d368b04a847858c29702ca5ba3412f5 --- /dev/null +++ b/es2panda/test/parser/js/test-hashbang-comment-3-expected.txt @@ -0,0 +1 @@ +SyntaxError: Invalid or unexpected token [test-hashbang-comment-3.js:18:1] diff --git a/es2panda/test/parser/js/test-hashbang-comment-3.js b/es2panda/test/parser/js/test-hashbang-comment-3.js new file mode 100644 index 0000000000000000000000000000000000000000..e91e04fc6c2d41b1567d50f83f47a000a25469d9 --- /dev/null +++ b/es2panda/test/parser/js/test-hashbang-comment-3.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// slash comment +print('hello world') +#! Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd. \ No newline at end of file