diff --git a/es2panda/ir/base/classDefinition.cpp b/es2panda/ir/base/classDefinition.cpp index ed8938dd01e0819a34a6be1ecdb061820b56a686..c86648d2e66f9b2bb436580d3def1fe118f9635f 100644 --- a/es2panda/ir/base/classDefinition.cpp +++ b/es2panda/ir/base/classDefinition.cpp @@ -155,6 +155,11 @@ int32_t ClassDefinition::CreateClassStaticProperties(compiler::PandaGen *pg, uti break; } + if (prop->IsAbstract()) { + compiled.Set(i); + continue; + } + util::StringView name = util::Helpers::LiteralToPropName(prop->Key()); compiler::LiteralBuffer *literalBuf = prop->IsStatic() ? &staticBuf : buf; auto &nameMap = prop->IsStatic() ? staticPropNameMap : propNameMap; diff --git a/es2panda/ir/base/methodDefinition.cpp b/es2panda/ir/base/methodDefinition.cpp index 3975b528cac8b290175e887860d96fd3e620ff0f..25c6ab407cae38b5a28a4ab71acb0754e35993c8 100644 --- a/es2panda/ir/base/methodDefinition.cpp +++ b/es2panda/ir/base/methodDefinition.cpp @@ -79,6 +79,7 @@ void MethodDefinition::Dump(ir::AstDumper *dumper) const {"key", key_}, {"kind", kind}, {"accessibility", AstDumper::Optional(AstDumper::ModifierToString(modifiers_))}, + {"abstract", AstDumper::Optional((modifiers_ & ModifierFlags::ABSTRACT) != 0)}, {"static", (modifiers_ & ModifierFlags::STATIC) != 0}, {"optional", (modifiers_ & ModifierFlags::OPTIONAL) != 0}, {"computed", isComputed_}, diff --git a/es2panda/ir/base/methodDefinition.h b/es2panda/ir/base/methodDefinition.h index ff51e020bf4f1d2bee4781ed076ba4c6d2b61a8f..1d3a1e2efa540dffd64cfe902934ac310626cf8f 100644 --- a/es2panda/ir/base/methodDefinition.h +++ b/es2panda/ir/base/methodDefinition.h @@ -91,6 +91,11 @@ public: return isComputed_; } + bool IsAbstract() const + { + return (modifiers_ & ModifierFlags::ABSTRACT) != 0; + } + bool IsStatic() const { return (modifiers_ & ModifierFlags::STATIC) != 0; diff --git a/es2panda/parser/parserImpl.cpp b/es2panda/parser/parserImpl.cpp index 908c246cd9f66f22efcc7a768b0bcadbc23b7f93..c411dbefc67dd48b02b537a7a447b070ff60d29d 100644 --- a/es2panda/parser/parserImpl.cpp +++ b/es2panda/parser/parserImpl.cpp @@ -45,9 +45,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -66,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -169,6 +172,10 @@ void ParserImpl::ParseProgram(ScriptKind kind) lexer_->NextToken(); auto statements = ParseStatementList(StatementParsingFlags::STMT_GLOBAL_LEXICAL); + if (IsDtsFile() && !CheckTopStatementsForRequiredDeclare(statements)) { + ThrowSyntaxError( + "Top-level declarations in .d.ts files must start with either a 'declare' or 'export' modifier."); + } auto *blockStmt = AllocNode(Binder()->GetScope(), std::move(statements)); Binder()->GetScope()->BindNode(blockStmt); @@ -177,6 +184,58 @@ void ParserImpl::ParseProgram(ScriptKind kind) program_.SetAst(blockStmt); } +bool ParserImpl::CheckTopStatementsForRequiredDeclare(const ArenaVector &statements) +{ + for (auto *statement : statements) { + switch (statement->Type()) { + case ir::AstNodeType::TS_INTERFACE_DECLARATION: + case ir::AstNodeType::TS_TYPE_ALIAS_DECLARATION: + case ir::AstNodeType::IMPORT_DECLARATION: + case ir::AstNodeType::TS_IMPORT_EQUALS_DECLARATION: + case ir::AstNodeType::EXPORT_ALL_DECLARATION: + case ir::AstNodeType::EXPORT_DEFAULT_DECLARATION: + case ir::AstNodeType::EXPORT_NAMED_DECLARATION: + case ir::AstNodeType::TS_NAMESPACE_EXPORT_DECLARATION: + continue; + case ir::AstNodeType::CLASS_DECLARATION: { + if (!statement->AsClassDeclaration()->Definition()->Declare()) { + return false; + } + break; + } + case ir::AstNodeType::FUNCTION_DECLARATION: { + if (!statement->AsFunctionDeclaration()->Function()->Declare() && + !statement->AsFunctionDeclaration()->Function()->IsOverload()) { + return false; + } + break; + } + case ir::AstNodeType::VARIABLE_DECLARATION: { + if (!statement->AsVariableDeclaration()->Declare()) { + return false; + } + break; + } + case ir::AstNodeType::TS_MODULE_DECLARATION: { + if (!statement->AsTSModuleDeclaration()->Declare()) { + return false; + } + break; + } + case ir::AstNodeType::TS_ENUM_DECLARATION: { + if (!statement->AsTSEnumDeclaration()->IsDeclare()) { + return false; + } + break; + } + default: + ThrowSyntaxError("Statements are not allowed in ambient contexts."); + UNREACHABLE(); + } + } + return true; +} + /* * Definitions of private methods */ diff --git a/es2panda/parser/parserImpl.h b/es2panda/parser/parserImpl.h index 7b50fd675c3a18b60d8f386ffd6915959f573c88..03288da0b31ebfcdbfbbbbc901e470cf016ace28 100644 --- a/es2panda/parser/parserImpl.h +++ b/es2panda/parser/parserImpl.h @@ -228,6 +228,7 @@ private: void AddCommonjsParams(ArenaVector ¶ms); void AddCommonjsArgs(ArenaVector &args); void ParseProgram(ScriptKind kind); + bool CheckTopStatementsForRequiredDeclare(const ArenaVector &statements); static ExpressionParseFlags CarryExpressionParserFlag(ExpressionParseFlags origin, ExpressionParseFlags carry); static ExpressionParseFlags CarryPatternFlags(ExpressionParseFlags flags); bool CurrentIsBasicType(); diff --git a/es2panda/parser/statementParser.cpp b/es2panda/parser/statementParser.cpp index b9c73c0ad85f75fccc6d04d60996a78efc32f5c3..3ab35b02e0beabcc6d11b47e5a8a0671b0811af9 100644 --- a/es2panda/parser/statementParser.cpp +++ b/es2panda/parser/statementParser.cpp @@ -2512,7 +2512,7 @@ ir::ExportNamedDeclaration *ParserImpl::ParseNamedExportDeclaration(const lexer: break; } case lexer::TokenType::KEYW_CLASS: { - decl = ParseClassDeclaration(true, std::move(decorators), isDeclare, false, !isTsModule); + decl = ParseClassDeclaration(true, std::move(decorators), isDeclare || IsDtsFile(), false, !isTsModule); break; } case lexer::TokenType::LITERAL_IDENT: { diff --git a/es2panda/test/compiler/dts/test-dts-1-expected.txt b/es2panda/test/compiler/dts/test-dts-1-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/es2panda/test/compiler/dts/test-dts-1.d.ts b/es2panda/test/compiler/dts/test-dts-1.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..dfe041495d61c29cc7a8bd87dab930ab33b7f4ef --- /dev/null +++ b/es2panda/test/compiler/dts/test-dts-1.d.ts @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2022 Huawei Device 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. + */ + + +export class A { + test() : number; +} diff --git a/es2panda/test/compiler/ts/cases/conformance/classes/test-ts-classes-9-expected.txt b/es2panda/test/compiler/ts/cases/conformance/classes/test-ts-classes-9-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d --- /dev/null +++ b/es2panda/test/compiler/ts/cases/conformance/classes/test-ts-classes-9-expected.txt @@ -0,0 +1 @@ +1 diff --git a/es2panda/test/compiler/ts/cases/conformance/classes/test-ts-classes-9.ts b/es2panda/test/compiler/ts/cases/conformance/classes/test-ts-classes-9.ts new file mode 100644 index 0000000000000000000000000000000000000000..a61da3518a5d3323fba8289823b0a01ec1cb6868 --- /dev/null +++ b/es2panda/test/compiler/ts/cases/conformance/classes/test-ts-classes-9.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 Huawei Device 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. + */ + + +abstract class A { + abstract test() : number; +} + +class B extends A { + test() : number { + return 1; + } +} + +var b : A = new B(); +print(b.test()); diff --git a/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration-expected.txt b/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..9eaa59407cec4becbc92b030d4485390ec6669c4 --- /dev/null +++ b/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration-expected.txt @@ -0,0 +1,139 @@ +{ + "type": "Program", + "statements": [ + { + "type": "ExportNamedDeclaration", + "declaration": { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "A", + "loc": { + "start": { + "line": 17, + "column": 14 + }, + "end": { + "line": 17, + "column": 15 + } + } + }, + "superClass": null, + "implements": [], + "constructor": { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "constructor", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "kind": "constructor", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": null, + "generator": false, + "async": false, + "expression": false, + "params": [], + "declare": true, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 17, + "column": 18 + } + } + }, + "body": [], + "indexSignatures": [], + "loc": { + "start": { + "line": 17, + "column": 16 + }, + "end": { + "line": 17, + "column": 18 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 8 + }, + "end": { + "line": 17, + "column": 18 + } + } + }, + "source": null, + "specifiers": [], + "loc": { + "start": { + "line": 17, + "column": 1 + }, + "end": { + "line": 17, + "column": 18 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 18, + "column": 1 + } + } +} diff --git a/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration.d.ts b/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..415c0cea6cbaec244d0b8a1797466cc47b848705 --- /dev/null +++ b/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration.d.ts @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 Huawei Device 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. + */ + + +export class A {} diff --git a/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration1-expected.txt b/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration1-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..275199decf50db8267577040cbcbd1b82aff6d1c --- /dev/null +++ b/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration1-expected.txt @@ -0,0 +1 @@ +SyntaxError: Top-level declarations in .d.ts files must start with either a 'declare' or 'export' modifier. [test-export-named-declaration1.d.ts:18:1] diff --git a/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration1.d.ts b/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration1.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..0238c3ad342811c703dcdbe6802a6c03c3f4ca96 --- /dev/null +++ b/es2panda/test/parser/ts/cases/declaration/test-export-named-declaration1.d.ts @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 Huawei Device 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. + */ + + +class A {} diff --git a/es2panda/test/parser/ts/cases/declaration/test-expression-statement-expected.txt b/es2panda/test/parser/ts/cases/declaration/test-expression-statement-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..ca757c365465e5ad448129edb6726a988084d26d --- /dev/null +++ b/es2panda/test/parser/ts/cases/declaration/test-expression-statement-expected.txt @@ -0,0 +1 @@ +SyntaxError: Statements are not allowed in ambient contexts. [test-expression-statement.d.ts:18:1] diff --git a/es2panda/test/parser/ts/cases/declaration/test-expression-statement.d.ts b/es2panda/test/parser/ts/cases/declaration/test-expression-statement.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..859b55cb81caf431cc9450ffeff8397814f40fef --- /dev/null +++ b/es2panda/test/parser/ts/cases/declaration/test-expression-statement.d.ts @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2022 Huawei Device 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. + */ + + +print(1) diff --git a/es2panda/test/parser/ts/cases/declaration/test-namespace-export-declaration-expected.txt b/es2panda/test/parser/ts/cases/declaration/test-namespace-export-declaration-expected.txt index 09e146d85d057f76142551810c0fb3d4ccef9b56..d9d6beb4ed4b4462e098f97256a14b0ee4934794 100644 --- a/es2panda/test/parser/ts/cases/declaration/test-namespace-export-declaration-expected.txt +++ b/es2panda/test/parser/ts/cases/declaration/test-namespace-export-declaration-expected.txt @@ -12,11 +12,11 @@ "name": "isPrime", "loc": { "start": { - "line": 16, + "line": 17, "column": 17 }, "end": { - "line": 16, + "line": 17, "column": 24 } } @@ -32,22 +32,22 @@ "type": "TSNumberKeyword", "loc": { "start": { - "line": 16, + "line": 17, "column": 28 }, "end": { - "line": 16, + "line": 17, "column": 34 } } }, "loc": { "start": { - "line": 16, + "line": 17, "column": 25 }, "end": { - "line": 16, + "line": 17, "column": 26 } } @@ -57,33 +57,33 @@ "type": "TSBooleanKeyword", "loc": { "start": { - "line": 16, + "line": 17, "column": 37 }, "end": { - "line": 16, + "line": 17, "column": 44 } } }, "loc": { "start": { - "line": 16, + "line": 17, "column": 8 }, "end": { - "line": 16, + "line": 17, "column": 45 } } }, "loc": { "start": { - "line": 16, + "line": 17, "column": 8 }, "end": { - "line": 16, + "line": 17, "column": 45 } } @@ -92,11 +92,11 @@ "specifiers": [], "loc": { "start": { - "line": 16, + "line": 17, "column": 1 }, "end": { - "line": 16, + "line": 17, "column": 45 } } @@ -108,22 +108,22 @@ "name": "mathLib", "loc": { "start": { - "line": 17, + "line": 18, "column": 21 }, "end": { - "line": 17, + "line": 18, "column": 28 } } }, "loc": { "start": { - "line": 17, + "line": 18, "column": 1 }, "end": { - "line": 17, + "line": 18, "column": 29 } } @@ -135,7 +135,7 @@ "column": 1 }, "end": { - "line": 17, + "line": 18, "column": 29 } } diff --git a/es2panda/test/parser/ts/cases/declaration/test-namespace-export-declaration.d.ts b/es2panda/test/parser/ts/cases/declaration/test-namespace-export-declaration.d.ts index 79d7ad4637099817981e91d2ae7c7fe951e97be2..54b6d5bd2ed96ab88047a66f5fc171694b6b7f90 100644 --- a/es2panda/test/parser/ts/cases/declaration/test-namespace-export-declaration.d.ts +++ b/es2panda/test/parser/ts/cases/declaration/test-namespace-export-declaration.d.ts @@ -13,5 +13,6 @@ * limitations under the License. */ + export function isPrime(x: number): boolean; export as namespace mathLib; \ No newline at end of file diff --git a/es2panda/test/parser/ts/test-class-definition-expected.txt b/es2panda/test/parser/ts/test-class-definition-expected.txt index 4380377952f38f6399899e13fa600c8443cb9a8f..2e0056d63b9cb65c0d039b89c29bd892ad5a0888 100644 --- a/es2panda/test/parser/ts/test-class-definition-expected.txt +++ b/es2panda/test/parser/ts/test-class-definition-expected.txt @@ -2118,6 +2118,7 @@ } }, "kind": "method", + "abstract": true, "static": false, "optional": false, "computed": false, diff --git a/es2panda/test/parser/ts/test-class-definiton18-expected.txt b/es2panda/test/parser/ts/test-class-definiton18-expected.txt index ccc182e09e64ab24e65bb2eb480b3d5907545d58..05ccf9db3bdfd94b2f4ca349545023d61c6b7e9e 100644 --- a/es2panda/test/parser/ts/test-class-definiton18-expected.txt +++ b/es2panda/test/parser/ts/test-class-definiton18-expected.txt @@ -180,6 +180,7 @@ } }, "kind": "method", + "abstract": true, "static": false, "optional": false, "computed": false, diff --git a/es2panda/test/runner.py b/es2panda/test/runner.py index 20ed0d8f1844c1b44e4036a04c950495c8dc9bfd..8515d2e4e4a7b3cdf04afe145a0bf7e59a9d8ba2 100755 --- a/es2panda/test/runner.py +++ b/es2panda/test/runner.py @@ -148,7 +148,9 @@ class Test: self.reproduce += "\n" + ' '.join(cmd) def get_path_to_expected(self): - return "%s-expected.txt" % (path.splitext(self.path)[0]) + if self.path.find(".d.ts") == -1: + return "%s-expected.txt" % (path.splitext(self.path)[0]) + return "%s-expected.txt" % (self.path[:self.path.find(".d.ts")]) def run(self, runner): cmd = runner.cmd_prefix + [runner.es2panda, "--dump-ast"] @@ -869,6 +871,7 @@ def main(): runner = CompilerRunner(args) runner.add_directory("compiler/js", "js", []) runner.add_directory("compiler/ts", "ts", ["--extension=ts"]) + runner.add_directory("compiler/dts", "d.ts", ["--module", "--extension=ts"]) runners.append(runner)