diff --git a/BUILD.gn b/BUILD.gn index 714417c1643cde5d2652383bd22dcecc36f4186a..8540f61504735a5abcb868745aebc01d57acec22 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -25,8 +25,14 @@ config("libes2panda_public_config") { libes2panda_sources = [ "es2panda.cpp", + "binder/ASBinder.cpp", + "binder/TSBinder.cpp", + "binder/TypedBinder.cpp", + "binder/ETSBinder.cpp", + "binder/JSBinder.cpp", "binder/binder.cpp", "binder/declaration.cpp", + "binder/recordTable.cpp", "binder/scope.cpp", "binder/variable.cpp", "compiler/base/catchTable.cpp", @@ -38,26 +44,36 @@ libes2panda_sources = [ "compiler/base/literals.cpp", "compiler/base/lreference.cpp", "compiler/base/optionalChain.cpp", + "compiler/core/codeGen.cpp", + "compiler/core/compileJob.cpp", "compiler/core/compileQueue.cpp", "compiler/core/compilerContext.cpp", "compiler/core/compilerImpl.cpp", "compiler/core/dynamicContext.cpp", "compiler/core/emitter.cpp", + "compiler/core/JSemitter.cpp", "compiler/core/envScope.cpp", "compiler/core/function.cpp", - "compiler/core/inlineCache.cpp", "compiler/core/labelTarget.cpp", "compiler/core/moduleContext.cpp", "compiler/core/pandagen.cpp", + "compiler/core/programElement.cpp", "compiler/core/regAllocator.cpp", "compiler/core/regScope.cpp", + "compiler/core/regSpiller.cpp", + "compiler/core/ETSemitter.cpp", + "compiler/core/ETSGen.cpp", + "compiler/core/ETSfunction.cpp", "compiler/core/switchBuilder.cpp", + "compiler/core/targetTypeContext.cpp", + "compiler/core/vReg.cpp", "compiler/debugger/debuginfoDumper.cpp", "compiler/function/asyncFunctionBuilder.cpp", "compiler/function/asyncGeneratorFunctionBuilder.cpp", "compiler/function/functionBuilder.cpp", "compiler/function/generatorFunctionBuilder.cpp", "ir/astDump.cpp", + "ir/astNode.cpp", "ir/irnode.cpp", "ir/base/catchClause.cpp", "ir/base/classElement.cpp", @@ -71,6 +87,10 @@ libes2panda_sources = [ "ir/base/scriptFunction.cpp", "ir/base/spreadElement.cpp", "ir/base/templateElement.cpp", + "ir/base/tsIndexSignature.cpp", + "ir/base/tsMethodSignature.cpp", + "ir/base/tsPropertySignature.cpp", + "ir/base/tsSignatureDeclaration.cpp", "ir/expression.cpp", "ir/expressions/arrayExpression.cpp", "ir/expressions/arrowFunctionExpression.cpp", @@ -88,6 +108,7 @@ libes2panda_sources = [ "ir/expressions/literal.cpp", "ir/expressions/literals/bigIntLiteral.cpp", "ir/expressions/literals/booleanLiteral.cpp", + "ir/expressions/literals/charLiteral.cpp", "ir/expressions/literals/nullLiteral.cpp", "ir/expressions/literals/numberLiteral.cpp", "ir/expressions/literals/regExpLiteral.cpp", @@ -113,11 +134,13 @@ libes2panda_sources = [ "ir/module/importNamespaceSpecifier.cpp", "ir/module/importSpecifier.cpp", "ir/statement.cpp", + "ir/statements/assertStatement.cpp", "ir/statements/blockStatement.cpp", "ir/statements/breakStatement.cpp", "ir/statements/classDeclaration.cpp", "ir/statements/continueStatement.cpp", "ir/statements/debuggerStatement.cpp", + "ir/statements/deferStatement.cpp", "ir/statements/doWhileStatement.cpp", "ir/statements/emptyStatement.cpp", "ir/statements/expressionStatement.cpp", @@ -128,9 +151,11 @@ libes2panda_sources = [ "ir/statements/ifStatement.cpp", "ir/statements/labelledStatement.cpp", "ir/statements/loopStatement.cpp", + "ir/statements/panicStatement.cpp", "ir/statements/returnStatement.cpp", "ir/statements/switchCaseStatement.cpp", "ir/statements/switchStatement.cpp", + "ir/statements/trapStatement.cpp", "ir/statements/throwStatement.cpp", "ir/statements/tryStatement.cpp", "ir/statements/variableDeclaration.cpp", @@ -152,7 +177,6 @@ libes2panda_sources = [ "ir/ts/tsFunctionType.cpp", "ir/ts/tsImportEqualsDeclaration.cpp", "ir/ts/tsImportType.cpp", - "ir/ts/tsIndexSignature.cpp", "ir/ts/tsIndexedAccessType.cpp", "ir/ts/tsInferType.cpp", "ir/ts/tsInterfaceBody.cpp", @@ -161,7 +185,6 @@ libes2panda_sources = [ "ir/ts/tsIntersectionType.cpp", "ir/ts/tsLiteralType.cpp", "ir/ts/tsMappedType.cpp", - "ir/ts/tsMethodSignature.cpp", "ir/ts/tsModuleBlock.cpp", "ir/ts/tsModuleDeclaration.cpp", "ir/ts/tsNamedTupleMember.cpp", @@ -172,9 +195,7 @@ libes2panda_sources = [ "ir/ts/tsObjectKeyword.cpp", "ir/ts/tsParameterProperty.cpp", "ir/ts/tsParenthesizedType.cpp", - "ir/ts/tsPropertySignature.cpp", "ir/ts/tsQualifiedName.cpp", - "ir/ts/tsSignatureDeclaration.cpp", "ir/ts/tsStringKeyword.cpp", "ir/ts/tsThisType.cpp", "ir/ts/tsTupleType.cpp", @@ -192,61 +213,116 @@ libes2panda_sources = [ "ir/ts/tsUnionType.cpp", "ir/ts/tsUnknownKeyword.cpp", "ir/ts/tsVoidKeyword.cpp", + "ir/ets/etsClassLiteral.cpp", + "ir/ets/etsNewArrayInstanceExpression.cpp", + "ir/ets/etsNewClassInstanceExpression.cpp", + "ir/ets/etsNewMultiDimArrayInstanceExpression.cpp", + "ir/ets/etsPackageDeclaration.cpp", + "ir/ets/etsPrimitiveType.cpp", + "ir/ets/etsScript.cpp", + "ir/ets/etsTryExpression.cpp", + "ir/ets/etsTypeReference.cpp", + "ir/ets/etsTypeReferencePart.cpp", + "ir/ets/etsWildcardType.cpp", + "lexer/ASLexer.cpp", + "lexer/keywords.cpp", "lexer/keywordsUtil.cpp", "lexer/lexer.cpp", + "lexer/ETSLexer.cpp", + "lexer/TSLexer.cpp", "lexer/regexp/regexp.cpp", + "lexer/token/number.cpp", "lexer/token/sourceLocation.cpp", "lexer/token/token.cpp", "parser/context/classPrivateContext.cpp", "parser/context/parserContext.cpp", "parser/expressionParser.cpp", + "parser/ASparser.cpp", + "parser/JSparser.cpp", "parser/parserImpl.cpp", + "parser/ETSparser.cpp", + "parser/TSparser.cpp", + "parser/TypedParser.cpp", "parser/program/program.cpp", "parser/statementParser.cpp", - "typescript/checker.cpp", - "typescript/core/binaryLikeExpression.cpp", - "typescript/core/checkerContext.cpp", - "typescript/core/destructuringContext.cpp", - "typescript/core/function.cpp", - "typescript/core/helpers.cpp", - "typescript/core/object.cpp", - "typescript/core/typeCreation.cpp", - "typescript/core/typeElaborationContext.cpp", - "typescript/core/typeRelation.cpp", - "typescript/core/util.cpp", - "typescript/types/anyType.cpp", - "typescript/types/arrayType.cpp", - "typescript/types/bigintLiteralType.cpp", - "typescript/types/bigintType.cpp", - "typescript/types/booleanLiteralType.cpp", - "typescript/types/booleanType.cpp", - "typescript/types/constructorType.cpp", - "typescript/types/enumLiteralType.cpp", - "typescript/types/enumType.cpp", - "typescript/types/functionType.cpp", - "typescript/types/globalTypesHolder.cpp", - "typescript/types/indexInfo.cpp", - "typescript/types/interfaceType.cpp", - "typescript/types/neverType.cpp", - "typescript/types/nonPrimitiveType.cpp", - "typescript/types/nullType.cpp", - "typescript/types/numberLiteralType.cpp", - "typescript/types/numberType.cpp", - "typescript/types/objectDescriptor.cpp", - "typescript/types/objectLiteralType.cpp", - "typescript/types/objectType.cpp", - "typescript/types/signature.cpp", - "typescript/types/stringLiteralType.cpp", - "typescript/types/stringType.cpp", - "typescript/types/tupleType.cpp", - "typescript/types/type.cpp", - "typescript/types/typeParameter.cpp", - "typescript/types/typeReference.cpp", - "typescript/types/typeRelation.cpp", - "typescript/types/undefinedType.cpp", - "typescript/types/unionType.cpp", - "typescript/types/unknownType.cpp", - "typescript/types/voidType.cpp", + "checker/checker.cpp", + "checker/checkerContext.cpp", + "checker/ETSchecker.cpp", + "checker/TSchecker.cpp", + "checker/ASchecker.cpp", + "checker/JSchecker.cpp", + "checker/ets/aliveAnalyzer.cpp", + "checker/ets/arithmetic.cpp", + "checker/ets/baseAnalyzer.cpp", + "checker/ets/boxingConverter.cpp", + "checker/ets/function.cpp", + "checker/ets/helpers.cpp", + "checker/ets/narrowingConverter.cpp", + "checker/ets/narrowingWideningConverter.cpp", + "checker/ets/object.cpp", + "checker/ets/primitiveWrappers.cpp", + "checker/ets/typeConverter.cpp", + "checker/ets/typeCreation.cpp", + "checker/ets/typeRelationContext.cpp", + "checker/ets/unboxingConverter.cpp", + "checker/ets/wideningConverter.cpp", + "checker/ts/binaryLikeExpression.cpp", + "checker/ts/destructuringContext.cpp", + "checker/ts/function.cpp", + "checker/ts/helpers.cpp", + "checker/ts/object.cpp", + "checker/ts/typeCreation.cpp", + "checker/ts/typeElaborationContext.cpp", + "checker/ts/util.cpp", + "checker/types/signature.cpp", + "checker/types/type.cpp", + "checker/types/typeRelation.cpp", + "checker/types/globalTypesHolder.cpp", + "checker/types/ets/byteType.cpp", + "checker/types/ets/charType.cpp", + "checker/types/ets/doubleType.cpp", + "checker/types/ets/floatType.cpp", + "checker/types/ets/intType.cpp", + "checker/types/ets/longType.cpp", + "checker/types/ets/shortType.cpp", + "checker/types/ets/etsArrayType.cpp", + "checker/types/ets/etsBooleanType.cpp", + "checker/types/ets/etsFunctionType.cpp", + "checker/types/ets/etsObjectType.cpp", + "checker/types/ets/etsStringType.cpp", + "checker/types/ets/etsTypeParameter.cpp", + "checker/types/ets/etsTypeReference.cpp", + "checker/types/ets/etsVoidType.cpp", + "checker/types/ets/wildcardType.cpp", + "checker/types/ts/anyType.cpp", + "checker/types/ts/arrayType.cpp", + "checker/types/ts/bigintLiteralType.cpp", + "checker/types/ts/bigintType.cpp", + "checker/types/ts/booleanLiteralType.cpp", + "checker/types/ts/booleanType.cpp", + "checker/types/ts/constructorType.cpp", + "checker/types/ts/enumLiteralType.cpp", + "checker/types/ts/enumType.cpp", + "checker/types/ts/functionType.cpp", + "checker/types/ts/indexInfo.cpp", + "checker/types/ts/interfaceType.cpp", + "checker/types/ts/neverType.cpp", + "checker/types/ts/nonPrimitiveType.cpp", + "checker/types/ts/nullType.cpp", + "checker/types/ts/numberLiteralType.cpp", + "checker/types/ts/numberType.cpp", + "checker/types/ts/objectDescriptor.cpp", + "checker/types/ts/objectLiteralType.cpp", + "checker/types/ts/objectType.cpp", + "checker/types/ts/stringLiteralType.cpp", + "checker/types/ts/stringType.cpp", + "checker/types/ts/tupleType.cpp", + "checker/types/ts/typeParameter.cpp", + "checker/types/ts/typeReference.cpp", + "checker/types/ts/undefinedType.cpp", + "checker/types/ts/unionType.cpp", + "checker/types/ts/unknownType.cpp", + "checker/types/ts/voidType.cpp", "util/bitset.cpp", "util/helpers.cpp", "util/ustring.cpp", @@ -277,8 +353,7 @@ ohos_shared_library("libes2panda") { deps = [ ":isa_gen_es2panda_isa_h", ":isa_gen_es2panda_formats_h", - ":es2panda_lexer_keywords_h", - ":es2panda_lexer_keywords_map_h", + ":gen_es2panda_keywords_h", "$ark_root/assembler:libarkassembler", "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", @@ -299,8 +374,8 @@ ohos_static_library("libes2panda_frontend_static") { deps = [ ":isa_gen_es2panda_isa_h", ":isa_gen_es2panda_formats_h", - ":es2panda_lexer_keywords_h", - ":es2panda_lexer_keywords_map_h", + ":gen_es2panda_lexer_keywords_h", + ":gen_es2panda_compiler_signatures_h", "$ark_root/assembler:libarkassembler_frontend_static", "$ark_root/libpandabase:libarkbase_frontend_static", "$ark_root/libpandafile:libarkfile_frontend_static", @@ -318,20 +393,26 @@ ark_isa_gen("isa_gen_es2panda") { destination = "$target_gen_dir/generated" } -action("es2panda_lexer_keywords_h") { - script = "lexer/scripts/keywords.rb" - outputs = [ "$target_gen_dir/generated/keywords.h" ] - args = [ - rebase_path("lexer/templates/keywords.h.erb", root_build_dir), - rebase_path("$target_gen_dir/generated/keywords.h", root_build_dir), +ark_gen("gen_es2panda_lexer") { + data = "lexer/scripts/keywords.yaml" + template_files = [ + "keywords.h.erb", + ] + sources = "lexer/templates" + destination = "$target_gen_dir/generated" + requires = [ + "lexer/scripts/keywords.rb", ] } -action("es2panda_lexer_keywords_map_h") { - script = "lexer/scripts/keywords.rb" - outputs = [ "$target_gen_dir/generated/keywordsMap.h" ] - args = [ - rebase_path("lexer/templates/keywordsMap.h.erb", root_build_dir), - rebase_path("$target_gen_dir/generated/keywordsMap.h", root_build_dir), +ark_gen("gen_es2panda_compiler") { + data = "compiler/scripts/signatures.yaml" + template_files = [ + "signatures.h.erb", + ] + sources = "compiler/templates" + destination = "$target_gen_dir/generated" + requires = [ + "compiler/scripts/signatures.rb", ] } diff --git a/CMakeLists.txt b/CMakeLists.txt index 3113e256fd9fb475c49ec6cbdf259d02c3e48897..571b9611675b8b40a37572c7d2486d8f8970ade3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,6 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) set(GENERATED_DIR ${OUTPUT_DIR}/generated) set(GENERATED_STAMP ${OUTPUT_DIR}/gen_dir.stamp) -add_custom_target(es2panda-gen) add_custom_command( OUTPUT ${GENERATED_STAMP} @@ -40,35 +39,36 @@ panda_isa_gen( EXTRA_DEPENDENCIES ${GENERATED_STAMP} ) -add_dependencies(es2panda-gen isa_gen_es2panda) - -function(gen_keywords TEMPLATE OUT_DIR) - set(TEMPLATE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/lexer/templates/${TEMPLATE}) - - string(REGEX REPLACE "\.erb$" "" NAME ${TEMPLATE}) - string(REPLACE "\." "_" CUSTOM_TARGET ${NAME}) - string(REPLACE "/" "_" CUSTOM_TARGET ${CUSTOM_TARGET}) - set(CUSTOM_TARGET "panda_es2panda_parser_gen_${CUSTOM_TARGET}") - - set(OUT_FILE ${OUT_DIR}/${NAME}) - set(GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/lexer/scripts/keywords.rb) - - add_custom_command(OUTPUT ${OUT_FILE} - COMMAND ruby ${GENERATOR} ${TEMPLATE_FILE} ${OUT_FILE} - DEPENDS ${GENERATED_STAMP} ${GENERATOR} ${TEMPLATE_FILE} - ) - - add_custom_target(${CUSTOM_TARGET} DEPENDS ${OUT_FILE}) - add_dependencies(es2panda-gen ${CUSTOM_TARGET}) -endfunction() +panda_gen( + DATA ${CMAKE_CURRENT_SOURCE_DIR}/lexer/scripts/keywords.yaml + TARGET_NAME es2panda_keywords + TEMPLATES keywords.h.erb + REQUIRES + ${CMAKE_CURRENT_SOURCE_DIR}/lexer/scripts/keywords.rb + SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lexer/templates + DESTINATION ${GENERATED_DIR} +) -gen_keywords(keywords.h.erb ${GENERATED_DIR}) -gen_keywords(keywordsMap.h.erb ${GENERATED_DIR}) +panda_gen( + DATA ${CMAKE_CURRENT_SOURCE_DIR}/compiler/scripts/signatures.yaml + TARGET_NAME es2panda_signatures + TEMPLATES signatures.h.erb + REQUIRES + ${CMAKE_CURRENT_SOURCE_DIR}/compiler/scripts/signatures.rb + SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/compiler/templates + DESTINATION ${GENERATED_DIR} +) set(ES2PANDA_LIB_SRC es2panda.cpp + binder/ASBinder.cpp + binder/TSBinder.cpp + binder/TypedBinder.cpp + binder/ETSBinder.cpp + binder/JSBinder.cpp binder/binder.cpp binder/declaration.cpp + binder/recordTable.cpp binder/scope.cpp binder/variable.cpp compiler/base/catchTable.cpp @@ -80,26 +80,36 @@ set(ES2PANDA_LIB_SRC compiler/base/literals.cpp compiler/base/lreference.cpp compiler/base/optionalChain.cpp + compiler/core/codeGen.cpp + compiler/core/compileJob.cpp compiler/core/compileQueue.cpp compiler/core/compilerContext.cpp compiler/core/compilerImpl.cpp compiler/core/dynamicContext.cpp compiler/core/emitter.cpp + compiler/core/JSemitter.cpp compiler/core/envScope.cpp compiler/core/function.cpp - compiler/core/inlineCache.cpp compiler/core/labelTarget.cpp compiler/core/moduleContext.cpp compiler/core/pandagen.cpp + compiler/core/programElement.cpp compiler/core/regAllocator.cpp compiler/core/regScope.cpp + compiler/core/regSpiller.cpp + compiler/core/ETSemitter.cpp + compiler/core/ETSGen.cpp + compiler/core/ETSfunction.cpp compiler/core/switchBuilder.cpp + compiler/core/targetTypeContext.cpp + compiler/core/vReg.cpp compiler/debugger/debuginfoDumper.cpp compiler/function/asyncFunctionBuilder.cpp compiler/function/asyncGeneratorFunctionBuilder.cpp compiler/function/functionBuilder.cpp compiler/function/generatorFunctionBuilder.cpp ir/astDump.cpp + ir/astNode.cpp ir/irnode.cpp ir/base/catchClause.cpp ir/base/classElement.cpp @@ -113,6 +123,10 @@ set(ES2PANDA_LIB_SRC ir/base/scriptFunction.cpp ir/base/spreadElement.cpp ir/base/templateElement.cpp + ir/base/tsIndexSignature.cpp + ir/base/tsMethodSignature.cpp + ir/base/tsPropertySignature.cpp + ir/base/tsSignatureDeclaration.cpp ir/expression.cpp ir/expressions/arrayExpression.cpp ir/expressions/arrowFunctionExpression.cpp @@ -130,6 +144,7 @@ set(ES2PANDA_LIB_SRC ir/expressions/literal.cpp ir/expressions/literals/bigIntLiteral.cpp ir/expressions/literals/booleanLiteral.cpp + ir/expressions/literals/charLiteral.cpp ir/expressions/literals/nullLiteral.cpp ir/expressions/literals/numberLiteral.cpp ir/expressions/literals/regExpLiteral.cpp @@ -155,11 +170,13 @@ set(ES2PANDA_LIB_SRC ir/module/importNamespaceSpecifier.cpp ir/module/importSpecifier.cpp ir/statement.cpp + ir/statements/assertStatement.cpp ir/statements/blockStatement.cpp ir/statements/breakStatement.cpp ir/statements/classDeclaration.cpp ir/statements/continueStatement.cpp ir/statements/debuggerStatement.cpp + ir/statements/deferStatement.cpp ir/statements/doWhileStatement.cpp ir/statements/emptyStatement.cpp ir/statements/expressionStatement.cpp @@ -170,16 +187,29 @@ set(ES2PANDA_LIB_SRC ir/statements/ifStatement.cpp ir/statements/labelledStatement.cpp ir/statements/loopStatement.cpp + ir/statements/panicStatement.cpp ir/statements/returnStatement.cpp ir/statements/switchCaseStatement.cpp ir/statements/switchStatement.cpp ir/statements/throwStatement.cpp + ir/statements/trapStatement.cpp ir/statements/tryStatement.cpp ir/statements/variableDeclaration.cpp ir/statements/variableDeclarator.cpp ir/statements/whileStatement.cpp ir/as/namedType.cpp ir/as/prefixAssertionExpression.cpp + ir/ets/etsClassLiteral.cpp + ir/ets/etsNewArrayInstanceExpression.cpp + ir/ets/etsNewClassInstanceExpression.cpp + ir/ets/etsNewMultiDimArrayInstanceExpression.cpp + ir/ets/etsPackageDeclaration.cpp + ir/ets/etsPrimitiveType.cpp + ir/ets/etsScript.cpp + ir/ets/etsTryExpression.cpp + ir/ets/etsTypeReference.cpp + ir/ets/etsTypeReferencePart.cpp + ir/ets/etsWildcardType.cpp ir/ts/tsAnyKeyword.cpp ir/ts/tsArrayType.cpp ir/ts/tsAsExpression.cpp @@ -194,7 +224,6 @@ set(ES2PANDA_LIB_SRC ir/ts/tsFunctionType.cpp ir/ts/tsImportEqualsDeclaration.cpp ir/ts/tsImportType.cpp - ir/ts/tsIndexSignature.cpp ir/ts/tsIndexedAccessType.cpp ir/ts/tsInferType.cpp ir/ts/tsInterfaceBody.cpp @@ -203,7 +232,6 @@ set(ES2PANDA_LIB_SRC ir/ts/tsIntersectionType.cpp ir/ts/tsLiteralType.cpp ir/ts/tsMappedType.cpp - ir/ts/tsMethodSignature.cpp ir/ts/tsModuleBlock.cpp ir/ts/tsModuleDeclaration.cpp ir/ts/tsNamedTupleMember.cpp @@ -214,9 +242,7 @@ set(ES2PANDA_LIB_SRC ir/ts/tsObjectKeyword.cpp ir/ts/tsParameterProperty.cpp ir/ts/tsParenthesizedType.cpp - ir/ts/tsPropertySignature.cpp ir/ts/tsQualifiedName.cpp - ir/ts/tsSignatureDeclaration.cpp ir/ts/tsStringKeyword.cpp ir/ts/tsThisType.cpp ir/ts/tsTupleType.cpp @@ -234,68 +260,112 @@ set(ES2PANDA_LIB_SRC ir/ts/tsUnionType.cpp ir/ts/tsUnknownKeyword.cpp ir/ts/tsVoidKeyword.cpp + lexer/ASLexer.cpp + lexer/keywords.cpp lexer/keywordsUtil.cpp lexer/lexer.cpp + lexer/ETSLexer.cpp + lexer/TSLexer.cpp lexer/regexp/regexp.cpp + lexer/token/number.cpp lexer/token/sourceLocation.cpp lexer/token/token.cpp parser/context/classPrivateContext.cpp parser/context/parserContext.cpp parser/expressionParser.cpp + parser/ASparser.cpp + parser/JSparser.cpp parser/parserImpl.cpp + parser/ETSparser.cpp + parser/TSparser.cpp + parser/TypedParser.cpp parser/program/program.cpp parser/statementParser.cpp - typescript/checker.cpp - typescript/core/binaryLikeExpression.cpp - typescript/core/checkerContext.cpp - typescript/core/destructuringContext.cpp - typescript/core/function.cpp - typescript/core/helpers.cpp - typescript/core/object.cpp - typescript/core/typeCreation.cpp - typescript/core/typeElaborationContext.cpp - typescript/core/typeRelation.cpp - typescript/core/util.cpp - typescript/types/anyType.cpp - typescript/types/arrayType.cpp - typescript/types/bigintLiteralType.cpp - typescript/types/bigintType.cpp - typescript/types/booleanLiteralType.cpp - typescript/types/booleanType.cpp - typescript/types/constructorType.cpp - typescript/types/enumLiteralType.cpp - typescript/types/enumType.cpp - typescript/types/functionType.cpp - typescript/types/globalTypesHolder.cpp - typescript/types/indexInfo.cpp - typescript/types/interfaceType.cpp - typescript/types/neverType.cpp - typescript/types/nonPrimitiveType.cpp - typescript/types/nullType.cpp - typescript/types/numberLiteralType.cpp - typescript/types/numberType.cpp - typescript/types/objectDescriptor.cpp - typescript/types/objectLiteralType.cpp - typescript/types/objectType.cpp - typescript/types/signature.cpp - typescript/types/stringLiteralType.cpp - typescript/types/stringType.cpp - typescript/types/tupleType.cpp - typescript/types/type.cpp - typescript/types/typeParameter.cpp - typescript/types/typeReference.cpp - typescript/types/typeRelation.cpp - typescript/types/undefinedType.cpp - typescript/types/unionType.cpp - typescript/types/unknownType.cpp - typescript/types/voidType.cpp + checker/checker.cpp + checker/checkerContext.cpp + checker/ETSchecker.cpp + checker/TSchecker.cpp + checker/ASchecker.cpp + checker/JSchecker.cpp + checker/ets/aliveAnalyzer.cpp + checker/ets/arithmetic.cpp + checker/ets/baseAnalyzer.cpp + checker/ets/boxingConverter.cpp + checker/ets/function.cpp + checker/ets/helpers.cpp + checker/ets/narrowingConverter.cpp + checker/ets/narrowingWideningConverter.cpp + checker/ets/object.cpp + checker/ets/primitiveWrappers.cpp + checker/ets/typeConverter.cpp + checker/ets/typeCreation.cpp + checker/ets/typeRelationContext.cpp + checker/ets/unboxingConverter.cpp + checker/ets/wideningConverter.cpp + checker/ts/binaryLikeExpression.cpp + checker/ts/destructuringContext.cpp + checker/ts/function.cpp + checker/ts/helpers.cpp + checker/ts/object.cpp + checker/ts/typeCreation.cpp + checker/ts/typeElaborationContext.cpp + checker/ts/util.cpp + checker/types/signature.cpp + checker/types/type.cpp + checker/types/typeRelation.cpp + checker/types/globalTypesHolder.cpp + checker/types/ets/byteType.cpp + checker/types/ets/charType.cpp + checker/types/ets/doubleType.cpp + checker/types/ets/floatType.cpp + checker/types/ets/intType.cpp + checker/types/ets/longType.cpp + checker/types/ets/shortType.cpp + checker/types/ets/etsArrayType.cpp + checker/types/ets/etsBooleanType.cpp + checker/types/ets/etsFunctionType.cpp + checker/types/ets/etsObjectType.cpp + checker/types/ets/etsStringType.cpp + checker/types/ets/etsTypeParameter.cpp + checker/types/ets/etsTypeReference.cpp + checker/types/ets/etsVoidType.cpp + checker/types/ets/wildcardType.cpp + checker/types/ts/anyType.cpp + checker/types/ts/arrayType.cpp + checker/types/ts/bigintLiteralType.cpp + checker/types/ts/bigintType.cpp + checker/types/ts/booleanLiteralType.cpp + checker/types/ts/booleanType.cpp + checker/types/ts/constructorType.cpp + checker/types/ts/enumLiteralType.cpp + checker/types/ts/enumType.cpp + checker/types/ts/functionType.cpp + checker/types/ts/indexInfo.cpp + checker/types/ts/interfaceType.cpp + checker/types/ts/neverType.cpp + checker/types/ts/nonPrimitiveType.cpp + checker/types/ts/nullType.cpp + checker/types/ts/numberLiteralType.cpp + checker/types/ts/numberType.cpp + checker/types/ts/objectDescriptor.cpp + checker/types/ts/objectLiteralType.cpp + checker/types/ts/objectType.cpp + checker/types/ts/stringLiteralType.cpp + checker/types/ts/stringType.cpp + checker/types/ts/tupleType.cpp + checker/types/ts/typeParameter.cpp + checker/types/ts/typeReference.cpp + checker/types/ts/undefinedType.cpp + checker/types/ts/unionType.cpp + checker/types/ts/unknownType.cpp + checker/types/ts/voidType.cpp util/bitset.cpp util/helpers.cpp util/ustring.cpp ) add_library(es2panda-lib ${PANDA_DEFAULT_LIB_TYPE} ${ES2PANDA_LIB_SRC}) -add_dependencies(es2panda-lib es2panda-gen) +add_dependencies(es2panda-lib isa_gen_es2panda es2panda_keywords es2panda_signatures) set(ICU_INCLUDE_DIRS ${PANDA_THIRD_PARTY_SOURCES_DIR}/icu/icu4c/source/common diff --git a/LICENSE-2.0.txt b/LICENSE-2.0.txt index 30e57694c9aef46e1f39a4293c89be4fc3ed906d..84e598348fac7d4aa58758472f15710f77306f15 100644 --- a/LICENSE-2.0.txt +++ b/LICENSE-2.0.txt @@ -54,7 +54,7 @@ the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, + communication on electronic mailing liets, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise diff --git a/README.md b/README.md index 1ae69d9bc615a6bd74dcd3ecf9ea2e786862a74f..dec035d94f99471a4b4bebef24d77f502e01b4af 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ es2panda [OPTIONS] [input file] -- [arguments] ## Tail arguments - `input`: input file -## Running the tests +## Running the teets ```sh pip install tqdm dataclasses python-dotenv ``` @@ -36,8 +36,6 @@ python3 test/runner/runner.py [OPTIONS] [build_directory] - `--regression`: Run regression tests - `--test262`: Run test262. To run tests from test262 set specify environment variables `TEST262_REVISION` and `TEST262_URL` in the `.env` file. - `--hermes`: Run Hermes runtime tests. To run tests from hermes set specify environment variables `HERMES_REVISION` and `HERMES_URL` in the `.env` file. - -#### Extra arguments - `--no-progress`: Don't show progress bar - `--verbose`: Generates more detailed output diff --git a/aot/main.cpp b/aot/main.cpp index 778d36a769bf0efb6d4c64bc301afb63555d1c52..7d81cf963a134af51ca5dda1660e4795b0708a82 100644 --- a/aot/main.cpp +++ b/aot/main.cpp @@ -63,13 +63,12 @@ static int GenerateProgram(panda::pandasm::Program *prog, const Options *options panda::Logger::InitializeStdLogging(Logger::LevelFromString(options->LogLevel()), componentMask); if (!panda::pandasm::AsmEmitter::Emit(options->CompilerOutput(), *prog, statp, mapsp, true)) { + std::cerr << "Failed to emit binary data: " << panda::pandasm::AsmEmitter::GetLastError() << std::endl; return 1; } panda::bytecodeopt::OPTIONS.SetOptLevel(options->OptLevel()); - // Set default value instead of maximum set in panda::bytecodeopt::SetCompilerOptions() - panda::compiler::OPTIONS.SetCompilerMaxBytecodeSize(panda::compiler::OPTIONS.GetCompilerMaxBytecodeSize()); - panda::bytecodeopt::OptimizeBytecode(prog, mapsp, options->CompilerOutput(), true, true); + panda::bytecodeopt::OptimizeBytecode(prog, mapsp, options->CompilerOutput(), options->IsDynamic(), true); } #endif @@ -83,6 +82,7 @@ static int GenerateProgram(panda::pandasm::Program *prog, const Options *options } if (!panda::pandasm::AsmEmitter::Emit(options->CompilerOutput(), *prog, statp, mapsp, true)) { + std::cerr << "Failed to emit binary data: " << panda::pandasm::AsmEmitter::GetLastError() << std::endl; return 1; } @@ -118,10 +118,18 @@ int Run(int argc, const char **argv) return 1; } + std::string_view sourceFile, parserInput; + if (options->CompilerOptions().genStdLib) { + sourceFile = "etsstdlib.ets"; + parserInput = ""; + } else { + sourceFile = options->SourceFile(); + parserInput = options->ParserInput(); + } es2panda::Compiler compiler(options->Extension(), options->ThreadCount()); - es2panda::SourceFile input(options->SourceFile(), options->ParserInput(), options->ParseModule()); + es2panda::SourceFile input(sourceFile, parserInput, options->ParseModule()); - auto *program = compiler.Compile(input, options->CompilerOptions()); + auto program = std::unique_ptr {compiler.Compile(input, options->CompilerOptions())}; if (program == nullptr) { const auto &err = compiler.GetError(); @@ -131,15 +139,13 @@ int Run(int argc, const char **argv) } std::cout << err.TypeString() << ": " << err.Message(); - std::cout << " [" << options->SourceFile() << ":" << err.Line() << ":" << err.Col() << "]" << std::endl; + std::cout << " [" << (err.File().empty() ? options->SourceFile() : err.File()) << ":" << err.Line() << ":" + << err.Col() << "]" << std::endl; return err.ErrorCode(); } - GenerateProgram(program, options.get()); - delete program; - - return 0; + return GenerateProgram(program.get(), options.get()); } } // namespace panda::es2panda::aot diff --git a/aot/options.cpp b/aot/options.cpp index fbce88d98b691b953203466560151bd1d307e1c3..523533b6b4f707ca330a9ed25fdbe3d006b10423 100644 --- a/aot/options.cpp +++ b/aot/options.cpp @@ -48,7 +48,7 @@ bool Options::Parse(int argc, const char **argv) // parser panda::PandArg inputExtension("extension", "js", - "Parse the input as the given extension (options: js | ts | as)"); + "Parse the input as the given extension (options: js | ts | as | ets)"); panda::PandArg opModule("module", false, "Parse the input as module"); panda::PandArg opParseOnly("parse-only", false, "Parse the input only"); panda::PandArg opDumpAst("dump-ast", false, "Dump the parsed AST"); @@ -64,6 +64,8 @@ bool Options::Parse(int argc, const char **argv) panda::PandArg opSizeStat("dump-size-stat", false, "Dump size statistics"); panda::PandArg outputFile("output", "", "Compiler binary output (.abc)"); panda::PandArg logLevel("log-level", "error", "Log-level"); + panda::PandArg stdLib("stdlib", "", "Path to standard library"); + panda::PandArg genStdLib("gen-stdlib", false, "Gen standard library"); // tail arguments panda::PandArg inputFile("input", "", "input file"); @@ -83,6 +85,8 @@ bool Options::Parse(int argc, const char **argv) argparser_->Add(&inputExtension); argparser_->Add(&outputFile); argparser_->Add(&logLevel); + argparser_->Add(&stdLib); + argparser_->Add(&genStdLib); argparser_->PushBackTail(&inputFile); argparser_->EnableTail(); @@ -137,8 +141,10 @@ bool Options::Parse(int argc, const char **argv) extension_ = es2panda::ScriptExtension::TS; } else if (extension == "as") { extension_ = es2panda::ScriptExtension::AS; + } else if (extension == "ets") { + extension_ = es2panda::ScriptExtension::ETS; } else { - errorMsg_ = "Invalid extension (available options: js, ts, as)"; + errorMsg_ = "Invalid extension (available options: js, ts, as, ets)"; return false; } } @@ -163,6 +169,8 @@ bool Options::Parse(int argc, const char **argv) compilerOptions_.dumpDebugInfo = opDumpDebugInfo.GetValue(); compilerOptions_.isDebug = opDebugInfo.GetValue(); compilerOptions_.parseOnly = opParseOnly.GetValue(); + compilerOptions_.stdLib = stdLib.GetValue(); + compilerOptions_.genStdLib = genStdLib.GetValue(); return true; } diff --git a/aot/options.h b/aot/options.h index a3d7d2f0ac44981ca68b0021ca6cc048f351b1eb..9da34c61fc3aa24809b69efb835b3a91ff23344c 100644 --- a/aot/options.h +++ b/aot/options.h @@ -119,6 +119,11 @@ public: return (options_ & OptionFlags::SIZE_STAT) != 0; } + bool IsDynamic() const + { + return extension_ != es2panda::ScriptExtension::ETS; + } + private: es2panda::ScriptExtension extension_ {es2panda::ScriptExtension::JS}; es2panda::CompilerOptions compilerOptions_ {}; diff --git a/binder/ASBinder.cpp b/binder/ASBinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a58d1c3e7dbad3a0c7c0240500a98935482e3ad --- /dev/null +++ b/binder/ASBinder.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "ASBinder.h" + +namespace panda::es2panda::binder { +} // namespace panda::es2panda::binder diff --git a/binder/ASBinder.h b/binder/ASBinder.h new file mode 100644 index 0000000000000000000000000000000000000000..ac6c8b22ec9131397f9e5ddee1698e714c907080 --- /dev/null +++ b/binder/ASBinder.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_BINDER_AS_BINDER_H +#define ES2PANDA_BINDER_AS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/binder.h" + +namespace panda::es2panda::binder { +class ASBinder : public Binder { +public: + explicit ASBinder(ArenaAllocator *allocator) : Binder(allocator) {} + + NO_COPY_SEMANTIC(ASBinder); + NO_MOVE_SEMANTIC(ASBinder); + ~ASBinder() = default; + + ScriptExtension Extension() const override + { + return ScriptExtension::AS; + } + + ResolveBindingOptions BindingOptions() const override + { + return ResolveBindingOptions::BINDINGS; + } + + void IdentifierAnalysis() override {} + +private: +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/ETSBinder.cpp b/binder/ETSBinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa5ec439033191a9caf1023444a276c3a3a142d0 --- /dev/null +++ b/binder/ETSBinder.cpp @@ -0,0 +1,563 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "ETSBinder.h" + +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/thisExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/functionExpression.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classElement.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/classStaticBlock.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" +#include "plugins/ecmascript/es2panda/ir/statements/functionDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/returnStatement.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsPrimitiveType.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReferencePart.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterInstantiation.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsClassImplements.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceHeritage.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceBody.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsQualifiedName.h" +#include "plugins/ecmascript/es2panda/ir/module/importDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/module/importSpecifier.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" + +namespace panda::es2panda::binder { + +void ETSBinder::IdentifierAnalysis() +{ + ASSERT(program_->Ast()); + ASSERT(scope_ == topScope_); + ASSERT(varScope_ == topScope_); + + recordTable_->SetProgram(program_); + globalRecordTable_.SetClassDefinition(program_->GlobalClass()); + externalRecordTable_.insert({program_, &globalRecordTable_}); + + BuildProgram(); + + ASSERT(globalRecordTable_.ClassDefinition() == program_->GlobalClass()); +} + +void ETSBinder::LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef) +{ + auto *iter = typeRef->Part(); + + while (iter) { + if (!iter->TypeParams()) { + iter = iter->Previous(); + continue; + } + + for (auto *it : iter->TypeParams()->Params()) { + if (!it->IsETSTypeReference()) { + continue; + } + + ResolveReference(it); + } + + iter = iter->Previous(); + } +} + +void ETSBinder::LookupTypeReference(ir::Identifier *ident) +{ + const auto &name = ident->Name(); + auto *iter = scope_; + + while (iter) { + ScopeFindResult res = iter->Find(name, BindingOptions()); + + if (!res.variable) { + break; + } + + switch (res.variable->Declaration()->Node()->Type()) { + case ir::AstNodeType::TS_INTERFACE_DECLARATION: + case ir::AstNodeType::CLASS_DECLARATION: + case ir::AstNodeType::CLASS_DEFINITION: + case ir::AstNodeType::TS_TYPE_PARAMETER: + case ir::AstNodeType::TS_ENUM_DECLARATION: { + ident->SetVariable(res.variable); + return; + } + default: { + iter = iter->Parent(); + } + } + } + + ThrowUnresolvableType(ident->Start(), name); +} + +void ETSBinder::LookupIdentReference(ir::Identifier *ident) +{ + const auto &name = ident->Name(); + ScopeFindResult res = scope_->Find(name, BindingOptions()); + if (res.level != 0) { + ASSERT(res.variable); + + auto *outerFunction = scope_->EnclosingVariableScope()->Node(); + + if ((!outerFunction->IsScriptFunction() || !outerFunction->AsScriptFunction()->IsArrow()) && + !res.variable->IsGlobalVariable() && res.level > 1) { + ThrowInvalidCapture(ident->Start(), name); + } + + res.variable->SetLexical(res.scope); + } + + if (!res.variable) { + return; + } + + if (ident->IsReference() && res.variable->Declaration()->IsLetOrConstDecl() && + !res.variable->HasFlag(VariableFlags::INITIALIZED)) { + ThrowTDZ(ident->Start(), name); + } + + ident->SetVariable(res.variable); +} + +void ETSBinder::BuildClassProperty(const ir::ClassProperty *prop) +{ + ResolveReferences(prop); +} + +void ETSBinder::InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl) +{ + ScopeFindResult res = scope_->Find(decl->Id()->Name()); + + ASSERT(res.variable && res.variable->Declaration()->IsConstDecl()); + res.variable->AddFlag(VariableFlags::INITIALIZED); + decl->Id()->SetVariable(res.variable); +} + +void ETSBinder::ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl, binder::LocalScope *scope) +{ + auto bctx = BoundContext(recordTable_, decl); + + for (auto *extend : decl->Extends()) { + ResolveReference(extend); + } + + InitializeInterfaceIdent(decl); + + auto scopeCtx = LexicalScope::Enter(this, decl->Scope()); + + for (auto *stmt : decl->Body()->Body()) { + if (!stmt->IsClassProperty()) { + continue; + } + ResolveReference(stmt); + + auto fieldVar = scope->FindLocal(stmt->AsClassProperty()->Id()->Name()); + fieldVar->AddFlag(VariableFlags::INITIALIZED); + } + + for (auto *stmt : decl->Body()->Body()) { + if (stmt->IsClassProperty()) { + continue; + } + ResolveReference(stmt); + } +} + +void ETSBinder::BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl) +{ + if (decl->TypeParams()) { + auto typeParamScopeCtx = LexicalScope::Enter(this, decl->TypeParams()->Scope()); + ResolveReferences(decl->TypeParams()); + + auto interfaceScopeCtx = LexicalScope::Enter(this, decl->Scope()); + ResolveInterfaceDeclaration(decl, interfaceScopeCtx.GetScope()); + return; + } + + auto interfaceScopeCtx = LexicalScope::Enter(this, decl->Scope()); + ResolveInterfaceDeclaration(decl, interfaceScopeCtx.GetScope()); +} + +void ETSBinder::BuildMethodDefinition(ir::MethodDefinition *methodDef) +{ + ResolveReferences(methodDef); + + if (recordTable_->InterfaceDeclaration() || methodDef->IsStatic() || methodDef->Function()->IsStaticBlock()) { + return; + } + + auto paramScopeCtx = LexicalScope::Enter(this, methodDef->Function()->Scope()->ParamScope()); + auto *thisParam = AddMandatoryParam(MANDATORY_PARAM_THIS); + thisParam->Declaration()->BindNode(thisParam_); +} + +void ETSBinder::BuildMemberExpression(ir::MemberExpression *memberExpr) +{ + ResolveReference(memberExpr->Object()); + + if (memberExpr->Kind() == ir::MemberExpressionKind::ELEMENT_ACCESS) { + ResolveReference(memberExpr->Property()); + } +} + +void ETSBinder::BuildClassDefinition(ir::ClassDefinition *classDef) +{ + auto bctx = BoundContext(recordTable_, classDef); + + if (classDef->TypeParams()) { + auto scopeCtx = LexicalScope::Enter(this, classDef->TypeParams()->Scope()); + ResolveReferences(classDef->TypeParams()); + + BuildClassDefinitionImpl(classDef); + } else { + BuildClassDefinitionImpl(classDef); + } +} + +void ETSBinder::BuildClassDefinitionImpl(ir::ClassDefinition *classDef) +{ + ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); + ASSERT(!res.variable || res.variable->Declaration()->IsClassDecl()); + + auto scopeCtx = LexicalScope::Enter(this, classDef->Scope()); + + if (classDef->Super()) { + ResolveReference(classDef->Super()); + } + + for (auto *impl : classDef->Implements()) { + ResolveReference(impl); + } + + for (auto *stmt : classDef->Body()) { + if (!stmt->IsClassProperty()) { + continue; + } + ResolveReference(stmt); + + auto fieldVar = scopeCtx.GetScope()->FindLocal(stmt->AsClassProperty()->Id()->Name()); + fieldVar->AddFlag(VariableFlags::INITIALIZED); + if (fieldVar->Declaration()->IsConstDecl() && !stmt->AsClassProperty()->Value()) { + fieldVar->AddFlag(VariableFlags::EXPLICIT_INIT_REQUIRED); + } + } + + for (auto *stmt : classDef->Body()) { + if (stmt->IsClassProperty()) { + continue; + } + ResolveReference(stmt); + } +} + +void ETSBinder::HandleCustomNodes(ir::AstNode *childNode) +{ + switch (childNode->Type()) { + case ir::AstNodeType::ETS_TYPE_REFERENCE: { + auto *typeRef = childNode->AsETSTypeReference(); + ASSERT(typeRef->BaseName()->IsReference()); + LookupTypeReference(typeRef->BaseName()); + LookupTypeArgumentReferences(typeRef); + break; + } + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + BuildInterfaceDeclaration(childNode->AsTSInterfaceDeclaration()); + break; + } + case ir::AstNodeType::EXPORT_NAMED_DECLARATION: { + break; + } + case ir::AstNodeType::IMPORT_DECLARATION: { + BuildImportDeclaration(childNode->AsImportDeclaration()); + break; + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + BuildMemberExpression(childNode->AsMemberExpression()); + break; + } + case ir::AstNodeType::METHOD_DEFINITION: { + BuildMethodDefinition(childNode->AsMethodDefinition()); + break; + } + case ir::AstNodeType::CLASS_STATIC_BLOCK: { + BuildClassStaticBlock(childNode->AsClassStaticBlock()); + break; + } + case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: { + BuildETSNewClassInstanceExpression(childNode->AsETSNewClassInstanceExpression()); + break; + } + case ir::AstNodeType::DEFER_STATEMENT: { + scope_->AddFlag(ScopeFlags::DEFER_STMT); + ResolveReferences(childNode); + break; + } + default: { + ResolveReferences(childNode); + break; + } + } +} + +void ETSBinder::BuildClassStaticBlock(ir::ClassStaticBlock *staticBlock) +{ + const auto &name = staticBlock->Name(); + ScopeFindResult res = scope_->Find(name, BindingOptions()); + staticBlock->Function()->Id()->SetVariable(res.variable); + + ResolveReferences(staticBlock); +} + +bool ETSBinder::BuildInternalName([[maybe_unused]] const ir::ScriptFunction *scriptFunc) +{ + std::stringstream ss; + ss << recordTable_->RecordName(); + util::UString className(ss.str(), Allocator()); + + auto *funcScope = scriptFunc->Scope(); + funcScope->BindName(className.View()); + + bool compilable = scriptFunc->Body() && !recordTable_->IsExternal(); + + if (!compilable) { + recordTable_->Signatures().push_back(funcScope); + } + + return compilable; +} + +void ETSBinder::BuildFunctionName(const ir::ScriptFunction *func) const +{ + auto *funcScope = func->Scope(); + + std::stringstream ss; + ss << funcScope->Name() << compiler::Signatures::METHOD_SEPARATOR; + + const auto *signature = func->Signature(); + + if (func->IsStaticBlock()) { + ss << compiler::Signatures::CCTOR; + } else { + if (func->IsConstructor()) { + ss << compiler::Signatures::CTOR; + } else { + ss << util::Helpers::FunctionName(Allocator(), func); + } + } + + signature->ToAssemblerType(ss); + + util::UString internalName(ss.str(), Allocator()); + funcScope->BindInternalName(internalName.View()); +} + +void ETSBinder::InitImplicitThisParam() +{ + thisParam_ = allocator_->New("this", Allocator()); +} + +void ETSBinder::BuildProgram() +{ + for (auto &[package, extPrograms] : program_->ExternalSources()) { + for (auto *extProg : extPrograms) { + BuildExternalProgram(extProg); + } + } + + for (auto *defaultImport : defaultImports_) { + BuildImportDeclaration(defaultImport); + } + + auto &stmts = program_->Ast()->Statements(); + const auto etsGlobal = std::find_if(stmts.begin(), stmts.end(), [](const ir::Statement *stmt) { + return stmt->IsClassDeclaration() && + stmt->AsClassDeclaration()->Definition()->Ident()->Name().Is(compiler::Signatures::ETS_GLOBAL); + }); + + if (etsGlobal != stmts.end()) { + const auto begin = stmts.begin(); + const size_t index = std::distance(begin, etsGlobal); + std::rotate(begin, begin + index, begin + index + 1); + } + + for (auto *stmt : stmts) { + ResolveReference(stmt); + } +} + +void ETSBinder::BuildExternalProgram(parser::Program *extProgram) +{ + auto *savedProgram = program_; + auto *savedrecordTable = recordTable_; + auto *savedTopScope_ = topScope_; + + auto flags = program_->Binder()->IsGenStdLib() ? RecordTableFlags::NONE : RecordTableFlags::EXTERNAL; + auto *extRecordTable = allocator_->New(allocator_, extProgram, flags); + externalRecordTable_.insert({extProgram, extRecordTable}); + + ResetTopScope(extProgram->GlobalScope()); + recordTable_ = extRecordTable; + program_ = extProgram; + + BuildProgram(); + + program_ = savedProgram; + recordTable_ = savedrecordTable; + ResetTopScope(savedTopScope_); +} + +void ETSBinder::BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *classInstance) +{ + BoundContext boundCtx(recordTable_, classInstance->ClassDefinition()); + ResolveReference(classInstance->GetTypeRef()); + + for (auto *arg : classInstance->GetArguments()) { + ResolveReference(arg); + } + + if (!classInstance->ClassDefinition()) { + return; + } + + ResolveReference(classInstance->ClassDefinition()); +} + +void ETSBinder::BuildImportDeclaration(ir::ImportDeclaration *decl) +{ + auto *specifier = decl->Specifiers().front()->AsImportSpecifier(); + + if (!specifier->Imported()->IsTSQualifiedName()) { + return; + } + + auto *importName = specifier->Imported()->AsTSQualifiedName(); + util::StringView fullPath = importName->ToString(allocator_); + + if (*fullPath.Utf8().rbegin() == Binder::STAR_IMPORT.front()) { + HandleStarImport(importName, fullPath); + return; + } + + util::StringView packageName = importName->BaseToString(allocator_); + + if (packageName == program_->GetPackageName()) { + return; + } + + util::StringView imported = importName->ResolveLeftMostQualifiedName()->Right()->Name(); + + auto res = globalRecordTable_.Program()->ExternalSources().find(packageName); + + if (res == globalRecordTable_.Program()->ExternalSources().end()) { + ThrowError(importName->Start(), "Cannot find package."); + } + + ASSERT(!res->second.empty()); + auto &packageNameSpace = res->second.front()->GlobalScope()->Bindings(); + auto bindingRes = packageNameSpace.find(imported); + + if (bindingRes == packageNameSpace.end()) { + ThrowError(importName->Start(), "Cannot find import"); + } + + auto *var = bindingRes->second; + util::StringView localName = imported; + + if (specifier->Local()) { + localName = specifier->Local()->Name(); + } + + if (!topScope_->Bindings().insert({localName, var}).second) { + ThrowError(importName->Start(), "Import already exiets."); + } + + return; +} + +void ETSBinder::HandleStarImport(ir::TSQualifiedName *importName, util::StringView fullPath) +{ + // Cut ".*" + util::StringView packageName = fullPath.Substr(0, fullPath.Length() - 2); + + if (packageName == program_->GetPackageName()) { + return; + } + + auto res = globalRecordTable_.Program()->ExternalSources().find(packageName); + + if (res == globalRecordTable_.Program()->ExternalSources().end()) { + ThrowError(importName->Start(), "Cannot find package."); + } + + ASSERT(!res->second.empty()); + auto *packageGlobalScope = res->second.front()->GlobalScope(); + + for (auto [bindingName, var] : packageGlobalScope->Bindings()) { + if (bindingName.Is(compiler::Signatures::ETS_GLOBAL)) { + auto *classDef = var->Declaration()->Node()->AsClassDeclaration()->Definition(); + ImportGlobalProperties(classDef); + continue; + } + + auto insRes = topScope_->Bindings().insert({bindingName, var}); + if (!insRes.second) { + if (insRes.first->second != var) { + ThrowError(importName->Start(), "Import already exiets."); + } + } + } +} + +void ETSBinder::ImportGlobalProperties(ir::ClassDefinition *classDef) +{ + auto scopeCtx = LexicalScope::Enter(this, classDef->Scope()); + + for (auto *prop : classDef->Body()) { + auto *classElement = prop->AsClassElement(); + + if (classElement->IsClassStaticBlock()) { + continue; + } + + ASSERT(classElement->IsStatic()); + auto &name = classElement->Id()->Name(); + auto *var = scopeCtx.GetScope()->FindLocal(name); + ASSERT(var); + + auto insRes = topScope_->Bindings().insert({name, var}); + if (!insRes.second) { + if (insRes.first->second != var) { + ThrowError(classElement->Id()->Start(), "Import already exiets."); + } + } + } +} + +} // namespace panda::es2panda::binder diff --git a/binder/ETSBinder.h b/binder/ETSBinder.h new file mode 100644 index 0000000000000000000000000000000000000000..00d01641a78a3939b35fce075b2f79f1cb7b77ee --- /dev/null +++ b/binder/ETSBinder.h @@ -0,0 +1,131 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_BINDER_ETS_BINDER_H +#define ES2PANDA_BINDER_ETS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/TypedBinder.h" +#include "plugins/ecmascript/es2panda/binder/recordTable.h" + +namespace panda::es2panda::binder { +class ETSBinder : public TypedBinder { +public: + explicit ETSBinder(ArenaAllocator *allocator) + : TypedBinder(allocator), + globalRecordTable_(allocator, program_, RecordTableFlags::NONE), + recordTable_(&globalRecordTable_), + externalRecordTable_(allocator_->Adapter()), + defaultImports_(allocator_->Adapter()) + { + InitImplicitThisParam(); + } + + NO_COPY_SEMANTIC(ETSBinder); + NO_MOVE_SEMANTIC(ETSBinder); + ~ETSBinder() = default; + + ScriptExtension Extension() const override + { + return ScriptExtension::ETS; + } + + ResolveBindingOptions BindingOptions() const override + { + return ResolveBindingOptions::ALL; + } + + RecordTable *GetRecordTable() + { + return recordTable_; + } + + const RecordTable *GetRecordTable() const + { + return recordTable_; + } + + RecordTable *GetGlobalRecordTable() + { + return &globalRecordTable_; + } + + const RecordTable *GetGlobalRecordTable() const + { + return &globalRecordTable_; + } + + ArenaUnorderedMap &GetExternalRecordTable() + { + return externalRecordTable_; + } + + const ArenaUnorderedMap &GetExternalRecordTable() const + { + return externalRecordTable_; + } + + virtual void HandleCustomNodes(ir::AstNode *childNode) override; + + void IdentifierAnalysis() override; + void BuildClassDefinition(ir::ClassDefinition *classDef) override; + void BuildClassProperty(const ir::ClassProperty *prop) override; + void LookupIdentReference(ir::Identifier *ident) override; + bool BuildInternalName(const ir::ScriptFunction *scriptFunc) override; + + void LookupTypeReference(ir::Identifier *ident); + void LookupTypeArgumentReferences(ir::ETSTypeReference *typeRef); + void BuildInterfaceDeclaration(ir::TSInterfaceDeclaration *decl); + void BuildMemberExpression(ir::MemberExpression *memberExpr); + void BuildMethodDefinition(ir::MethodDefinition *methodDef); + void BuildImportDeclaration(ir::ImportDeclaration *decl); + void BuildClassStaticBlock(ir::ClassStaticBlock *staticBlock); + void BuildETSNewClassInstanceExpression(ir::ETSNewClassInstanceExpression *classDef); + + void ResolveInterfaceDeclaration(ir::TSInterfaceDeclaration *decl, binder::LocalScope *scope); + void InitializeInterfaceIdent(ir::TSInterfaceDeclaration *decl); + void BuildExternalProgram(parser::Program *extProgram); + void BuildProgram(); + + void BuildFunctionName(const ir::ScriptFunction *func) const; + + void SetDefaultImports(ArenaVector defaultImports) + { + defaultImports_ = std::move(defaultImports); + } + + static constexpr std::string_view DEFAULT_IMPORT_SOURCE_FILE = ".ets"; + static constexpr std::string_view DEFAULT_IMPORT_SOURCE = R"( +import std.array.*; +import std.containers.*; +import std.core.*; +import std.math.*; +)"; + +private: + void BuildClassDefinitionImpl(ir::ClassDefinition *classDef); + void InitImplicitThisParam(); + void HandleStarImport(ir::TSQualifiedName *importName, util::StringView fullPath); + void ImportGlobalProperties(ir::ClassDefinition *classDef); + + RecordTable globalRecordTable_; + RecordTable *recordTable_; + ArenaUnorderedMap externalRecordTable_; + ArenaVector defaultImports_; + ir::Identifier *thisParam_; +}; + +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/JSBinder.cpp b/binder/JSBinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e1ead59219b90db78133fad3421ceccaaf4bb64 --- /dev/null +++ b/binder/JSBinder.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "JSBinder.h" + +namespace panda::es2panda::binder { +} // namespace panda::es2panda::binder diff --git a/binder/JSBinder.h b/binder/JSBinder.h new file mode 100644 index 0000000000000000000000000000000000000000..c96c028952c16ff4b0857baefbd2e70f9815eb21 --- /dev/null +++ b/binder/JSBinder.h @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_BINDER_JS_BINDER_H +#define ES2PANDA_BINDER_JS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/binder.h" + +namespace panda::es2panda::binder { +class JSBinder : public Binder { +public: + explicit JSBinder(ArenaAllocator *allocator) : Binder(allocator) {} + + NO_COPY_SEMANTIC(JSBinder); + DEFAULT_MOVE_SEMANTIC(JSBinder); + ~JSBinder() = default; + +private: +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/TSBinder.cpp b/binder/TSBinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c33d7d0ca6f55160ab73d04845703d0295e57ef7 --- /dev/null +++ b/binder/TSBinder.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "TSBinder.h" + +namespace panda::es2panda::binder { +} // namespace panda::es2panda::binder diff --git a/binder/TSBinder.h b/binder/TSBinder.h new file mode 100644 index 0000000000000000000000000000000000000000..30b11582990cd14984f62e002bbe0bd89ba0909c --- /dev/null +++ b/binder/TSBinder.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_BINDER_TS_BINDER_H +#define ES2PANDA_BINDER_TS_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/TypedBinder.h" + +namespace panda::es2panda::binder { +class TSBinder : public TypedBinder { +public: + explicit TSBinder(ArenaAllocator *allocator) : TypedBinder(allocator) {} + + NO_COPY_SEMANTIC(TSBinder); + NO_MOVE_SEMANTIC(TSBinder); + ~TSBinder() = default; + + ScriptExtension Extension() const override + { + return ScriptExtension::TS; + } + + ResolveBindingOptions BindingOptions() const override + { + return ResolveBindingOptions::ALL; + } + +protected: +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/TypedBinder.cpp b/binder/TypedBinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3346b9f6156d52d8df08add9b8e05f85371edae5 --- /dev/null +++ b/binder/TypedBinder.cpp @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "TypedBinder.h" +#include "plugins/ecmascript/es2panda/ir/base/tsSignatureDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/base/tsMethodSignature.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsFunctionType.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsConstructorType.h" + +namespace panda::es2panda::binder { + +void TypedBinder::BuildSignatureDeclarationBaseParams([[maybe_unused]] const ir::AstNode *typeNode) +{ + if (!typeNode) { + return; + } + + Scope *scope = nullptr; + + switch (typeNode->Type()) { + case ir::AstNodeType::TS_FUNCTION_TYPE: { + scope = typeNode->AsTSFunctionType()->Scope(); + break; + } + case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: { + scope = typeNode->AsTSConstructorType()->Scope(); + break; + } + case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { + scope = typeNode->AsTSSignatureDeclaration()->Scope(); + break; + } + case ir::AstNodeType::TS_METHOD_SIGNATURE: { + scope = typeNode->AsTSMethodSignature()->Scope(); + break; + } + default: { + ResolveReferences(typeNode); + return; + } + } + + ASSERT(scope && scope->IsFunctionParamScope()); + + auto scopeCtx = LexicalScope::Enter(this, scope->AsFunctionParamScope()); + ResolveReferences(typeNode); +} + +void TypedBinder::HandleCustomNodes(ir::AstNode *childNode) +{ + switch (childNode->Type()) { + case ir::AstNodeType::TS_FUNCTION_TYPE: + case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: + case ir::AstNodeType::TS_METHOD_SIGNATURE: + case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { + BuildSignatureDeclarationBaseParams(childNode); + break; + } + default: { + ResolveReferences(childNode); + break; + } + } +} +} // namespace panda::es2panda::binder diff --git a/binder/TypedBinder.h b/binder/TypedBinder.h new file mode 100644 index 0000000000000000000000000000000000000000..813d8aad385e3577f071d4d7bab6bbf6696e6127 --- /dev/null +++ b/binder/TypedBinder.h @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_BINDER_TYPED_BINDER_H +#define ES2PANDA_BINDER_TYPED_BINDER_H + +#include "plugins/ecmascript/es2panda/binder/binder.h" + +namespace panda::es2panda::binder { +class TypedBinder : public Binder { +public: + explicit TypedBinder(ArenaAllocator *allocator) : Binder(allocator) {} + + NO_COPY_SEMANTIC(TypedBinder); + NO_MOVE_SEMANTIC(TypedBinder); + ~TypedBinder() = default; + +protected: + void HandleCustomNodes(ir::AstNode *childNode) override; + void BuildSignatureDeclarationBaseParams([[maybe_unused]] const ir::AstNode *typeNode) override; +}; +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/binder.cpp b/binder/binder.cpp index 682ac0684997b8beac4ad591ad58846268574111..3dfdaa556b8641880673cf8bda8f493a55fe82b3 100644 --- a/binder/binder.cpp +++ b/binder/binder.cpp @@ -16,6 +16,7 @@ #include "binder.h" #include "plugins/ecmascript/es2panda/binder/privateBinding.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" #include "plugins/ecmascript/es2panda/util/helpers.h" #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/binder/tsBinding.h" @@ -24,12 +25,15 @@ #include "plugins/ecmascript/es2panda/ir/astNode.h" #include "plugins/ecmascript/es2panda/ir/base/catchClause.h" #include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/classStaticBlock.h" #include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" #include "plugins/ecmascript/es2panda/ir/base/property.h" #include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" #include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" #include "plugins/ecmascript/es2panda/ir/expressions/arrayExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/expressions/objectExpression.h" #include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" @@ -42,10 +46,17 @@ #include "plugins/ecmascript/es2panda/ir/statements/variableDeclaration.h" #include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" #include "plugins/ecmascript/es2panda/ir/statements/whileStatement.h" +#include "plugins/ecmascript/es2panda/ir/module/exportNamedDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/module/importDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsFunctionType.h" #include "plugins/ecmascript/es2panda/ir/ts/tsConstructorType.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsSignatureDeclaration.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsMethodSignature.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/base/tsSignatureDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/base/tsMethodSignature.h" namespace panda::es2panda::binder { void Binder::InitTopScope() @@ -60,7 +71,7 @@ void Binder::InitTopScope() varScope_ = topScope_; } -ParameterDecl *Binder::AddParamDecl(const ir::AstNode *param) +ParameterDecl *Binder::AddParamDecl(ir::AstNode *param) { ASSERT(scope_->IsFunctionParamScope() || scope_->IsCatchParamScope()); auto [decl, node] = static_cast(scope_)->AddParamDecl(Allocator(), param); @@ -72,24 +83,55 @@ ParameterDecl *Binder::AddParamDecl(const ir::AstNode *param) ThrowRedeclaration(node->Start(), decl->Name()); } -void Binder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) +void Binder::ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) const { - lexer::LineIndex index(program_->SourceCode()); - lexer::SourceLocation loc = index.GetLocation(pos); - std::stringstream ss; ss << "Variable '" << name << "' has already been declared."; - throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col); + ThrowError(pos, ss.str()); +} + +void Binder::ThrowUnresolvableVariable(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Cannot find variable '" << name << "'."; + ThrowError(pos, ss.str()); +} + +void Binder::ThrowUnresolvableType(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Cannot find type '" << name << "'."; + ThrowError(pos, ss.str()); +} + +void Binder::ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Variable '" << name << "' is accessed before it's initialization."; + ThrowError(pos, ss.str()); +} + +void Binder::ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Cannot capture variable'" << name << "'."; + ThrowError(pos, ss.str()); } void Binder::ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const +{ + std::stringstream ss; + ss << "Private field '" << name << "' must be declared in an enclosing class"; + + ThrowError(pos, ss.str()); +} + +void Binder::ThrowError(const lexer::SourcePosition &pos, const std::string_view &msg) const { lexer::LineIndex index(program_->SourceCode()); lexer::SourceLocation loc = index.GetLocation(pos); - std::stringstream ss; - ss << "Private field '" << name << "' must be declared in an enclosing class"; - throw Error(ErrorType::SYNTAX, ss.str(), loc.line, loc.col); + throw Error(ErrorType::SYNTAX, program_->SourceFile().Utf8(), msg, loc.line, loc.col); } void Binder::IdentifierAnalysis() @@ -98,11 +140,10 @@ void Binder::IdentifierAnalysis() ASSERT(scope_ == topScope_); ASSERT(varScope_ == topScope_); - if (program_->Extension() == ScriptExtension::AS) { - return; - } + functionScopes_.push_back(topScope_); + topScope_->BindName(MAIN); + topScope_->BindInternalName(BuildFunctionName(MAIN, 0)); - BuildFunction(topScope_, "main"); topScope_->CheckDirectEval(compilerCtx_); ResolveReferences(program_->Ast()); @@ -150,7 +191,7 @@ void Binder::InstantiateArguments() scope->Bindings().insert({argumentsVariable->Name(), argumentsVariable}); } - scope->AsVariableScope()->AddFlag(VariableScopeFlags::USE_ARGS); + scope->AddFlag(ScopeFlags::USE_ARGS); break; } @@ -167,7 +208,7 @@ void Binder::PropagateDirectEval() const VariableScope *scope = iter->IsFunctionParamScope() ? iter->AsFunctionParamScope()->GetFunctionScope() : iter->EnclosingVariableScope(); - scope->AddFlag(VariableScopeFlags::NO_REG_STORE); + scope->AddFlag(ScopeFlags::NO_REG_STORE); iter = iter->Parent(); } while (iter != nullptr); } @@ -197,16 +238,20 @@ void Binder::InstantiatePrivateContext(const ir::Identifier *ident) const void Binder::LookupIdentReference(ir::Identifier *ident) { + if (!ident->IsReference()) { + return; + } + if (ident->Name().Is(FUNCTION_ARGUMENTS)) { InstantiateArguments(); } - if (ident->IsPrivate()) { + if (ident->IsPrivateIdent()) { InstantiatePrivateContext(ident); return; } - ScopeFindResult res = scope_->Find(ident->Name(), bindingOptions_); + ScopeFindResult res = scope_->Find(ident->Name(), BindingOptions()); if (res.level != 0) { ASSERT(res.variable); res.variable->SetLexical(res.scope); @@ -223,32 +268,29 @@ void Binder::LookupIdentReference(ir::Identifier *ident) ident->SetVariable(res.variable); } -void Binder::BuildFunction(FunctionScope *funcScope, util::StringView name) +util::StringView Binder::BuildFunctionName(util::StringView name, uint32_t idx) { - uint32_t idx = functionScopes_.size(); - functionScopes_.push_back(funcScope); - std::stringstream ss; ss << "func_" << name << "_" << std::to_string(idx); util::UString internalName(ss.str(), Allocator()); - funcScope->BindName(name, internalName.View()); + return internalName.View(); } -void Binder::BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc) +bool Binder::BuildInternalName(const ir::ScriptFunction *scriptFunc) { - if (scriptFunc->IsArrow()) { - VariableScope *outerVarScope = outerScope->EnclosingVariableScope(); - outerVarScope->AddFlag(VariableScopeFlags::INNER_ARROW); - } + auto *funcScope = scriptFunc->Scope(); + auto name = util::Helpers::FunctionName(Allocator(), scriptFunc); - BuildFunction(scope_->AsFunctionScope(), util::Helpers::FunctionName(Allocator(), scriptFunc)); + uint32_t idx = functionScopes_.size(); + funcScope->BindName(name); + funcScope->BindInternalName(BuildFunctionName(name, idx)); + + return !scriptFunc->IsOverload(); } -void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childNode) +void Binder::BuildVarDeclaratorId(ir::AstNode *childNode) { - childNode->SetParent(parent); - switch (childNode->Type()) { case ir::AstNodeType::IDENTIFIER: { auto *ident = childNode->AsIdentifier(); @@ -259,12 +301,8 @@ void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childN } auto *variable = scope_->FindLocal(name); - - if (Program()->Extension() == ScriptExtension::TS) { - ident->SetVariable(variable); - BuildTSSignatureDeclarationBaseParams(ident->TypeAnnotation()); - } - + ident->SetVariable(variable); + BuildSignatureDeclarationBaseParams(ident->TypeAnnotation()); variable->AddFlag(VariableFlags::INITIALIZED); break; } @@ -272,34 +310,34 @@ void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childN auto *objPattern = childNode->AsObjectPattern(); for (auto *prop : objPattern->Properties()) { - BuildVarDeclaratorId(childNode, prop); + BuildVarDeclaratorId(prop); } - BuildTSSignatureDeclarationBaseParams(objPattern->TypeAnnotation()); + BuildSignatureDeclarationBaseParams(objPattern->TypeAnnotation()); break; } case ir::AstNodeType::ARRAY_PATTERN: { auto *arrayPattern = childNode->AsArrayPattern(); for (auto *element : childNode->AsArrayPattern()->Elements()) { - BuildVarDeclaratorId(childNode, element); + BuildVarDeclaratorId(element); } - BuildTSSignatureDeclarationBaseParams(arrayPattern->TypeAnnotation()); + BuildSignatureDeclarationBaseParams(arrayPattern->TypeAnnotation()); break; } case ir::AstNodeType::ASSIGNMENT_PATTERN: { - ResolveReference(childNode, childNode->AsAssignmentPattern()->Right()); - BuildVarDeclaratorId(childNode, childNode->AsAssignmentPattern()->Left()); + ResolveReference(childNode->AsAssignmentPattern()->Right()); + BuildVarDeclaratorId(childNode->AsAssignmentPattern()->Left()); break; } case ir::AstNodeType::PROPERTY: { - ResolveReference(childNode, childNode->AsProperty()->Key()); - BuildVarDeclaratorId(childNode, childNode->AsProperty()->Value()); + ResolveReference(childNode->AsProperty()->Key()); + BuildVarDeclaratorId(childNode->AsProperty()->Value()); break; } case ir::AstNodeType::REST_ELEMENT: { - BuildVarDeclaratorId(childNode, childNode->AsRestElement()->Argument()); + BuildVarDeclaratorId(childNode->AsRestElement()->Argument()); break; } default: @@ -307,86 +345,67 @@ void Binder::BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childN } } -void Binder::BuildTSSignatureDeclarationBaseParams(const ir::AstNode *typeNode) +void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl) { - if (typeNode == nullptr) { + if (varDecl->Parent()->AsVariableDeclaration()->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) { + ResolveReferences(varDecl); return; } - Scope *scope = nullptr; - - switch (typeNode->Type()) { - case ir::AstNodeType::TS_FUNCTION_TYPE: { - scope = typeNode->AsTSFunctionType()->Scope(); - break; - } - case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: { - scope = typeNode->AsTSConstructorType()->Scope(); - break; - } - case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { - scope = typeNode->AsTSSignatureDeclaration()->Scope(); - break; - } - case ir::AstNodeType::TS_METHOD_SIGNATURE: { - scope = typeNode->AsTSMethodSignature()->Scope(); - break; - } - default: { - ResolveReferences(typeNode); - return; - } + if (varDecl->Init()) { + ResolveReference(varDecl->Init()); } - ASSERT(scope && scope->IsFunctionParamScope()); + BuildVarDeclaratorId(varDecl->Id()); +} + +void Binder::BuildClassProperty(const ir::ClassProperty *prop) +{ + const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(prop); + auto scopeCtx = LexicalScope::Enter(this, ctor->Scope()); - auto scopeCtx = LexicalScope::Enter(this, scope->AsFunctionParamScope()); - ResolveReferences(typeNode); + ResolveReferences(prop); } -void Binder::BuildVarDeclarator(ir::VariableDeclarator *varDecl) +void Binder::InitializeClassBinding(ir::ClassDefinition *classDef) { - if (varDecl->Parent()->AsVariableDeclaration()->Kind() == ir::VariableDeclaration::VariableDeclarationKind::VAR) { - ResolveReferences(varDecl); - return; - } + ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - if (varDecl->Init() != nullptr) { - ResolveReference(varDecl, varDecl->Init()); - } + ASSERT(res.variable && res.variable->Declaration()->IsLetDecl()); + res.variable->AddFlag(VariableFlags::INITIALIZED); +} + +void Binder::InitializeClassIdent(ir::ClassDefinition *classDef) +{ + ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - BuildVarDeclaratorId(varDecl, varDecl->Id()); + ASSERT(res.variable && res.variable->Declaration()->IsConstDecl()); + res.variable->AddFlag(VariableFlags::INITIALIZED); } void Binder::BuildClassDefinition(ir::ClassDefinition *classDef) { if (classDef->Parent()->IsClassDeclaration()) { - ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - - ASSERT(res.variable && res.variable->Declaration()->IsLetDecl()); - res.variable->AddFlag(VariableFlags::INITIALIZED); + InitializeClassBinding(classDef); } auto scopeCtx = LexicalScope::Enter(this, classDef->Scope()); if (classDef->Super() != nullptr) { - ResolveReference(classDef, classDef->Super()); + ResolveReference(classDef->Super()); } Variable *variable = scope_->FindLocal(classDef->PrivateId()); variable->AddFlag(VariableFlags::INITIALIZED); if (classDef->Ident() != nullptr) { - ScopeFindResult res = scope_->Find(classDef->Ident()->Name()); - - ASSERT(res.variable && res.variable->Declaration()->IsConstDecl()); - res.variable->AddFlag(VariableFlags::INITIALIZED); + InitializeClassIdent(classDef); } - ResolveReference(classDef, classDef->Ctor()); + ResolveReference(classDef->Ctor()); for (auto *stmt : classDef->Body()) { - ResolveReference(classDef, stmt); + ResolveReference(stmt); } } @@ -397,35 +416,35 @@ void Binder::BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt) auto declScopeCtx = LexicalScope::Enter(this, loopScope->DeclScope()); if (forUpdateStmt->Init() != nullptr) { - ResolveReference(forUpdateStmt, forUpdateStmt->Init()); + ResolveReference(forUpdateStmt->Init()); } if (forUpdateStmt->Update() != nullptr) { - ResolveReference(forUpdateStmt, forUpdateStmt->Update()); + ResolveReference(forUpdateStmt->Update()); } auto loopCtx = LexicalScope::Enter(this, loopScope); if (forUpdateStmt->Test() != nullptr) { - ResolveReference(forUpdateStmt, forUpdateStmt->Test()); + ResolveReference(forUpdateStmt->Test()); } - ResolveReference(forUpdateStmt, forUpdateStmt->Body()); + ResolveReference(forUpdateStmt->Body()); loopCtx.GetScope()->ConvertToVariableScope(Allocator()); } -void Binder::BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left, - ir::Expression *right, ir::Statement *body) +void Binder::BuildForInOfLoop(binder::LoopScope *loopScope, ir::AstNode *left, ir::Expression *right, + ir::Statement *body) { auto declScopeCtx = LexicalScope::Enter(this, loopScope->DeclScope()); - ResolveReference(parent, right); - ResolveReference(parent, left); + ResolveReference(right); + ResolveReference(left); auto loopCtx = LexicalScope::Enter(this, loopScope); - ResolveReference(parent, body); + ResolveReference(body); loopCtx.GetScope()->ConvertToVariableScope(Allocator()); } @@ -433,81 +452,98 @@ void Binder::BuildCatchClause(ir::CatchClause *catchClauseStmt) { if (catchClauseStmt->Param() != nullptr) { auto paramScopeCtx = LexicalScope::Enter(this, catchClauseStmt->Scope()->ParamScope()); - ResolveReference(catchClauseStmt, catchClauseStmt->Param()); + ResolveReference(catchClauseStmt->Param()); } auto scopeCtx = LexicalScope::Enter(this, catchClauseStmt->Scope()); - ResolveReference(catchClauseStmt, catchClauseStmt->Body()); + ResolveReference(catchClauseStmt->Body()); +} + +void Binder::AddCompilableFunction(ir::ScriptFunction *func) +{ + if (func->IsArrow()) { + VariableScope *outerVarScope = scope_->EnclosingVariableScope(); + outerVarScope->AddFlag(ScopeFlags::INNER_ARROW); + } + + AddCompilableFunctionScope(func->Scope()); +} + +void Binder::AddCompilableFunctionScope(binder::FunctionScope *funcScope) +{ + functionScopes_.push_back(funcScope); } -void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) +void Binder::VisitScriptFunction(ir::ScriptFunction *func) { - childNode->SetParent(parent); + auto *funcScope = func->Scope(); + { + auto paramScopeCtx = LexicalScope::Enter(this, funcScope->ParamScope()); + + for (auto *param : func->Params()) { + ResolveReference(param); + } + } + + if (func->ReturnTypeAnnotation()) { + ResolveReference(func->ReturnTypeAnnotation()); + } + + if (!BuildInternalName(func)) { + return; + } + + AddCompilableFunction(func); + + auto scopeCtx = LexicalScope::Enter(this, funcScope); + + if (func->Body()) { + ResolveReference(func->Body()); + } +} + +void Binder::VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction *func) +{ + if (func->TypeParams()) { + auto typeParamScopeCtx = LexicalScope::Enter(this, func->TypeParams()->Scope()); + VisitScriptFunction(func); + return; + } + + VisitScriptFunction(func); +} + +void Binder::ResolveReference(ir::AstNode *childNode) +{ switch (childNode->Type()) { case ir::AstNodeType::IDENTIFIER: { auto *ident = childNode->AsIdentifier(); - if (ident->IsReference()) { - LookupIdentReference(ident); - } - + LookupIdentReference(ident); ResolveReferences(childNode); break; } case ir::AstNodeType::SUPER_EXPRESSION: { VariableScope *varScope = scope_->EnclosingVariableScope(); - varScope->AddFlag(VariableScopeFlags::USE_SUPER); - + varScope->AddFlag(ScopeFlags::USE_SUPER); ResolveReferences(childNode); break; } case ir::AstNodeType::SCRIPT_FUNCTION: { - auto *scriptFunc = childNode->AsScriptFunction(); - auto *funcScope = scriptFunc->Scope(); - - auto *outerScope = scope_; - - { - auto paramScopeCtx = LexicalScope::Enter(this, funcScope->ParamScope()); - - for (auto *param : scriptFunc->Params()) { - ResolveReference(scriptFunc, param); - } - } - - if (Program()->Extension() == ScriptExtension::TS) { - if (scriptFunc->ReturnTypeAnnotation() != nullptr) { - ResolveReference(scriptFunc, scriptFunc->ReturnTypeAnnotation()); - } - - if (scriptFunc->IsOverload()) { - break; - } - } - - auto scopeCtx = LexicalScope::Enter(this, funcScope); - - BuildScriptFunction(outerScope, scriptFunc); - - ResolveReference(scriptFunc, scriptFunc->Body()); + VisitScriptFunctionWithPotentialTypeParams(childNode->AsScriptFunction()); break; } case ir::AstNodeType::VARIABLE_DECLARATOR: { BuildVarDeclarator(childNode->AsVariableDeclarator()); - break; } case ir::AstNodeType::CLASS_DEFINITION: { BuildClassDefinition(childNode->AsClassDefinition()); - break; } case ir::AstNodeType::CLASS_PROPERTY: { - const ir::ScriptFunction *ctor = util::Helpers::GetContainingConstructor(childNode->AsClassProperty()); - auto scopeCtx = LexicalScope::Enter(this, ctor->Scope()); - - ResolveReferences(childNode); + BuildClassProperty(childNode->AsClassProperty()); break; } case ir::AstNodeType::BLOCK_STATEMENT: { @@ -527,18 +563,18 @@ void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) { auto loopScopeCtx = LexicalScope::Enter(this, doWhileStatement->Scope()); - ResolveReference(doWhileStatement, doWhileStatement->Body()); + ResolveReference(doWhileStatement->Body()); } - ResolveReference(doWhileStatement, doWhileStatement->Test()); + ResolveReference(doWhileStatement->Test()); break; } case ir::AstNodeType::WHILE_STATEMENT: { auto *whileStatement = childNode->AsWhileStatement(); - ResolveReference(whileStatement, whileStatement->Test()); + ResolveReference(whileStatement->Test()); auto loopScopeCtx = LexicalScope::Enter(this, whileStatement->Scope()); - ResolveReference(whileStatement, whileStatement->Body()); + ResolveReference(whileStatement->Body()); break; } @@ -548,36 +584,29 @@ void Binder::ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode) } case ir::AstNodeType::FOR_IN_STATEMENT: { auto *forInStmt = childNode->AsForInStatement(); - BuildForInOfLoop(forInStmt, forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body()); + BuildForInOfLoop(forInStmt->Scope(), forInStmt->Left(), forInStmt->Right(), forInStmt->Body()); break; } case ir::AstNodeType::FOR_OF_STATEMENT: { auto *forOfStmt = childNode->AsForOfStatement(); - BuildForInOfLoop(forOfStmt, forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body()); + BuildForInOfLoop(forOfStmt->Scope(), forOfStmt->Left(), forOfStmt->Right(), forOfStmt->Body()); break; } case ir::AstNodeType::CATCH_CLAUSE: { BuildCatchClause(childNode->AsCatchClause()); break; } - // TypeScript specific part - case ir::AstNodeType::TS_FUNCTION_TYPE: - case ir::AstNodeType::TS_CONSTRUCTOR_TYPE: - case ir::AstNodeType::TS_METHOD_SIGNATURE: - case ir::AstNodeType::TS_SIGNATURE_DECLARATION: { - BuildTSSignatureDeclarationBaseParams(childNode); - break; - } default: { - ResolveReferences(childNode); + HandleCustomNodes(childNode); break; } } } + void Binder::ResolveReferences(const ir::AstNode *parent) { - parent->Iterate([this, parent](auto *childNode) { ResolveReference(parent, childNode); }); + parent->Iterate([this](auto *childNode) { ResolveReference(childNode); }); } LocalVariable *Binder::AddMandatoryParam(const std::string_view &name) @@ -601,7 +630,7 @@ void Binder::LookUpMandatoryReferences(const FunctionScope *funcScope, bool need LookupReference(MANDATORY_PARAM_NEW_TARGET); LookupReference(MANDATORY_PARAM_THIS); - if (funcScope->HasFlag(VariableScopeFlags::USE_ARGS)) { + if (funcScope->HasFlag(ScopeFlags::USE_ARGS)) { LookupReference(FUNCTION_ARGUMENTS); } @@ -649,9 +678,9 @@ void Binder::AddMandatoryParams() bool lexicalFunctionObject {}; if (ctor != nullptr && util::Helpers::GetClassDefiniton(ctor)->Super() != nullptr && - funcScope->HasFlag(VariableScopeFlags::USE_SUPER)) { - ASSERT(ctor->Scope()->HasFlag(VariableScopeFlags::INNER_ARROW)); - ctor->Scope()->AddFlag(VariableScopeFlags::SET_LEXICAL_FUNCTION); + funcScope->HasFlag(ScopeFlags::USE_SUPER)) { + ASSERT(ctor->Scope()->HasFlag(ScopeFlags::INNER_ARROW)); + ctor->Scope()->AddFlag(ScopeFlags::SET_LEXICAL_FUNCTION); lexicalFunctionObject = true; AddMandatoryParams(CTOR_ARROW_MANDATORY_PARAMS); } else { diff --git a/binder/binder.h b/binder/binder.h index 2f67336d1130a1a975d1fefdd3f5fa055d1919b4..30aecb8c7d2f0ea54434198f0b71a86f7f5f2dea 100644 --- a/binder/binder.h +++ b/binder/binder.h @@ -20,7 +20,11 @@ #include "plugins/ecmascript/es2panda/binder/variableFlags.h" #include "plugins/ecmascript/es2panda/lexer/token/sourceLocation.h" #include "macros.h" -#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::parser { +class Program; +enum class ScriptKind; +} // namespace panda::es2panda::parser namespace panda::es2panda::ir { class AstNode; @@ -34,28 +38,22 @@ class ScriptFunction; class Statement; class VariableDeclarator; class TSFunctionType; +class ThisExpression; +class MemberExpression; +class ClassStaticBlock; } // namespace panda::es2panda::ir namespace panda::es2panda::binder { class Binder { public: - explicit Binder(parser::Program *program, ScriptExtension extension) - : program_(program), functionScopes_(Allocator()->Adapter()) - { - if (extension == ScriptExtension::TS) { - bindingOptions_ = ResolveBindingOptions::ALL; - return; - } - - bindingOptions_ = ResolveBindingOptions::BINDINGS; - } + explicit Binder(ArenaAllocator *allocator) : allocator_(allocator), functionScopes_(allocator_->Adapter()) {} NO_COPY_SEMANTIC(Binder); - DEFAULT_MOVE_SEMANTIC(Binder); + NO_MOVE_SEMANTIC(Binder); ~Binder() = default; void InitTopScope(); - void IdentifierAnalysis(); + virtual void IdentifierAnalysis(); template T *AddDecl(const lexer::SourcePosition &pos, Args &&...args); @@ -63,7 +61,25 @@ public: template T *AddTsDecl(const lexer::SourcePosition &pos, Args &&...args); - ParameterDecl *AddParamDecl(const ir::AstNode *param); + ParameterDecl *AddParamDecl(ir::AstNode *param); + + void SetProgram(parser::Program *program) + { + ASSERT(!program_); + program_ = program; + } + + parser::Program *Program() + { + ASSERT(program_); + return program_; + } + + const parser::Program *Program() const + { + ASSERT(program_); + return program_; + } void SetCompilerContext(compiler::CompilerContext *compilerContext) { @@ -77,17 +93,41 @@ public: return compilerCtx_; } + void SetGenStdLib(bool genStdLib) + { + genStdLib_ = genStdLib; + } + + bool IsGenStdLib() + { + return genStdLib_; + } + Scope *GetScope() const { return scope_; } + void ResetTopScope(GlobalScope *topScope) + { + ASSERT(topScope_ == scope_); + topScope_ = topScope; + varScope_ = topScope_; + scope_ = topScope_; + } + GlobalScope *TopScope() const { return topScope_; } - [[noreturn]] void ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name); + [[noreturn]] void ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowRedeclaration(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowUnresolvableVariable(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowUnresolvableType(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowTDZ(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowInvalidCapture(const lexer::SourcePosition &pos, const util::StringView &name) const; + [[noreturn]] void ThrowError(const lexer::SourcePosition &pos, const std::string_view &name) const; void PropagateDirectEval() const; @@ -96,7 +136,7 @@ public: inline ArenaAllocator *Allocator() const { - return program_->Allocator(); + return allocator_; } const ArenaVector &Functions() const @@ -109,9 +149,14 @@ public: return functionScopes_; } - const parser::Program *Program() const + virtual ScriptExtension Extension() const { - return program_; + return ScriptExtension::JS; + } + + virtual ResolveBindingOptions BindingOptions() const + { + return ResolveBindingOptions::BINDINGS; } static constexpr std::string_view FUNCTION_ARGUMENTS = "arguments"; @@ -127,9 +172,11 @@ public: static constexpr std::string_view LEXICAL_MANDATORY_PARAM_THIS = "!t"; static constexpr std::string_view LEXICAL_CONTEXT_PARAM = "=eval"; + static constexpr std::string_view MAIN = "main"; static constexpr uint32_t LEXICAL_CONTEXT_PARAM_REG = MANDATORY_PARAMS_NUMBER; + static constexpr std::string_view STAR_IMPORT = "*"; -private: +protected: template using MandatoryParams = std::array; @@ -150,33 +197,45 @@ private: template void AddMandatoryParams(const MandatoryParams ¶ms); void AddMandatoryParams(); - void BuildFunction(FunctionScope *funcScope, util::StringView name); - void BuildScriptFunction(Scope *outerScope, const ir::ScriptFunction *scriptFunc); - void BuildClassDefinition(ir::ClassDefinition *classDef); void LookupReference(const util::StringView &name); void InstantiateArguments(); void InstantiatePrivateContext(const ir::Identifier *ident) const; void BuildVarDeclarator(ir::VariableDeclarator *varDecl); - void BuildVarDeclaratorId(const ir::AstNode *parent, ir::AstNode *childNode); + void BuildVarDeclaratorId(ir::AstNode *childNode); void BuildForUpdateLoop(ir::ForUpdateStatement *forUpdateStmt); - void BuildForInOfLoop(const ir::Statement *parent, binder::LoopScope *loopScope, ir::AstNode *left, - ir::Expression *right, ir::Statement *body); + void BuildForInOfLoop(binder::LoopScope *loopScope, ir::AstNode *left, ir::Expression *right, ir::Statement *body); void BuildCatchClause(ir::CatchClause *catchClauseStmt); - void LookupIdentReference(ir::Identifier *ident); - void ResolveReference(const ir::AstNode *parent, ir::AstNode *childNode); + void ResolveReference(ir::AstNode *childNode); void ResolveReferences(const ir::AstNode *parent); + void VisitScriptFunctionWithPotentialTypeParams(ir::ScriptFunction *func); + void VisitScriptFunction(ir::ScriptFunction *func); + util::StringView BuildFunctionName(util::StringView name, uint32_t idx); - // TypeScript specific functions - void BuildTSSignatureDeclarationBaseParams(const ir::AstNode *typeNode); - [[noreturn]] void ThrowPrivateFieldMismatch(const lexer::SourcePosition &pos, const util::StringView &name) const; + void AddCompilableFunction(ir::ScriptFunction *func); + void AddCompilableFunctionScope(binder::FunctionScope *funcScope); + + void InitializeClassBinding(ir::ClassDefinition *classDef); + void InitializeClassIdent(ir::ClassDefinition *classDef); + + virtual void LookupIdentReference(ir::Identifier *ident); + virtual void HandleCustomNodes(ir::AstNode *childNode) + { + ResolveReferences(childNode); + } + virtual void BuildSignatureDeclarationBaseParams([[maybe_unused]] const ir::AstNode *typeNode) {}; + virtual void BuildClassDefinition(ir::ClassDefinition *classDef); + virtual void BuildClassProperty(const ir::ClassProperty *prop); + virtual bool BuildInternalName(const ir::ScriptFunction *scriptFunc); parser::Program *program_ {}; + ArenaAllocator *allocator_ {}; compiler::CompilerContext *compilerCtx_ {}; GlobalScope *topScope_ {}; Scope *scope_ {}; VariableScope *varScope_ {}; ArenaVector functionScopes_; ResolveBindingOptions bindingOptions_; + bool genStdLib_ {false}; }; template @@ -201,10 +260,10 @@ public: binder_->varScope_ = prevVarScope_; } - [[nodiscard]] static LexicalScope Enter(Binder *binder, T *scope) + [[nodiscard]] static LexicalScope Enter(Binder *binder, T *scope, bool checkEval = true) { LexicalScope lexScope(scope, binder); - if (binder->Program()->Extension() == ScriptExtension::TS) { + if (!checkEval || binder->Extension() == ScriptExtension::TS) { return lexScope; } // NOLINTNEXTLINE(readability-braces-around-statements) @@ -266,7 +325,7 @@ T *Binder::AddTsDecl(const lexer::SourcePosition &pos, Args &&...args) { T *decl = Allocator()->New(std::forward(args)...); - if (scope_->AddTsDecl(Allocator(), decl, program_->Extension())) { + if (scope_->AddTsDecl(Allocator(), decl, Extension())) { return decl; } @@ -278,7 +337,7 @@ T *Binder::AddDecl(const lexer::SourcePosition &pos, Args &&...args) { T *decl = Allocator()->New(std::forward(args)...); - if (scope_->AddDecl(Allocator(), decl, program_->Extension())) { + if (scope_->AddDecl(Allocator(), decl, Extension())) { return decl; } diff --git a/binder/declaration.h b/binder/declaration.h index ba4cee19e180526d5fec68c269da965fe19b9beb..82cb34ec0bd4fe282383a2956e9382a4bc547d01 100644 --- a/binder/declaration.h +++ b/binder/declaration.h @@ -49,13 +49,18 @@ public: return name_; } + ir::AstNode *Node() + { + return node_; + } + const ir::AstNode *Node() const { return node_; } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DECLARE_CHECKS_CASTS(declKind, className) \ +#define DECLARE_CHECKS_CAETS(declKind, className) \ bool Is##className() const \ { \ return Type() == DeclType::declKind; \ @@ -70,10 +75,10 @@ public: ASSERT(Is##className()); \ return reinterpret_cast(this); \ } - DECLARATION_KINDS(DECLARE_CHECKS_CASTS) -#undef DECLARE_CHECKS_CASTS + DECLARATION_KINDS(DECLARE_CHECKS_CAETS) +#undef DECLARE_CHECKS_CAETS - void BindNode(const ir::AstNode *node) + void BindNode(ir::AstNode *node) { node_ = node; } @@ -83,12 +88,17 @@ public: return IsLetDecl() || IsConstDecl(); } + bool PossibleTDZ() const + { + return IsLetOrConstDecl() || IsParameterDecl(); + } + protected: explicit Decl(util::StringView name) : name_(name) {} // NOLINTBEGIN(misc-non-private-member-variables-in-classes) util::StringView name_; - const ir::AstNode *node_ {}; + ir::AstNode *node_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) }; @@ -153,9 +163,19 @@ public: } }; +class ClassDecl : public Decl { +public: + explicit ClassDecl(util::StringView name) : Decl(name) {} + + DeclType Type() const override + { + return DeclType::CLASS; + } +}; + class FunctionDecl : public MultiDecl { public: - explicit FunctionDecl(ArenaAllocator *allocator, util::StringView name, const ir::AstNode *node) + explicit FunctionDecl(ArenaAllocator *allocator, util::StringView name, ir::AstNode *node) : MultiDecl(allocator, name) { node_ = node; @@ -169,7 +189,7 @@ public: class TypeParameterDecl : public Decl { public: - explicit TypeParameterDecl(util::StringView name, const ir::AstNode *node); + explicit TypeParameterDecl(util::StringView name) : Decl(name) {} DeclType Type() const override { @@ -274,7 +294,7 @@ public: { } - explicit ImportDecl(util::StringView importName, util::StringView localName, const ir::AstNode *node) + explicit ImportDecl(util::StringView importName, util::StringView localName, ir::AstNode *node) : Decl(localName), importName_(importName) { BindNode(node); @@ -306,7 +326,7 @@ public: { } - explicit ExportDecl(util::StringView exportName, util::StringView localName, const ir::AstNode *node) + explicit ExportDecl(util::StringView exportName, util::StringView localName, ir::AstNode *node) : Decl(localName), exportName_(exportName) { BindNode(node); diff --git a/binder/recordTable.cpp b/binder/recordTable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dcc9ffaa67aa618b93f9df81d3e8346195389336 --- /dev/null +++ b/binder/recordTable.cpp @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "recordTable.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "generated/signatures.h" + +namespace panda::es2panda::binder { + +BoundContext::BoundContext(RecordTable *recordTable, ir::ClassDefinition *classDef) + : prev_(recordTable->boundCtx_), + recordTable_(recordTable), + savedClassDefinition_(recordTable->classDefinition_), + savedInterfaceDeclaration_(recordTable->interfaceDeclaration_) +{ + if (!classDef || !recordTable_->classDefinitions_.insert(classDef).second) { + return; + } + + recordTable_->boundCtx_ = this; + recordTable_->classDefinition_ = classDef; + recordTable_->interfaceDeclaration_ = nullptr; + recordIdent_ = classDef->Ident(); + classDef->SetInternalName(FormRecordName()); +} + +BoundContext::BoundContext(RecordTable *recordTable, ir::TSInterfaceDeclaration *interfaceDecl) + : prev_(recordTable->boundCtx_), + recordTable_(recordTable), + savedClassDefinition_(recordTable->classDefinition_), + savedInterfaceDeclaration_(recordTable->interfaceDeclaration_) +{ + if (!interfaceDecl || !recordTable_->interfaceDeclarations_.insert(interfaceDecl).second) { + return; + } + + recordTable_->boundCtx_ = this; + recordTable_->classDefinition_ = nullptr; + recordTable_->interfaceDeclaration_ = interfaceDecl; + recordIdent_ = interfaceDecl->Id(); + interfaceDecl->SetInternalName(FormRecordName()); +} + +BoundContext::~BoundContext() +{ + recordTable_->classDefinition_ = savedClassDefinition_; + recordTable_->interfaceDeclaration_ = savedInterfaceDeclaration_; + recordTable_->boundCtx_ = prev_; +} + +util::StringView BoundContext::FormRecordName() const +{ + auto packageName = recordTable_->program_->GetPackageName(); + if (prev_ == nullptr && packageName.Empty()) { + return recordIdent_->Name(); + } + + util::UString recordName(recordTable_->program_->Allocator()); + if (prev_ == nullptr && !packageName.Empty()) { + recordName.Append(packageName); + recordName.Append(compiler::Signatures::METHOD_SEPARATOR); + recordName.Append(recordIdent_->Name()); + return recordName.View(); + } + + recordName.Append(prev_->FormRecordName()); + recordName.Append(compiler::Signatures::METHOD_SEPARATOR); + recordName.Append(recordIdent_->Name()); + return recordName.View(); +} + +util::StringView RecordTable::RecordName() const +{ + if (classDefinition_) { + return classDefinition_->InternalName(); + } + + return interfaceDeclaration_->Id()->Name(); +} + +} // namespace panda::es2panda::binder diff --git a/binder/recordTable.h b/binder/recordTable.h new file mode 100644 index 0000000000000000000000000000000000000000..986679db086441e95e84d6320c5a197d8f9a131e --- /dev/null +++ b/binder/recordTable.h @@ -0,0 +1,184 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_recordTable_RECORD_TABLE_H +#define ES2PANDA_recordTable_RECORD_TABLE_H + +#include "macros.h" +#include "utils/arena_containers.h" +#include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +namespace panda::es2panda::parser { +class Program; +} // namespace panda::es2panda::parser + +namespace panda::es2panda::checker { +class Signature; +} // namespace panda::es2panda::checker + +namespace panda::es2panda::ir { +class ClassDefinition; +class TSInterfaceDeclaration; +class Identifier; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::binder { +class FunctionScope; +class BoundContext; + +enum class RecordTableFlags { + NONE = 0, + EXTERNAL = 1 << 0, +}; + +DEFINE_BITOPS(RecordTableFlags) + +class RecordTable { +public: + explicit RecordTable(ArenaAllocator *allocator, parser::Program *program, RecordTableFlags flags) + : classDefinitions_(allocator->Adapter()), + interfaceDeclarations_(allocator->Adapter()), + signatures_(allocator->Adapter()), + program_(program), + flags_(flags) + { + } + + NO_COPY_SEMANTIC(RecordTable); + NO_MOVE_SEMANTIC(RecordTable); + + ~RecordTable() = default; + + bool IsExternal() const + { + return (flags_ & RecordTableFlags::EXTERNAL) != 0; + } + + ArenaUnorderedSet &ClassDefinitions() + { + return classDefinitions_; + } + + const ArenaUnorderedSet &ClassDefinitions() const + { + return classDefinitions_; + } + + ArenaUnorderedSet &InterfaceDeclarations() + { + return interfaceDeclarations_; + } + + const ArenaUnorderedSet &InterfaceDeclarations() const + { + return interfaceDeclarations_; + } + + ArenaVector &Signatures() + { + return signatures_; + } + + const ArenaVector &Signatures() const + { + return signatures_; + } + + void SetClassDefinition(ir::ClassDefinition *classDefinition) + { + classDefinition_ = classDefinition; + } + + ir::ClassDefinition *ClassDefinition() + { + return classDefinition_; + } + + const ir::ClassDefinition *ClassDefinition() const + { + return classDefinition_; + } + + void SetInterfaceDeclaration(ir::TSInterfaceDeclaration *interfaceDeclaration) + { + interfaceDeclaration_ = interfaceDeclaration; + } + + ir::TSInterfaceDeclaration *InterfaceDeclaration() + { + return interfaceDeclaration_; + } + + const ir::TSInterfaceDeclaration *InterfaceDeclaration() const + { + return interfaceDeclaration_; + } + + void SetProgram(parser::Program *program) + { + program_ = program; + } + + parser::Program *Program() + { + return program_; + } + + const parser::Program *Program() const + { + return program_; + } + + util::StringView RecordName() const; + +private: + friend class BoundContext; + + ArenaUnorderedSet classDefinitions_; + ArenaUnorderedSet interfaceDeclarations_; + ArenaVector signatures_; + ir::ClassDefinition *classDefinition_ {}; + ir::TSInterfaceDeclaration *interfaceDeclaration_ {}; + parser::Program *program_ {}; + BoundContext *boundCtx_ {}; + RecordTableFlags flags_ {}; +}; + +class BoundContext { +public: + explicit BoundContext(RecordTable *recordTable, ir::ClassDefinition *classDef); + explicit BoundContext(RecordTable *recordTable, ir::TSInterfaceDeclaration *interfaceDecl); + ~BoundContext(); + + NO_COPY_SEMANTIC(BoundContext); + NO_MOVE_SEMANTIC(BoundContext); + + void *operator new(size_t) = delete; + void *operator new[](size_t) = delete; + + util::StringView FormRecordName() const; + +private: + BoundContext *prev_; + RecordTable *recordTable_; + ir::ClassDefinition *savedClassDefinition_ {}; + ir::TSInterfaceDeclaration *savedInterfaceDeclaration_ {}; + ir::Identifier *recordIdent_; +}; + +} // namespace panda::es2panda::binder + +#endif diff --git a/binder/scope.cpp b/binder/scope.cpp index 2c8fbad997d3e74a091816c23022c34846318d46..0287fd67bb8d7bbf8eea2bb91673d59952d1d22d 100644 --- a/binder/scope.cpp +++ b/binder/scope.cpp @@ -200,6 +200,10 @@ bool Scope::AddLocal(ArenaAllocator *allocator, Variable *currentVariable, Decl bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::INTERFACE)}); return true; } + case DeclType::TYPE_PARAMETER: { + bindings_.insert({newDecl->Name(), allocator->New(newDecl, VariableFlags::TYPE_PARAMETER)}); + return true; + } case DeclType::FUNC: { flags = VariableFlags::HOIST; [[fallthrough]]; @@ -227,7 +231,7 @@ void VariableScope::CheckDirectEval(compiler::CompilerContext *compilerCtx) { ASSERT(compilerCtx); - if (!HasFlag(VariableScopeFlags::NO_REG_STORE) || bindings_.empty()) { + if (!HasFlag(ScopeFlags::NO_REG_STORE) || bindings_.empty()) { evalBindings_ = compiler::INVALID_LITERAL_BUFFER_ID; return; } @@ -291,8 +295,7 @@ bool ParamScope::AddParam(ArenaAllocator *allocator, Variable *currentVariable, return true; } -std::tuple ParamScope::AddParamDecl(ArenaAllocator *allocator, - const ir::AstNode *param) +std::tuple ParamScope::AddParamDecl(ArenaAllocator *allocator, ir::AstNode *param) { const auto [name, pattern] = util::Helpers::ParamName(allocator, param, params_.size()); @@ -307,9 +310,9 @@ std::tuple ParamScope::AddParamDecl(ArenaA return {decl, nullptr}; } - std::vector bindings = util::Helpers::CollectBindingNames(param); + std::vector bindings = util::Helpers::CollectBindingNames(param); - for (const auto *binding : bindings) { + for (auto *binding : bindings) { auto *varDecl = NewDecl(allocator, binding->Name()); varDecl->BindNode(binding); @@ -427,7 +430,7 @@ bool ModuleScope::AddBinding(ArenaAllocator *allocator, Variable *currentVariabl } } -void ModuleScope::AddImportDecl(const ir::ImportDeclaration *importDecl, ImportDeclList &&decls) +void ModuleScope::AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls) { auto res = imports_.emplace_back(importDecl, decls); @@ -436,7 +439,7 @@ void ModuleScope::AddImportDecl(const ir::ImportDeclaration *importDecl, ImportD } } -void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl) +void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl) { decl->BindNode(exportDecl); @@ -446,7 +449,7 @@ void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl) AddExportDecl(exportDecl, std::move(decls)); } -void ModuleScope::AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList &&decls) +void ModuleScope::AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls) { auto res = exports_.emplace_back(exportDecl, decls); diff --git a/binder/scope.h b/binder/scope.h index 9beb2fcc0640436b2d853651e379bb6103966334..94180b325b721b2d631abe17fda5f93b285f21c4 100644 --- a/binder/scope.h +++ b/binder/scope.h @@ -18,7 +18,7 @@ #include "plugins/ecmascript/es2panda/binder/declaration.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/es2panda.h" #include "plugins/ecmascript/es2panda/util/enumbitops.h" #include "plugins/ecmascript/es2panda/util/ustring.h" @@ -71,7 +71,7 @@ public: virtual ScopeType Type() const = 0; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DECLARE_CHECKS_CASTS(scopeType, className) \ +#define DECLARE_CHECKS_CAETS(scopeType, className) \ bool Is##className() const \ { \ return Type() == ScopeType::scopeType; \ @@ -86,8 +86,8 @@ public: ASSERT(Is##className()); \ return reinterpret_cast(this); \ } - SCOPE_TYPES(DECLARE_CHECKS_CASTS) -#undef DECLARE_CHECKS_CASTS + SCOPE_TYPES(DECLARE_CHECKS_CAETS) +#undef DECLARE_CHECKS_CAETS bool IsVariableScope() const { @@ -127,6 +127,21 @@ public: const VariableScope *EnclosingVariableScope() const; + void AddFlag(ScopeFlags flag) + { + flags_ |= flag; + } + + void ClearFlag(ScopeFlags flag) + { + flags_ &= ~flag; + } + + bool HasFlag(ScopeFlags flag) const + { + return (flags_ & flag) != 0; + } + const ArenaVector &Decls() const { return decls_; @@ -162,12 +177,17 @@ public: endIns_ = ins; } + ir::AstNode *Node() + { + return node_; + } + const ir::AstNode *Node() const { return node_; } - void BindNode(const ir::AstNode *node) + void BindNode(ir::AstNode *node) { node_ = node; } @@ -192,7 +212,7 @@ public: template static VariableType *CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, - const ir::AstNode *node); + ir::AstNode *node); template void PropagateBinding(ArenaAllocator *allocator, util::StringView name, Args &&...args); @@ -243,7 +263,8 @@ protected: Scope *parent_ {}; ArenaVector decls_; VariableMap bindings_; - const ir::AstNode *node_ {}; + ir::AstNode *node_ {}; + ScopeFlags flags_ {}; const compiler::IRNode *startIns_ {}; const compiler::IRNode *endIns_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -255,21 +276,6 @@ public: NO_COPY_SEMANTIC(VariableScope); NO_MOVE_SEMANTIC(VariableScope); - void AddFlag(VariableScopeFlags flag) - { - flags_ |= flag; - } - - void ClearFlag(VariableScopeFlags flag) - { - flags_ &= ~flag; - } - - bool HasFlag(VariableScopeFlags flag) const - { - return (flags_ & flag) != 0; - } - uint32_t NextSlot() { return slotIndex_++; @@ -309,7 +315,6 @@ protected: bool AddLexical(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - VariableScopeFlags flags_ {}; uint32_t evalBindings_ {}; uint32_t slotIndex_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -332,7 +337,7 @@ public: return params_; } - std::tuple AddParamDecl(ArenaAllocator *allocator, const ir::AstNode *param); + std::tuple AddParamDecl(ArenaAllocator *allocator, ir::AstNode *param); protected: explicit ParamScope(ArenaAllocator *allocator, Scope *parent) @@ -429,9 +434,13 @@ public: return ScopeType::FUNCTION; } - void BindName(util::StringView name, util::StringView internalName) + void BindName(util::StringView name) { name_ = name; + } + + void BindInternalName(util::StringView internalName) + { internalName_ = internalName; } @@ -604,12 +613,12 @@ public: return ScopeType::MODULE; } - const ModuleEntry &Imports() const + const ModuleEntry &Imports() const { return imports_; } - const ModuleEntry &Exports() const + const ModuleEntry &Exports() const { return exports_; } @@ -619,11 +628,11 @@ public: return localExports_; } - void AddImportDecl(const ir::ImportDeclaration *importDecl, ImportDeclList &&decls); + void AddImportDecl(ir::ImportDeclaration *importDecl, ImportDeclList &&decls); - void AddExportDecl(const ir::AstNode *exportDecl, ExportDecl *decl); + void AddExportDecl(ir::AstNode *exportDecl, ExportDecl *decl); - void AddExportDecl(const ir::AstNode *exportDecl, ExportDeclList &&decls); + void AddExportDecl(ir::AstNode *exportDecl, ExportDeclList &&decls); bool AddBinding(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl, [[maybe_unused]] ScriptExtension extension) override; @@ -634,8 +643,8 @@ private: bool AddImport(ArenaAllocator *allocator, Variable *currentVariable, Decl *newDecl); ArenaAllocator *allocator_; - ModuleEntry imports_; - ModuleEntry exports_; + ModuleEntry imports_; + ModuleEntry exports_; LocalExportNameMap localExports_; }; @@ -739,8 +748,7 @@ VariableType *Scope::AddDecl(ArenaAllocator *allocator, util::StringView name, V } template -VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, - const ir::AstNode *node) +VariableType *Scope::CreateVar(ArenaAllocator *allocator, util::StringView name, VariableFlags flags, ir::AstNode *node) { auto *decl = allocator->New(name); auto *variable = allocator->New(decl, flags); diff --git a/binder/variable.h b/binder/variable.h index ffa856132b7554a0cea5390034419e74124eeea8..563aafd9727e52c4ac0cc0a9e8a1092890ef1571 100644 --- a/binder/variable.h +++ b/binder/variable.h @@ -47,7 +47,7 @@ public: VariableType virtual Type() const = 0; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DECLARE_CHECKS_CASTS(variableType, className) \ +#define DECLARE_CHECKS_CAETS(variableType, className) \ bool Is##className() const \ { \ return Type() == VariableType::variableType; \ @@ -62,10 +62,15 @@ public: ASSERT(Is##className()); \ return reinterpret_cast(this); \ } - VARIABLE_TYPES(DECLARE_CHECKS_CASTS) -#undef DECLARE_CHECKS_CASTS + VARIABLE_TYPES(DECLARE_CHECKS_CAETS) +#undef DECLARE_CHECKS_CAETS - Decl *Declaration() const + const Decl *Declaration() const + { + return decl_; + } + + Decl *Declaration() { return decl_; } @@ -143,7 +148,7 @@ public: { ASSERT(!LexicalBound()); AddFlag(VariableFlags::LEXICAL_BOUND); - vreg_ = slot; + vreg_.SetIndex(slot); } compiler::VReg Vreg() const @@ -151,17 +156,22 @@ public: return vreg_; } + compiler::VReg &Vreg() + { + return vreg_; + } + uint32_t LexIdx() const { ASSERT(LexicalBound()); - return vreg_; + return vreg_.GetIndex(); } void SetLexical([[maybe_unused]] Scope *scope) override; LocalVariable *Copy(ArenaAllocator *allocator, Decl *decl) const; private: - uint32_t vreg_ {}; + compiler::VReg vreg_ {}; }; class GlobalVariable : public Variable { diff --git a/binder/variableFlags.h b/binder/variableFlags.h index 7be9b096f119e4b7bce0ecd3c2b1e79eedb097ca..39daef9f86192d6240f2f07ccd258c30beef7c9b 100644 --- a/binder/variableFlags.h +++ b/binder/variableFlags.h @@ -35,6 +35,7 @@ namespace panda::es2panda::binder { _(ENUM_LITERAL, EnumLiteralDecl) \ _(TYPE_PARAMETER, TypeParameterDecl) \ _(PROPERTY, PropertyDecl) \ + _(CLASS, ClassDecl) \ _(METHOD, MethodDecl) \ _(ENUM, EnumDecl) @@ -124,7 +125,16 @@ enum class VariableFlags : uint32_t { INITIALIZED = 0x80000U, LEXICAL_BOUND = 0x100000U, + TYPE_PARAMETER = 0x200000U, + STATIC = 0x400000U, + CLASS = 0x800000U, + EXPLICIT_INIT_REQUIRED = 0x1000000U, + PUBLIC = 0x2000000U, + PROTECTED = 0x4000000U, + PRIVATE = 0x8000000U, + HOIST_VAR = HOIST | VAR, + CLASS_OR_INTERFACE = CLASS | INTERFACE, }; DEFINE_BITOPS(VariableFlags) @@ -134,16 +144,17 @@ enum class LetOrConstStatus { UNINITIALIZED, }; -enum class VariableScopeFlags : uint32_t { +enum class ScopeFlags : uint32_t { NONE = 0x0U, SET_LEXICAL_FUNCTION = 0x1U, USE_ARGS = 0x2U, USE_SUPER = 0x4U, INNER_ARROW = 0x8U, NO_REG_STORE = 0x10U, + DEFER_STMT = 0x20U, }; -DEFINE_BITOPS(VariableScopeFlags) +DEFINE_BITOPS(ScopeFlags) } // namespace panda::es2panda::binder #endif diff --git a/checker/ASchecker.cpp b/checker/ASchecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..221945cbbab43c172d948f9081b546276ffa7cf5 --- /dev/null +++ b/checker/ASchecker.cpp @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "ASchecker.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::checker { + +bool ASChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + + if (options.dumpAst) { + std::cout << program_->Dump() << std::endl; + } + + return false; +} + +} // namespace panda::es2panda::checker diff --git a/checker/ASchecker.h b/checker/ASchecker.h new file mode 100644 index 0000000000000000000000000000000000000000..4f472e00f88a6dde6f262afdad3cde99803eed02 --- /dev/null +++ b/checker/ASchecker.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_CHECKER_AS_CHECKER_H +#define ES2PANDA_CHECKER_AS_CHECKER_H + +#include "plugins/ecmascript/es2panda/checker/checker.h" + +namespace panda::es2panda::checker { + +class ASChecker : public Checker { +public: + explicit ASChecker() : Checker() {} + + bool StartChecker([[maybe_unused]] binder::Binder *binder, + [[maybe_unused]] const CompilerOptions &options) override; + Type *CheckTypeCached([[maybe_unused]] ir::Expression *expr) override + { + return nullptr; + } + + void ResolveStructuredTypeMembers([[maybe_unused]] Type *type) override {} + + Type *GetTypeOfVariable([[maybe_unused]] binder::Variable *var) override + { + return nullptr; + } +}; + +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/checker/ETSchecker.cpp b/checker/ETSchecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65d3d9c5b4d7d2fe12f07645d3e221024679315f --- /dev/null +++ b/checker/ETSchecker.cpp @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "ETSchecker.h" + +#include "plugins/ecmascript/es2panda/ir/expression.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/checker/ets/aliveAnalyzer.h" + +namespace panda::es2panda::checker { +bool ETSChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + + if (options.dumpAst) { + std::cout << program_->Dump() << std::endl; + } + + if (options.parseOnly) { + return false; + } + + binder->SetGenStdLib(options.genStdLib); + binder->IdentifierAnalysis(); + + CheckProgram(program_, true); + + auto *etsBinder = static_cast(binder); + + for (auto *func : binder->Functions()) { + etsBinder->BuildFunctionName(func->Node()->AsScriptFunction()); + } + + return true; +} + +void ETSChecker::CheckProgram(parser::Program *program, bool runAnalysis) +{ + auto *savedProgram = program_; + program_ = program; + + for (auto &[package, extPrograms] : program->ExternalSources()) { + for (auto *extProg : extPrograms) { + CheckProgram(extProg); + } + } + + ASSERT(program_->Ast()->IsProgram()); + program_->Ast()->Check(this); + + if (runAnalysis) { + AliveAnalyzer(program_->Ast(), this); + } + + auto *binder = static_cast(binder_); + auto *recordTable = binder->GetExternalRecordTable().find(program)->second; + + InitializeRecordElements(binder, recordTable); + + program_ = savedProgram; +} + +void ETSChecker::InitializeRecordElements(binder::ETSBinder *binder, binder::RecordTable *recordTable) +{ + for (auto *func : recordTable->Signatures()) { + binder->BuildFunctionName(func->Node()->AsScriptFunction()); + } +} + +Type *ETSChecker::CheckTypeCached(ir::Expression *expr) +{ + if (!expr->TsType()) { + expr->SetTsType(expr->Check(this)); + } + + return expr->TsType(); +} +} // namespace panda::es2panda::checker diff --git a/checker/ETSchecker.h b/checker/ETSchecker.h new file mode 100644 index 0000000000000000000000000000000000000000..7f6a1774b6c00ee43b5a219ea2f9a0f481f37eb2 --- /dev/null +++ b/checker/ETSchecker.h @@ -0,0 +1,376 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_CHECKER_ETS_CHECKER_H +#define ES2PANDA_CHECKER_ETS_CHECKER_H + +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/binder/enumMemberResult.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" +#include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/primitiveWrappers.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" + +#include "macros.h" + +#include +#include +#include +#include + +namespace panda::es2panda::binder { +class Binder; +class Decl; +class EnumVariable; +class FunctionDecl; +class LocalVariable; +class Scope; +class Variable; +class ETSBinder; +class RecordTable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::checker { +enum class OperationType { + BITWISE_AND, + BITWISE_OR, + BITWISE_XOR, + LEFT_SHIFT, + RIGHT_SHIFT, + ADDITON, + SUBSTRACTION, + MULTIPLICATION, + DIVISION, + MOD, + LESS_THAN, + LESS_THAN_EQUAL, + GREATER_THAN, + GREATER_THAN_EQUAL, +}; + +enum class OverrideErrorCode { + NO_ERROR, + OVERRIDING_STATIC, + OVERRIDEN_STATIC, + OVERRIDEN_NOT_OPEN, + INCOMPATIBLE_RETURN, + OVERRIDEN_WEAKER, +}; + +using ComputedAbstracts = + ArenaUnorderedMap, std::unordered_set>>; +using ArrayMap = ArenaUnorderedMap; +using GlobalArraySignatureMap = ArenaUnorderedMap; + +class ETSChecker : public Checker { +public: + explicit ETSChecker() + : Checker(), + arrayTypes_(Allocator()->Adapter()), + globalArraySignatures_(Allocator()->Adapter()), + primitiveWrappers_(Allocator()), + cachedComputedAbstracts_(Allocator()->Adapter()) + { + } + + static inline TypeFlag ETSType(const Type *type) + { + return static_cast(type->TypeFlags() & TypeFlag::ETS_TYPE); + } + + static inline TypeFlag TypeKind(const Type *type) + { + return static_cast(type->TypeFlags() & checker::TypeFlag::ETS_TYPE); + } + + Type *GlobalByteType() const + { + return globalTypes_->GlobalByteType(); + } + + Type *GlobalShortType() const + { + return globalTypes_->GlobalShortType(); + } + + Type *GlobalIntType() const + { + return globalTypes_->GlobalIntType(); + } + + Type *GlobalLongType() const + { + return globalTypes_->GlobalLongType(); + } + + Type *GlobalFloatType() const + { + return globalTypes_->GlobalFloatType(); + } + + Type *GlobalDoubleType() const + { + return globalTypes_->GlobalDoubleType(); + } + + Type *GlobalCharType() const + { + return globalTypes_->GlobalCharType(); + } + + Type *GlobalETSBooleanType() const + { + return globalTypes_->GlobalETSBooleanType(); + } + + Type *GlobalVoidType() const + { + return globalTypes_->GlobalETSVoidType(); + } + + Type *GlobalETSObjectType() const + { + return globalTypes_->GlobalETSObjectType(); + } + + Type *GlobalETSNullType() const + { + return globalTypes_->GlobalETSNullType(); + } + + Type *GlobalETSStringType() const + { + return globalTypes_->GlobalETSStringType(); + } + + Type *GlobalWildcardType() const + { + return globalTypes_->GLobalWildcardType(); + } + + ETSObjectType *GlobalBuiltinObjectType() + { + return globalBuiltinObjectType_; + } + + const ETSObjectType *GlobalBuiltinObjectType() const + { + return globalBuiltinObjectType_; + } + + ETSObjectType *GlobalBuiltinClassType() + { + return globalBuiltinClassType_; + } + + const ETSObjectType *GlobalBuiltinClassType() const + { + return globalBuiltinClassType_; + } + + const ETSObjectType *GlobalBuiltinExceptionType() const + { + return globalBuiltinExceptionType_; + } + + checker::WrapperDesc PrimitiveWrapper() const + { + return primitiveWrappers_.Wrappers(); + } + + GlobalArraySignatureMap &GlobalArrayTypes() + { + return globalArraySignatures_; + } + + const GlobalArraySignatureMap &GlobalArrayTypes() const + { + return globalArraySignatures_; + } + + bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) override; + Type *CheckTypeCached(ir::Expression *expr) override; + void ResolveStructuredTypeMembers([[maybe_unused]] Type *type) override {} + Type *GetTypeOfVariable([[maybe_unused]] binder::Variable *var) override; + + // Object + ETSObjectType *BuildClassProperties(ir::ClassDefinition *classDef); + ETSObjectType *BuildAnonymousClassProperties(ir::ClassDefinition *classDef, ETSObjectType *superType); + ETSObjectType *BuildInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl); + ETSObjectType *GetSuperType(ETSObjectType *type); + ArenaVector GetInterfaces(ETSObjectType *type); + ArenaVector GetInterfacesOfClass(ETSObjectType *type); + ArenaVector GetInterfacesOfInterface(ETSObjectType *type); + void ValidateImplementedInterface(ETSObjectType *type, Type *interface, std::unordered_set *extendsSet, + const lexer::SourcePosition &pos); + void ResolveDeclaredMembersOfObject(ETSObjectType *type); + Type *ValidateArrayIndex(ir::Expression *expr); + Type *CheckArrayElementAccess(ir::MemberExpression *expr); + ETSObjectType *CheckThisOrSuperAccess(ir::Expression *node, ETSObjectType *classType, std::string_view msg); + void CreateTypeForClassTypeParameters(ETSObjectType *type); + void CreateTypeForInterfaceTypeParameters(ETSObjectType *type); + void SetTypeParameterType(ir::TSTypeParameter *typeParam, Type *assemblerType); + void ValidateOverriding(ETSObjectType *classType, const lexer::SourcePosition &pos); + void AddImplementedSignature(std::vector *implementedSignatures, binder::LocalVariable *function, + ETSFunctionType *it); + void CheckInnerClassMembers(const ETSObjectType *classType); + void CheckClassDefinition(ir::ClassDefinition *classDef); + void FindAssignment(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized); + void FindAssignments(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized); + void CheckConstFields(const ETSObjectType *classType); + void CheckConstFieldInitialized(const ETSObjectType *classType, binder::LocalVariable *prop); + void CheckConstFieldInitialized(const Signature *signature, binder::LocalVariable *prop); + void ComputeAbstractsFromInterface(ETSObjectType *interfaceType); + ArenaVector &GetAbstractsForClass(ETSObjectType *classType); + const std::vector CollectAbstractSignaturesFromObject(ETSObjectType *objType); + void CreateFunctionTypesFromAbstracts(const std::vector &abstracts, + ArenaVector *target); + void CheckCyclicContructorCall(Signature *signature); + + // Type creation + ByteType *CreateByteType(int8_t value); + ETSBooleanType *CreateETSBooleanType(bool value); + DoubleType *CreateDoubleType(double value); + FloatType *CreateFloatType(float value); + IntType *CreateIntType(int32_t value); + LongType *CreateLongType(int64_t value); + ShortType *CreateShortType(int16_t value); + CharType *CreateCharType(char16_t value); + ETSStringType *CreateETSStringType(util::StringView value); + ETSArrayType *CreateETSArrayType(Type *elementType); + ETSFunctionType *CreateETSFunctionType(Signature *signature); + ETSFunctionType *CreateETSFunctionType(util::StringView name); + ETSTypeReference *CreateTypeReference(Type **ref, Type **assemblerRef, binder::LocalVariable *refVar); + ETSTypeParameter *CreateTypeParameter(Type *assemblerType); + ETSObjectType *CreateETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags); + std::tuple CreateBuiltinArraySignatureInfo(ETSArrayType *arrayType, size_t dim); + Signature *CreateBuiltinArraySignature(ETSArrayType *arrayType, size_t dim); + IntType *CreateIntTypeFromType(Type *type); + ETSObjectType *CreateNewETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags); + + Signature *CreateSignature(SignatureInfo *info, Type *returnType, ir::ScriptFunction *func); + Signature *CreateSignature(SignatureInfo *info, Type *returnType, util::StringView internalName); + SignatureInfo *CreateSignatureInfo(); + + // Arithmetic + Type *NegateNumericType(Type *type, ir::Expression *node); + Type *BitwiseNegateIntegralType(Type *type, ir::Expression *node); + std::tuple CheckBinaryOperator(ir::Expression *left, ir::Expression *right, + lexer::TokenType operationType, lexer::SourcePosition pos); + Type *HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + template + Type *PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + + Type *HandleRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + template + Type *PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType); + + // Function + bool ValidateSignature(Signature *signature, const ArenaVector &arguments, + const lexer::SourcePosition &pos, TypeRelationFlag initialFlags); + Signature *ValidateSignatures(ArenaVector &signatures, const ArenaVector &arguments, + const lexer::SourcePosition &pos, std::string_view signatureKind, + TypeRelationFlag flags); + Signature *ResolveCallExpression(ArenaVector &signatures, + const ArenaVector &arguments, const lexer::SourcePosition &pos, + bool isIdentifier); + + Signature *ResolveConstructExpression(ETSObjectType *type, const ArenaVector &arguments, + const lexer::SourcePosition &pos); + checker::ETSFunctionType *BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig = false); + checker::ETSFunctionType *BuildMethodSignature(ir::MethodDefinition *method); + Signature *CheckEveryAbstractSignatureIsOverriden(ETSFunctionType *target, ETSFunctionType *source); + Signature *GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef); + void CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload, + const lexer::SourcePosition &overloadStart); + void CheckOverride(Signature *signature); + bool CheckOverride(Signature *signature, ETSObjectType *site); + std::tuple CheckOverride(Signature *signature, Signature *other); + bool IsMethodOverridesOther(Signature *target, Signature *source); + bool IsOverridableIn(Signature *signature); + void ValidateSignatureAccessibility(ETSObjectType *callee, Signature *signature, const lexer::SourcePosition &pos); + + // Helpers + Type *GetReferencedTypeFromBase(Type *baseType, ir::Expression *name); + Type *GetReferencedTypeBase(ir::Expression *name); + Type *GetTypeFromInterfaceReference(binder::Variable *var); + Type *GetTypeFromClassReference(binder::Variable *var); + Type *GetTypeFromEnumReference(binder::Variable *var); + Type *GetTypeFromTypeParameterReference(binder::LocalVariable *var, const lexer::SourcePosition &pos); + Type *GetDefaultTypeFromPrimitiveType(Type *type); + bool IsConstantExpression(ir::Expression *expr, Type *type); + void ValidateUnaryOperatorOperand(binder::Variable *variable); + std::tuple ApplyBinaryOperatorPromotion(Type *left, Type *right, TypeFlag test); + Type *ApplyUnaryOperatorPromotion(Type *type, bool createConst = true); + Type *HandleBooleanLogicalOperators(Type *leftType, Type *rightType, lexer::TokenType tokenType); + checker::Type *CheckVariableDeclaration(checker::ETSChecker *checker, ir::Identifier *ident, + ir::TypeNode *typeAnnotation, ir::Expression *init, + ir::ModifierFlags flags); + void CheckTruthinessOfType(Type *type, const lexer::SourcePosition &pos); + void ConcantConstantString(util::UString &target, Type *type); + Type *HandleStringConcatenation(Type *leftType, Type *rightType); + Type *ResolveIdentifier(ir::Identifier *ident); + ETSFunctionType *FindFunctionInVectorGivenByName(util::StringView name, ArenaVector &list); + void MergeComputedAbstracts(ArenaVector &merged, ArenaVector ¤t); + void MergeSignatures(ETSFunctionType *target, ETSFunctionType *source); + ir::AstNode *FindAncestorGivenByType(ir::AstNode *node, ir::AstNodeType type); + util::StringView GetContainingObjectNameFromSignature(Signature *signature); + bool IsFunctionContainsSignature(ETSFunctionType *funcType, Signature *signature); + void CheckFunctionContainsClashingSignature(const ETSFunctionType *funcType, Signature *signature); + bool IsTypeBuiltinType(Type *type); + const ir::AstNode *FindJumpTarget(ir::AstNodeType nodeType, const ir::AstNode *node, const ir::Identifier *target); + void ValidatePropertyAccess(binder::Variable *var, ETSObjectType *obj, const lexer::SourcePosition &pos); + binder::VariableFlags GetAccessFlagFromNode(const ir::AstNode *node); + + // Exception + ETSObjectType *CheckExceptionType(checker::Type *type, lexer::SourcePosition pos); + ETSObjectType *CheckRuntimeExceptionType(checker::Type *type, lexer::SourcePosition pos); + + static Type *TryToInstantiate(Type *type, ArenaAllocator *allocator, TypeRelation *relation, + GlobalTypesHolder *globalTypes); + +private: + void CreateTypeForTypeParameters(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParams); + ETSObjectType *CheckException(checker::Type *type, lexer::SourcePosition pos, ETSObjectType *expected, + std::string_view msg); + ETSObjectType *CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags); + void CheckProgram(parser::Program *program, bool runAnalysis = false); + void InitializeRecordElements(binder::ETSBinder *binder, binder::RecordTable *recordTable); + + template + UType HandleModulo(UType leftValue, UType rightValue); + + template + UType HandleBitWiseArithmetic(UType leftValue, UType rightValue, lexer::TokenType operationType); + + template + typename TargetType::UType GetOperand(Type *type); + + ArrayMap arrayTypes_; + GlobalArraySignatureMap globalArraySignatures_; + PrimitiveWrappers primitiveWrappers_; + ComputedAbstracts cachedComputedAbstracts_; + ETSObjectType *globalBuiltinStringType_ {}; + ETSObjectType *globalBuiltinObjectType_ {}; + ETSObjectType *globalBuiltinExceptionType_ {}; + ETSObjectType *globalBuiltinRuntimeExceptionType_ {}; + ETSObjectType *globalBuiltinClassType_ {}; +}; + +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/checker/JSchecker.cpp b/checker/JSchecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..964a1b5673529635c1f3cae24c3d53dc14db9281 --- /dev/null +++ b/checker/JSchecker.cpp @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "JSchecker.h" + +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::checker { + +bool JSChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + binder->IdentifierAnalysis(); + + if (options.dumpAst) { + std::cout << program_->Dump() << std::endl; + } + + return !options.parseOnly; +} + +} // namespace panda::es2panda::checker diff --git a/checker/JSchecker.h b/checker/JSchecker.h new file mode 100644 index 0000000000000000000000000000000000000000..14cad67db185572dc74626d79f4c8b9c04366721 --- /dev/null +++ b/checker/JSchecker.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_CHECKER_JS_CHECKER_H +#define ES2PANDA_CHECKER_JS_CHECKER_H + +#include "plugins/ecmascript/es2panda/checker/checker.h" + +namespace panda::es2panda::checker { + +class JSChecker : public Checker { +public: + explicit JSChecker() : Checker() {} + + bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) override; + + Type *CheckTypeCached([[maybe_unused]] ir::Expression *expr) override + { + return nullptr; + } + + void ResolveStructuredTypeMembers([[maybe_unused]] Type *type) override {} + + Type *GetTypeOfVariable([[maybe_unused]] binder::Variable *var) override + { + return nullptr; + } +}; + +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/checker/TSchecker.cpp b/checker/TSchecker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fee813306f3376f0baf6a8470a43ffafb0706130 --- /dev/null +++ b/checker/TSchecker.cpp @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "TSchecker.h" + +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::checker { + +bool TSChecker::StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) +{ + Initialize(binder); + binder->IdentifierAnalysis(); + + if (options.dumpAst) { + std::cout << program_->Dump() << std::endl; + } + + if (options.parseOnly) { + return false; + } + + ASSERT(program_->Ast()->IsProgram()); + program_->Ast()->Check(this); + + return false; +} + +Type *TSChecker::CheckTypeCached(ir::Expression *expr) +{ + if (!expr->TsType()) { + expr->SetTsType(expr->Check(this)); + } + + return expr->TsType(); +} + +} // namespace panda::es2panda::checker diff --git a/typescript/checker.h b/checker/TSchecker.h similarity index 51% rename from typescript/checker.h rename to checker/TSchecker.h index dd3365372957b9a8d2e49e90ebfc509dc6e5c0df..6c475a4e122ced99a70ff95d1f11752e03ea8683 100644 --- a/typescript/checker.h +++ b/checker/TSchecker.h @@ -13,14 +13,13 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_CHECKER_H -#define ES2PANDA_COMPILER_TYPESCRIPT_CHECKER_H +#ifndef ES2PANDA_CHECKER_TS_CHECKER_H +#define ES2PANDA_CHECKER_TS_CHECKER_H +#include "plugins/ecmascript/es2panda/checker/checker.h" #include "plugins/ecmascript/es2panda/binder/enumMemberResult.h" -#include "plugins/ecmascript/es2panda/typescript/core/checkerContext.h" -#include "plugins/ecmascript/es2panda/typescript/types/globalTypesHolder.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeRelation.h" -#include "plugins/ecmascript/es2panda/typescript/types/types.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/types.h" #include "plugins/ecmascript/es2panda/util/enumbitops.h" #include "plugins/ecmascript/es2panda/util/ustring.h" #include "macros.h" @@ -104,36 +103,10 @@ enum class AstNodeType; } // namespace panda::es2panda::ir namespace panda::es2panda::checker { -using StringLiteralPool = std::unordered_map; -using NumberLiteralPool = std::unordered_map; -using FunctionParamsResolveResult = std::variant &, bool>; -using InterfacePropertyMap = std::unordered_map>; -using TypeOrNode = std::variant; -using IndexInfoTypePair = std::pair; -using PropertyMap = std::unordered_map; -using ArgRange = std::pair; - -class Checker { -public: - explicit Checker(ArenaAllocator *allocator, binder::Binder *binder); - ~Checker() = default; - NO_COPY_SEMANTIC(Checker); - NO_MOVE_SEMANTIC(Checker); - ArenaAllocator *Allocator() const - { - return allocator_; - } - - binder::Binder *Binder() - { - return binder_; - } - - binder::Scope *Scope() const - { - return scope_; - } +class TSChecker : public Checker { +public: + explicit TSChecker() : Checker() {} Type *GlobalNumberType() { @@ -250,26 +223,6 @@ public: return globalTypes_->GlobalErrorType(); } - CheckerContext Context() - { - return context_; - } - - bool HasStatus(CheckerStatus status) - { - return (context_.Status() & status) != 0; - } - - void RemoveStatus(CheckerStatus status) - { - context_.Status() &= ~status; - } - - void AddStatus(CheckerStatus status) - { - context_.Status() |= status; - } - NumberLiteralPool &NumberLiteralMap() { return numberLiteralMap_; @@ -285,82 +238,44 @@ public: return bigintLiteralMap_; } - TypeRelation *Relation() - { - return relation_; - } - - RelationHolder &IdenticalResults() - { - return identicalResults_; - } - - RelationHolder &AssignableResults() - { - return assignableResults_; - } - - RelationHolder &ComparableResults() - { - return comparableResults_; - } - - std::unordered_set &TypeStack() - { - return typeStack_; - } - - std::unordered_map &NodeCache() - { - return nodeCache_; - } - - void StartChecker(); - - Type *CheckTypeCached(const ir::Expression *expr); - - [[noreturn]] void ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos); - [[noreturn]] void ThrowTypeError(std::initializer_list list, - const lexer::SourcePosition &pos); + bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) override; + Type *CheckTypeCached(ir::Expression *expr) override; // Util - static bool InAssignment(const ir::AstNode *node); + static bool InAssignment(ir::AstNode *node); static bool IsAssignmentOperator(lexer::TokenType op); static bool IsLiteralType(const Type *type); - static const ir::AstNode *FindAncestorGivenByType(const ir::AstNode *node, ir::AstNodeType type); - static const ir::AstNode *FindAncestorUntilGivenType(const ir::AstNode *node, ir::AstNodeType stop); + static ir::AstNode *FindAncestorUntilGivenType(ir::AstNode *node, ir::AstNodeType stop); static bool MaybeTypeOfKind(const Type *type, TypeFlag flags); static bool MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind); - static bool IsConstantMemberAccess(const ir::Expression *expr); - static bool IsStringLike(const ir::Expression *expr); - static const ir::TSQualifiedName *ResolveLeftMostQualifiedName(const ir::TSQualifiedName *qualifiedName); - static const ir::MemberExpression *ResolveLeftMostMemberExpression(const ir::MemberExpression *expr); + static bool IsConstantMemberAccess(ir::Expression *expr); + static bool IsStringLike(ir::Expression *expr); + static ir::MemberExpression *ResolveLeftMostMemberExpression(ir::MemberExpression *expr); // Helpers void CheckTruthinessOfType(Type *type, lexer::SourcePosition lineInfo); Type *CheckNonNullType(Type *type, lexer::SourcePosition lineInfo); Type *GetBaseTypeOfLiteralType(Type *type); - void CheckReferenceExpression(const ir::Expression *expr, const char *invalidReferenceMsg, + void CheckReferenceExpression(ir::Expression *expr, const char *invalidReferenceMsg, const char *invalidOptionalChainMsg); - void CheckTestingKnownTruthyCallableOrAwaitableType(const ir::Expression *condExpr, Type *type, - const ir::AstNode *body); + void CheckTestingKnownTruthyCallableOrAwaitableType(ir::Expression *condExpr, Type *type, ir::AstNode *body); Type *ExtractDefinitelyFalsyTypes(Type *type); Type *RemoveDefinitelyFalsyTypes(Type *type); TypeFlag GetFalsyFlags(Type *type); - bool IsVariableUsedInConditionBody(const ir::AstNode *parent, binder::Variable *searchVar); - bool FindVariableInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar); - bool IsVariableUsedInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar); + bool IsVariableUsedInConditionBody(ir::AstNode *parent, binder::Variable *searchVar); + bool FindVariableInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar); + bool IsVariableUsedInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar); [[noreturn]] void ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *rightType, lexer::SourcePosition lineInfo); [[noreturn]] void ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosition lineInfo, bool isAsSrcLeftType = false); - void ElaborateElementwise(Type *targetType, const ir::Expression *sourceNode, const lexer::SourcePosition &pos); - void InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *declarator); - Type *GetTypeOfVariable(binder::Variable *var); + void ElaborateElementwise(Type *targetType, ir::Expression *sourceNode, const lexer::SourcePosition &pos); + void InferSimpleVariableDeclaratorType(ir::VariableDeclarator *declarator); + Type *GetTypeOfVariable(binder::Variable *var) override; Type *GetUnaryResultType(Type *operandType); - Type *GetTypeFromClassOrInterfaceReference(const ir::TSTypeReference *node, binder::Variable *var); - Type *GetTypeFromTypeAliasReference(const ir::TSTypeReference *node, binder::Variable *var); - Type *GetTypeReferenceType(const ir::TSTypeReference *node, binder::Variable *var); + Type *GetTypeFromClassOrInterfaceReference(ir::TSTypeReference *node, binder::Variable *var); + Type *GetTypeFromTypeAliasReference(ir::TSTypeReference *node, binder::Variable *var); + Type *GetTypeReferenceType(ir::TSTypeReference *node, binder::Variable *var); // Type creation Type *CreateNumberLiteralType(double value); @@ -379,12 +294,12 @@ public: Type *CreateObjectTypeWithConstructSignature(Signature *constructSignature); // Object - void ResolvePropertiesOfObjectType(ObjectType *type, const ir::Expression *member, - ArenaVector &signatureDeclarations, - ArenaVector &indexDeclarations, bool isInterface); + void ResolvePropertiesOfObjectType(ObjectType *type, ir::AstNode *member, + ArenaVector &signatureDeclarations, + ArenaVector &indexDeclarations, bool isInterface); void ResolveSignaturesOfObjectType(ObjectType *type, - ArenaVector &signatureDeclarations); - void ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector &indexDeclarations); + ArenaVector &signatureDeclarations); + void ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector &indexDeclarations); void ResolveDeclaredMembers(InterfaceType *type); bool ValidateInterfaceMemberRedeclaration(ObjectType *type, binder::Variable *prop, const lexer::SourcePosition &locInfo); @@ -393,142 +308,64 @@ public: binder::Variable *GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, binder::VariableFlags propagateFlags); void CheckIndexConstraints(Type *type); - void ResolveStructuredTypeMembers(Type *type); void ResolveUnionTypeMembers(UnionType *type); void ResolveObjectTypeMembers(ObjectType *type); void ResolveInterfaceOrClassTypeMembers(InterfaceType *type); - Type *CheckComputedPropertyName(const ir::Expression *key); + Type *CheckComputedPropertyName(ir::Expression *key); Type *GetPropertyTypeForIndexType(Type *type, Type *indexType); IndexInfo *GetApplicableIndexInfo(Type *type, Type *indexType); ArenaVector GetBaseTypes(InterfaceType *type); + void ResolveStructuredTypeMembers(Type *type) override; // Function - Type *HandleFunctionReturn(const ir::ScriptFunction *func); + Type *HandleFunctionReturn(ir::ScriptFunction *func); void CheckFunctionParameterDeclarations(const ArenaVector ¶ms, SignatureInfo *signatureInfo); std::tuple CheckFunctionParameter( - const ir::Expression *param, SignatureInfo *signatureInfo); + ir::Expression *param, SignatureInfo *signatureInfo); std::tuple CheckFunctionIdentifierParameter( - const ir::Identifier *param); + ir::Identifier *param); std::tuple CheckFunctionAssignmentPatternParameter( - const ir::AssignmentExpression *param); + ir::AssignmentExpression *param); std::tuple CheckFunctionRestParameter( - const ir::SpreadElement *param, SignatureInfo *signatureInfo); + ir::SpreadElement *param, SignatureInfo *signatureInfo); std::tuple CheckFunctionArrayPatternParameter( - const ir::ArrayExpression *param); + ir::ArrayExpression *param); std::tuple CheckFunctionObjectPatternParameter( - const ir::ObjectExpression *param); + ir::ObjectExpression *param); void InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar); - void CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaVector *returnTypes); - void CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFunction *func, lexer::SourcePosition lineInfo, + void CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector *returnTypes); + void CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func, lexer::SourcePosition lineInfo, const char *errMsg); - void CreatePatternParameterName(const ir::AstNode *node, std::stringstream &ss); - void ThrowReturnTypeCircularityError(const ir::ScriptFunction *func); + void CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss); + void ThrowReturnTypeCircularityError(ir::ScriptFunction *func); ArgRange GetArgRange(const ArenaVector &signatures, ArenaVector *potentialSignatures, uint32_t callArgsSize, bool *haveSignatureWithRest); bool CallMatchesSignature(const ArenaVector &args, Signature *signature, bool throwError); Type *resolveCallOrNewExpression(const ArenaVector &signatures, ArenaVector arguments, const lexer::SourcePosition &errPos); - Type *CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpression *arrayPattern, Type *inferedType); - Type *CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExpression *objectPattern, Type *inferedType); - - // Type relation - bool IsTypeIdenticalTo(Type *source, Type *target); - bool IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); - bool IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list list, - const lexer::SourcePosition &errPos); - bool IsTypeAssignableTo(Type *source, Type *target); - bool IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); - bool IsTypeAssignableTo(Type *source, Type *target, std::initializer_list list, - const lexer::SourcePosition &errPos); - bool IsTypeComparableTo(Type *source, Type *target); - bool IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); - bool IsTypeComparableTo(Type *source, Type *target, std::initializer_list list, - const lexer::SourcePosition &errPos); - bool AreTypesComparable(Type *source, Type *target); - bool IsTypeEqualityComparableTo(Type *source, Type *target); - bool IsAllTypesAssignableTo(Type *source, Type *target); + Type *CreateParameterTypeForArrayAssignmentPattern(ir::ArrayExpression *arrayPattern, Type *inferedType); + Type *CreateParameterTypeForObjectAssignmentPattern(ir::ObjectExpression *objectPattern, Type *inferedType); // Binary like expression - Type *CheckBinaryOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op); - Type *CheckPlusOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op); - Type *CheckCompareOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op); - Type *CheckAndOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr); - Type *CheckOrOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr); - Type *CheckInstanceofExpression(Type *leftType, Type *rightType, const ir::Expression *rightExpr, - const ir::AstNode *expr); - Type *CheckInExpression(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr); - void CheckAssignmentOperator(lexer::TokenType op, const ir::Expression *leftExpr, Type *leftType, Type *valueType); - - friend class ScopeContext; - friend class SavedCheckerContext; + Type *CheckBinaryOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op); + Type *CheckPlusOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op); + Type *CheckCompareOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op); + Type *CheckAndOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr); + Type *CheckOrOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr); + Type *CheckInstanceofExpression(Type *leftType, Type *rightType, ir::Expression *rightExpr, ir::AstNode *expr); + Type *CheckInExpression(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr); + void CheckAssignmentOperator(lexer::TokenType op, ir::Expression *leftExpr, Type *leftType, Type *valueType); private: - ArenaAllocator *allocator_; - binder::Binder *binder_; - const ir::BlockStatement *rootNode_; - binder::Scope *scope_; - CheckerContext context_; - GlobalTypesHolder *globalTypes_; - NumberLiteralPool numberLiteralMap_; StringLiteralPool stringLiteralMap_; StringLiteralPool bigintLiteralMap_; - - TypeRelation *relation_; - - RelationHolder identicalResults_; - RelationHolder assignableResults_; - RelationHolder comparableResults_; - - std::unordered_set typeStack_; - std::unordered_map nodeCache_; - std::vector scopeStack_; }; -class ScopeContext { -public: - explicit ScopeContext(Checker *checker, binder::Scope *newScope) : checker_(checker), prevScope_(checker_->scope_) - { - checker_->scope_ = newScope; - } - - ~ScopeContext() - { - checker_->scope_ = prevScope_; - } - - NO_COPY_SEMANTIC(ScopeContext); - NO_MOVE_SEMANTIC(ScopeContext); - -private: - Checker *checker_; - binder::Scope *prevScope_; -}; - -class SavedCheckerContext { -public: - explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus) - : checker_(checker), prev_(checker->context_) - { - checker_->context_ = CheckerContext(newStatus); - } - - NO_COPY_SEMANTIC(SavedCheckerContext); - DEFAULT_MOVE_SEMANTIC(SavedCheckerContext); - - ~SavedCheckerContext() - { - checker_->context_ = prev_; - } - -private: - Checker *checker_; - CheckerContext prev_; -}; } // namespace panda::es2panda::checker #endif /* CHECKER_H */ diff --git a/typescript/core/typeRelation.cpp b/checker/checker.cpp similarity index 57% rename from typescript/core/typeRelation.cpp rename to checker/checker.cpp index 4bd2675be7187005957ada65edeb40bb3cf1385a..828e8d35defc31e36057e506ca373c9b602b23ca 100644 --- a/typescript/core/typeRelation.cpp +++ b/checker/checker.cpp @@ -13,11 +13,77 @@ * limitations under the License. */ -#include "plugins/ecmascript/es2panda/typescript/checker.h" - -#include +#include "checker.h" + +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/ir/expression.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/unionType.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +#include +#include +#include namespace panda::es2panda::checker { +Checker::Checker() + : allocator_(SpaceType::SPACE_TYPE_COMPILER, nullptr, true), + context_(CheckerStatus::NO_OPTS), + globalTypes_(allocator_.New(&allocator_)), + relation_(allocator_.New(this)) +{ +} + +void Checker::Initialize(binder::Binder *binder) +{ + binder_ = binder; + scope_ = binder_->TopScope(); + program_ = binder_->Program(); +} + +void Checker::ThrowTypeError(std::initializer_list list, const lexer::SourcePosition &pos) +{ + std::stringstream ss; + + for (const auto &it : list) { + if (std::holds_alternative(it)) { + ss << std::get(it); + } else if (std::holds_alternative(it)) { + ss << std::get(it); + } else if (std::holds_alternative(it)) { + ss << TokenToString(std::get(it)); + } else if (std::holds_alternative(it)) { + std::get(it)->ToString(ss); + } else if (std::holds_alternative(it)) { + std::get(it).GetType()->ToStringAsSrc(ss); + } else if (std::holds_alternative(it)) { + ss << std::to_string(std::get(it)); + } else if (std::holds_alternative(it)) { + std::get(it)->ToString(ss, nullptr, true); + } else { + UNREACHABLE(); + } + } + + std::string err = ss.str(); + ThrowTypeError(err, pos); +} + +void Checker::ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos) +{ + lexer::LineIndex index(program_->SourceCode()); + lexer::SourceLocation loc = index.GetLocation(pos); + + throw Error {ErrorType::TYPE, program_->SourceFile().Utf8(), message, loc.line, loc.col}; +} + bool Checker::IsAllTypesAssignableTo(Type *source, Type *target) { if (source->TypeFlags() == TypeFlag::UNION) { @@ -114,4 +180,5 @@ bool Checker::IsTypeEqualityComparableTo(Type *source, Type *target) { return target->HasTypeFlag(TypeFlag::NULLABLE) || IsTypeComparableTo(source, target); } + } // namespace panda::es2panda::checker diff --git a/checker/checker.h b/checker/checker.h new file mode 100644 index 0000000000000000000000000000000000000000..0764028eda188af27904ece1724acd11089e1121 --- /dev/null +++ b/checker/checker.h @@ -0,0 +1,269 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_CHECKER_CHECKER_H +#define ES2PANDA_CHECKER_CHECKER_H + +#include "plugins/ecmascript/es2panda/binder/enumMemberResult.h" +#include "plugins/ecmascript/es2panda/checker/checkerContext.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" +#include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/es2panda.h" +#include "macros.h" + +#include +#include +#include +#include + +namespace panda::es2panda::parser { +class Program; +} // namespace panda::es2panda::parser + +namespace panda::es2panda::ir { +class AstNode; +class Expression; +class BlockStatement; +enum class AstNodeType; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::binder { +class Binder; +class Decl; +class EnumVariable; +class FunctionDecl; +class LocalVariable; +class Scope; +class Variable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::checker { +class ETSChecker; +class InterfaceType; +class GlobalTypesHolder; + +using StringLiteralPool = std::unordered_map; +using NumberLiteralPool = std::unordered_map; +using FunctionParamsResolveResult = std::variant &, bool>; +using InterfacePropertyMap = std::unordered_map>; +using TypeOrNode = std::variant; +using IndexInfoTypePair = std::pair; +using PropertyMap = std::unordered_map; +using ArgRange = std::pair; + +class Checker { +public: + explicit Checker(); + ~Checker() = default; + NO_COPY_SEMANTIC(Checker); + NO_MOVE_SEMANTIC(Checker); + + ArenaAllocator *Allocator() + { + return &allocator_; + } + + binder::Binder *Binder() + { + return binder_; + } + + binder::Scope *Scope() const + { + return scope_; + } + + CheckerContext &Context() + { + return context_; + } + + bool HasStatus(CheckerStatus status) + { + return (context_.Status() & status) != 0; + } + + void RemoveStatus(CheckerStatus status) + { + context_.Status() &= ~status; + } + + void AddStatus(CheckerStatus status) + { + context_.Status() |= status; + } + + TypeRelation *Relation() + { + return relation_; + } + + GlobalTypesHolder *GetGlobalTypesHolder() + { + return globalTypes_; + } + + RelationHolder &IdenticalResults() + { + return identicalResults_; + } + + RelationHolder &AssignableResults() + { + return assignableResults_; + } + + RelationHolder &ComparableResults() + { + return comparableResults_; + } + + std::unordered_set &TypeStack() + { + return typeStack_; + } + + ETSChecker *AsETSChecker() + { + return reinterpret_cast(this); + } + + virtual bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) = 0; + virtual Type *CheckTypeCached(ir::Expression *expr) = 0; + virtual Type *GetTypeOfVariable(binder::Variable *var) = 0; + virtual void ResolveStructuredTypeMembers(Type *type) = 0; + + [[noreturn]] void ThrowTypeError(std::string_view message, const lexer::SourcePosition &pos); + [[noreturn]] void ThrowTypeError(std::initializer_list list, + const lexer::SourcePosition &pos); + + bool IsTypeIdenticalTo(Type *source, Type *target); + bool IsTypeIdenticalTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); + bool IsTypeIdenticalTo(Type *source, Type *target, std::initializer_list list, + const lexer::SourcePosition &errPos); + bool IsTypeAssignableTo(Type *source, Type *target); + bool IsTypeAssignableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); + bool IsTypeAssignableTo(Type *source, Type *target, std::initializer_list list, + const lexer::SourcePosition &errPos); + bool IsTypeComparableTo(Type *source, Type *target); + bool IsTypeComparableTo(Type *source, Type *target, const std::string &errMsg, const lexer::SourcePosition &errPos); + bool IsTypeComparableTo(Type *source, Type *target, std::initializer_list list, + const lexer::SourcePosition &errPos); + bool AreTypesComparable(Type *source, Type *target); + bool IsTypeEqualityComparableTo(Type *source, Type *target); + bool IsAllTypesAssignableTo(Type *source, Type *target); + + friend class ScopeContext; + friend class TypeStackElement; + friend class SavedCheckerContext; + +protected: + void Initialize(binder::Binder *binder); + + ArenaAllocator allocator_; + CheckerContext context_; + GlobalTypesHolder *globalTypes_; + TypeRelation *relation_; + binder::Binder *binder_ {}; + parser::Program *program_; + binder::Scope *scope_ {}; + + RelationHolder identicalResults_; + RelationHolder assignableResults_; + RelationHolder comparableResults_; + + std::unordered_set typeStack_; +}; + +class TypeStackElement { +public: + explicit TypeStackElement(Checker *checker, void *element, std::initializer_list list, + const lexer::SourcePosition &pos) + : checker_(checker), element_(element) + { + if (!checker->typeStack_.insert(element).second) { + checker_->ThrowTypeError(list, pos); + } + } + + explicit TypeStackElement(Checker *checker, void *element, std::string_view err, const lexer::SourcePosition &pos) + : checker_(checker), element_(element) + { + if (!checker->typeStack_.insert(element).second) { + checker_->ThrowTypeError(err, pos); + } + } + + ~TypeStackElement() + { + checker_->typeStack_.erase(element_); + } + + NO_COPY_SEMANTIC(TypeStackElement); + NO_MOVE_SEMANTIC(TypeStackElement); + +private: + Checker *checker_; + void *element_; +}; + +class ScopeContext { +public: + explicit ScopeContext(Checker *checker, binder::Scope *newScope) : checker_(checker), prevScope_(checker_->scope_) + { + checker_->scope_ = newScope; + } + + ~ScopeContext() + { + checker_->scope_ = prevScope_; + } + + NO_COPY_SEMANTIC(ScopeContext); + NO_MOVE_SEMANTIC(ScopeContext); + +private: + Checker *checker_; + binder::Scope *prevScope_; +}; + +class SavedCheckerContext { +public: + explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus) + : SavedCheckerContext(checker, newStatus, nullptr) + { + } + explicit SavedCheckerContext(Checker *checker, CheckerStatus newStatus, ETSObjectType *containingClass) + : checker_(checker), prev_(checker->context_) + { + checker_->context_ = CheckerContext(newStatus, containingClass); + } + + NO_COPY_SEMANTIC(SavedCheckerContext); + DEFAULT_MOVE_SEMANTIC(SavedCheckerContext); + + ~SavedCheckerContext() + { + checker_->context_ = prev_; + } + +private: + Checker *checker_; + CheckerContext prev_; +}; +} // namespace panda::es2panda::checker + +#endif /* CHECKER_H */ diff --git a/typescript/core/checkerContext.cpp b/checker/checkerContext.cpp similarity index 100% rename from typescript/core/checkerContext.cpp rename to checker/checkerContext.cpp diff --git a/typescript/core/checkerContext.h b/checker/checkerContext.h similarity index 57% rename from typescript/core/checkerContext.h rename to checker/checkerContext.h index 3aef77d6058ce515ba08c4ac34f4678e754853ff..453c684e2e93974ac23a1c082997def336c0a3c6 100644 --- a/typescript/core/checkerContext.h +++ b/checker/checkerContext.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_PARSER_CORE_CHECKER_CONTEXT_H -#define ES2PANDA_PARSER_CORE_CHECKER_CONTEXT_H +#ifndef ES2PANDA_CHECKER_CHECKER_CONTEXT_H +#define ES2PANDA_CHECKER_CHECKER_CONTEXT_H #include #include "plugins/ecmascript/es2panda/util/enumbitops.h" @@ -28,30 +28,61 @@ enum class CheckerStatus : uint32_t { IN_CONST_CONTEXT = 0x2U, KEEP_LITERAL_TYPE = 0x4U, IN_PARAMETER = 0x8U, + IN_CLASS = 0x10U, + IN_INTERFACE = 0x20U, + IN_ABSTRACT = 0x40U, + IN_STATIC_CONTEXT = 0x80U, + IN_CONSTRUCTOR = 0x100U, + IN_STATIC_BLOCK = 0x200U, + INNER_CLASS = 0x400U, }; +class ETSObjectType; +class Signature; + DEFINE_BITOPS(CheckerStatus) class CheckerContext { public: - explicit CheckerContext(CheckerStatus newStatus) : status_(newStatus) {} + explicit CheckerContext(CheckerStatus newStatus) : CheckerContext(newStatus, nullptr) {} + explicit CheckerContext(CheckerStatus newStatus, ETSObjectType *containingClass) + : status_(newStatus), containingClass_(containingClass) + { + } const CheckerStatus &Status() const { return status_; } + ETSObjectType *ContainingClass() const + { + return containingClass_; + } + + Signature *ContainingSignature() const + { + return containingSignature_; + } + CheckerStatus &Status() { return status_; } + void SetContainingSignature(Signature *containingSignature) + { + containingSignature_ = containingSignature; + } + DEFAULT_COPY_SEMANTIC(CheckerContext); DEFAULT_MOVE_SEMANTIC(CheckerContext); ~CheckerContext() = default; private: CheckerStatus status_; + ETSObjectType *containingClass_ {}; + Signature *containingSignature_ {nullptr}; }; } // namespace panda::es2panda::checker diff --git a/checker/ets/aliveAnalyzer.cpp b/checker/ets/aliveAnalyzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e25a4ed1dfdb464a94076a42b71680813ecde92e --- /dev/null +++ b/checker/ets/aliveAnalyzer.cpp @@ -0,0 +1,425 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "aliveAnalyzer.h" + +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/doWhileStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/expressionStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/whileStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/forUpdateStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/labelledStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/forOfStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/ifStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/switchStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" +#include "plugins/ecmascript/es2panda/ir/statements/throwStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/switchCaseStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/breakStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/continueStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/returnStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/tryStatement.h" +#include "plugins/ecmascript/es2panda/ir/expressions/callExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsNewClassInstanceExpression.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { + +void AliveAnalyzer::AnalyzeNodes(const ir::AstNode *node) +{ + node->Iterate([this](auto *childNode) { AnalyzeNode(childNode); }); +} + +void AliveAnalyzer::AnalyzeNode(const ir::AstNode *node) +{ + if (!node) { + return; + } + + switch (node->Type()) { + case ir::AstNodeType::EXPRESSION_STATEMENT: { + AnalyzeNode(node->AsExpressionStatement()->GetExpression()); + break; + } + case ir::AstNodeType::CLASS_DECLARATION: { + AnalyzeClassDecl(node->AsClassDeclaration()); + break; + } + case ir::AstNodeType::CLASS_DEFINITION: { + AnalyzeClassDef(node->AsClassDefinition()); + break; + } + case ir::AstNodeType::METHOD_DEFINITION: { + AnalyzeMethodDef(node->AsMethodDefinition()); + break; + } + case ir::AstNodeType::VARIABLE_DECLARATION: { + AnalyzeVarDef(node->AsVariableDeclaration()); + break; + } + case ir::AstNodeType::BLOCK_STATEMENT: { + AnalyzeStats(node->AsBlockStatement()->Statements()); + break; + } + case ir::AstNodeType::DO_WHILE_STATEMENT: { + AnalyzeDoLoop(node->AsDoWhileStatement()); + break; + } + case ir::AstNodeType::WHILE_STATEMENT: { + AnalyzeWhileLoop(node->AsWhileStatement()); + break; + } + case ir::AstNodeType::FOR_UPDATE_STATEMENT: { + AnalyzeForLoop(node->AsForUpdateStatement()); + break; + } + case ir::AstNodeType::FOR_OF_STATEMENT: { + AnalyzeForOfLoop(node->AsForOfStatement()); + break; + } + case ir::AstNodeType::IF_STATEMENT: { + AnalyzeIf(node->AsIfStatement()); + break; + } + case ir::AstNodeType::LABELLED_STATEMENT: { + AnalyzeLabelled(node->AsLabelledStatement()); + break; + } + case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION: { + AnalyzeNewClass(node->AsETSNewClassInstanceExpression()); + break; + } + case ir::AstNodeType::CALL_EXPRESSION: { + AnalyzeCall(node->AsCallExpression()); + break; + } + case ir::AstNodeType::THROW_STATEMENT: { + AnalyzeThrow(node->AsThrowStatement()); + break; + } + case ir::AstNodeType::SWITCH_STATEMENT: { + AnalyzeSwitch(node->AsSwitchStatement()); + break; + } + case ir::AstNodeType::TRY_STATEMENT: { + AnalyzeTry(node->AsTryStatement()); + break; + } + case ir::AstNodeType::BREAK_STATEMENT: { + AnalyzeBreak(node->AsBreakStatement()); + break; + } + case ir::AstNodeType::CONTINUE_STATEMENT: { + AnalyzeContinue(node->AsContinueStatement()); + break; + } + case ir::AstNodeType::RETURN_STATEMENT: { + AnalyzeReturn(node->AsReturnStatement()); + break; + } + default: { + break; + } + } +} + +void AliveAnalyzer::AnalyzeDef(const ir::AstNode *node) +{ + AnalyzeStat(node); + if (node && node->IsClassStaticBlock() && status_ == LivenessStatus::DEAD) { + checker_->ThrowTypeError("Initializer must be able to complete normally.", node->Start()); + } +} + +void AliveAnalyzer::AnalyzeStat(const ir::AstNode *node) +{ + if (!node) { + return; + } + + if (status_ == LivenessStatus::DEAD) { + checker_->ThrowTypeError("Unreachable statement.", node->Start()); + } + + if (node->IsClassStaticBlock()) { + AnalyzeNodes(node); + return; + } + + AnalyzeNode(node); +} + +void AliveAnalyzer::AnalyzeStats(const ArenaVector &stats) +{ + for (const auto *it : stats) { + AnalyzeStat(it); + } +} + +void AliveAnalyzer::ClearPendingExits() +{ + pendingExits_.clear(); +} + +static bool IsStaticMember(const ir::AstNode *node) +{ + switch (node->Type()) { + case ir::AstNodeType::CLASS_PROPERTY: { + return node->IsStatic(); + } + case ir::AstNodeType::CLASS_DECLARATION: { + return node->AsClassDeclaration()->Definition()->IsStatic(); + } + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + return node->IsStatic(); + } + default: { + return false; + } + } +} + +void AliveAnalyzer::AnalyzeClassDecl(const ir::ClassDeclaration *classDecl) +{ + for (const auto *it : classDecl->Definition()->Body()) { + AnalyzeNode(it); + } +} + +void AliveAnalyzer::AnalyzeClassDef(const ir::ClassDefinition *classDef) +{ + if (!classDef->Variable()) { + return; + } + + LivenessStatus prevStatus = status_; + PendingExitsVector oldPendingExits = std::move(pendingExits_); + + for (const auto *it : classDef->Body()) { + if (!it->IsMethodDefinition() && IsStaticMember(it)) { + AnalyzeDef(it); + ClearPendingExits(); + } + } + + for (const auto *it : classDef->Body()) { + if (!it->IsMethodDefinition() && !IsStaticMember(it)) { + AnalyzeDef(it); + ClearPendingExits(); + } + } + + for (const auto *it : classDef->Body()) { + if (it->IsClassStaticBlock()) { + AnalyzeDef(it); + break; + } + } + + for (const auto *it : classDef->Body()) { + if (it->IsMethodDefinition()) { + AnalyzeNode(it); + } + } + + pendingExits_ = std::move(oldPendingExits); + status_ = prevStatus; +} + +void AliveAnalyzer::AnalyzeMethodDef(const ir::MethodDefinition *methodDef) +{ + auto *func = methodDef->Function(); + + if (!func->Body()) { + return; + } + + status_ = LivenessStatus::ALIVE; + AnalyzeStat(func->Body()); + ASSERT(methodDef->TsType() && methodDef->TsType()->IsETSFunctionType()); + + if (status_ == LivenessStatus::ALIVE && + !methodDef->TsType()->AsETSFunctionType()->FindSignature(func)->ReturnType()->IsETSVoidType()) { + checker_->ThrowTypeError("Function with a non void return type must return a value.", func->Id()->Start()); + } + + ClearPendingExits(); +} + +void AliveAnalyzer::AnalyzeVarDef(const ir::VariableDeclaration *varDef) +{ + for (auto *it : varDef->Declarators()) { + if (!it->Init()) { + continue; + } + + AnalyzeNode(it->Init()); + } +} + +void AliveAnalyzer::AnalyzeDoLoop(const ir::DoWhileStatement *doWhile) +{ + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeStat(doWhile->Body()); + status_ = Or(status_, ResolveContinues(doWhile)); + AnalyzeNode(doWhile->Test()); + ASSERT(doWhile->Test()->TsType() && doWhile->Test()->TsType()->IsETSBooleanType()); + auto *condType = doWhile->Test()->TsType()->AsETSBooleanType(); + status_ = + And(status_, static_cast(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && condType->GetValue()))); + status_ = Or(status_, ResolveBreaks(doWhile, oldPendingExits)); +} + +void AliveAnalyzer::AnalyzeWhileLoop(const ir::WhileStatement *whileStmt) +{ + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeNode(whileStmt->Test()); + ASSERT(whileStmt->Test()->TsType() && whileStmt->Test()->TsType()->IsETSBooleanType()); + auto *condType = whileStmt->Test()->TsType()->AsETSBooleanType(); + status_ = And(status_, + static_cast(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && !condType->GetValue()))); + AnalyzeStat(whileStmt->Body()); + status_ = Or(status_, ResolveContinues(whileStmt)); + status_ = Or(ResolveBreaks(whileStmt, oldPendingExits), + From(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && condType->GetValue()))); +} + +void AliveAnalyzer::AnalyzeForLoop(const ir::ForUpdateStatement *forStmt) +{ + AnalyzeNode(forStmt->Init()); + PendingExitsVector oldPendingExits = std::move(pendingExits_); + const ETSBooleanType *condType {}; + if (forStmt->Test()) { + AnalyzeNode(forStmt->Test()); + ASSERT(forStmt->Test()->TsType() && forStmt->Test()->TsType()->IsETSBooleanType()); + condType = forStmt->Test()->TsType()->AsETSBooleanType(); + status_ = From(!(condType->HasTypeFlag(TypeFlag::CONSTANT) && !condType->GetValue())); + } else { + status_ = LivenessStatus::ALIVE; + } + + AnalyzeStat(forStmt->Body()); + status_ = Or(status_, ResolveContinues(forStmt)); + AnalyzeNode(forStmt->Update()); + status_ = Or(ResolveBreaks(forStmt, oldPendingExits), + From(condType && !(condType->HasTypeFlag(TypeFlag::CONSTANT) && condType->GetValue()))); +} + +void AliveAnalyzer::AnalyzeForOfLoop(const ir::ForOfStatement *forOfStmt) +{ + ASSERT(forOfStmt->Left()->IsVariableDeclaration()); + AnalyzeVarDef(forOfStmt->Left()->AsVariableDeclaration()); + AnalyzeNode(forOfStmt->Right()); + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeStat(forOfStmt->Body()); + status_ = Or(status_, ResolveContinues(forOfStmt)); + ResolveBreaks(forOfStmt, oldPendingExits); + status_ = LivenessStatus::ALIVE; +} + +void AliveAnalyzer::AnalyzeIf(const ir::IfStatement *ifStmt) +{ + AnalyzeNode(ifStmt->Test()); + AnalyzeStat(ifStmt->Consequent()); + if (ifStmt->Alternate()) { + LivenessStatus prevStatus = status_; + status_ = LivenessStatus::ALIVE; + AnalyzeStat(ifStmt->Alternate()); + status_ = Or(status_, prevStatus); + } else { + status_ = LivenessStatus::ALIVE; + } +} + +void AliveAnalyzer::AnalyzeLabelled(const ir::LabelledStatement *labelledStmt) +{ + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeStat(labelledStmt->Body()); + status_ = Or(status_, ResolveBreaks(labelledStmt, oldPendingExits)); +} + +void AliveAnalyzer::AnalyzeNewClass(const ir::ETSNewClassInstanceExpression *newClass) +{ + for (const auto *it : newClass->GetArguments()) { + AnalyzeNode(it); + } + + if (newClass->ClassDefinition()) { + AnalyzeNode(newClass->ClassDefinition()); + } +} + +void AliveAnalyzer::AnalyzeCall(const ir::CallExpression *callExpr) +{ + AnalyzeNode(callExpr->Callee()); + for (const auto *it : callExpr->Arguments()) { + AnalyzeNode(it); + } +} + +void AliveAnalyzer::AnalyzeThrow(const ir::ThrowStatement *throwStmt) +{ + AnalyzeNode(throwStmt->Argument()); + MarkDead(); +} + +void AliveAnalyzer::AnalyzeSwitch(const ir::SwitchStatement *switchStmt) +{ + PendingExitsVector oldPendingExits = std::move(pendingExits_); + AnalyzeNode(switchStmt->Discriminant()); + + std::vector constants; + for (const auto *it : switchStmt->Cases()) { + status_ = LivenessStatus::ALIVE; + AnalyzeNode(it->Test()); + AnalyzeStats(it->Consequent()); + } + + status_ = Or(status_, ResolveBreaks(switchStmt, oldPendingExits)); +} + +void AliveAnalyzer::AnalyzeBreak(const ir::BreakStatement *breakStmt) +{ + RecordExit(PendingExit(breakStmt)); +} + +void AliveAnalyzer::AnalyzeContinue(const ir::ContinueStatement *contStmt) +{ + RecordExit(PendingExit(contStmt)); +} + +void AliveAnalyzer::AnalyzeReturn(const ir::ReturnStatement *retStmt) +{ + AnalyzeNode(retStmt->Argument()); + RecordExit(PendingExit(retStmt)); +} + +void AliveAnalyzer::AnalyzeTry([[maybe_unused]] const ir::TryStatement *tryStmt) +{ + // TODO +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/aliveAnalyzer.h b/checker/ets/aliveAnalyzer.h new file mode 100644 index 0000000000000000000000000000000000000000..72ca1f42a490a0b7d2b2fc44a582a98d0b5a9268 --- /dev/null +++ b/checker/ets/aliveAnalyzer.h @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_ALIVE_ANALYZER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_ALIVE_ANALYZER_H + +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ets/baseAnalyzer.h" + +#include "utils/arena_containers.h" + +namespace panda::es2panda::ir { +class AstNode; +class Statement; +class ClassDefinition; +class MethodDefinition; +class DoWhileStatement; +class VariableDeclaration; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::checker { +class AliveAnalyzer : public BaseAnalyzer { +public: + AliveAnalyzer(const ir::AstNode *node, ETSChecker *checker) : BaseAnalyzer(), checker_(checker) + { + AnalyzeNodes(node); + } + + void MarkDead() override + { + status_ = LivenessStatus::DEAD; + } + + LivenessStatus Or(LivenessStatus left, LivenessStatus right) + { + return static_cast(left | right); + } + + LivenessStatus And(LivenessStatus left, LivenessStatus right) + { + return static_cast(left & right); + } + +private: + void ClearPendingExits(); + void AnalyzeNodes(const ir::AstNode *node); + void AnalyzeNode(const ir::AstNode *node); + void AnalyzeDef(const ir::AstNode *node); + void AnalyzeStat(const ir::AstNode *node); + void AnalyzeStats(const ArenaVector &stats); + void AnalyzeClassDecl(const ir::ClassDeclaration *classDecl); + void AnalyzeClassDef(const ir::ClassDefinition *classDef); + void AnalyzeMethodDef(const ir::MethodDefinition *methodDef); + void AnalyzeVarDef(const ir::VariableDeclaration *varDef); + void AnalyzeDoLoop(const ir::DoWhileStatement *doWhile); + void AnalyzeWhileLoop(const ir::WhileStatement *whileStmt); + void AnalyzeForLoop(const ir::ForUpdateStatement *forStmt); + void AnalyzeForOfLoop(const ir::ForOfStatement *forOfStmt); + void AnalyzeIf(const ir::IfStatement *ifStmt); + void AnalyzeLabelled(const ir::LabelledStatement *labelledStmt); + void AnalyzeNewClass(const ir::ETSNewClassInstanceExpression *newClass); + void AnalyzeCall(const ir::CallExpression *callExpr); + void AnalyzeThrow(const ir::ThrowStatement *throwStmt); + void AnalyzeSwitch(const ir::SwitchStatement *switchStmt); + void AnalyzeTry(const ir::TryStatement *tryStmt); + void AnalyzeBreak(const ir::BreakStatement *breakStmt); + void AnalyzeContinue(const ir::ContinueStatement *contStmt); + void AnalyzeReturn(const ir::ReturnStatement *retStmt); + + ETSChecker *checker_; + LivenessStatus status_ {LivenessStatus::ALIVE}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/arithmetic.cpp b/checker/ets/arithmetic.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5ecf8deb53f5e9724f31630780acc3a2d705e69 --- /dev/null +++ b/checker/ets/arithmetic.cpp @@ -0,0 +1,327 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "arithmetic.h" + +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { + +Type *ETSChecker::NegateNumericType(Type *type, ir::Expression *node) +{ + ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC)); + + TypeFlag typeKind = ETSType(type); + Type *result = nullptr; + + switch (typeKind) { + case TypeFlag::BYTE: { + result = CreateByteType(-(type->AsByteType()->GetValue())); + break; + } + case TypeFlag::CHAR: { + result = CreateCharType(-(type->AsCharType()->GetValue())); + break; + } + case TypeFlag::SHORT: { + result = CreateShortType(-(type->AsShortType()->GetValue())); + break; + } + case TypeFlag::INT: { + result = CreateIntType(-(type->AsIntType()->GetValue())); + break; + } + case TypeFlag::LONG: { + result = CreateLongType(-(type->AsLongType()->GetValue())); + break; + } + case TypeFlag::FLOAT: { + result = CreateFloatType(-(type->AsFloatType()->GetValue())); + break; + } + case TypeFlag::DOUBLE: { + result = CreateDoubleType(-(type->AsDoubleType()->GetValue())); + break; + } + default: { + UNREACHABLE(); + } + } + + node->SetTsType(result); + return result; +} + +Type *ETSChecker::BitwiseNegateIntegralType(Type *type, ir::Expression *node) +{ + ASSERT(type->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_INTEGRAL)); + + TypeFlag typeKind = ETSType(type); + + Type *result = nullptr; + + switch (typeKind) { + case TypeFlag::BYTE: { + result = CreateByteType(~(type->AsByteType()->GetValue())); + break; + } + case TypeFlag::CHAR: { + result = CreateCharType(~(type->AsCharType()->GetValue())); + break; + } + case TypeFlag::SHORT: { + result = CreateShortType(~(type->AsShortType()->GetValue())); + break; + } + case TypeFlag::INT: { + result = CreateIntType(~(type->AsIntType()->GetValue())); + break; + } + case TypeFlag::LONG: { + result = CreateLongType(~(type->AsLongType()->GetValue())); + break; + } + default: { + UNREACHABLE(); + } + } + + node->SetTsType(result); + return result; +} + +Type *ETSChecker::HandleRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) && + right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC)); + + if (left->IsDoubleType() || right->IsDoubleType()) { + return PerformRelationOperationOnTypes(left, right, operationType); + } + + if (left->IsFloatType() || right->IsFloatType()) { + return PerformRelationOperationOnTypes(left, right, operationType); + } + + if (left->IsLongType() || right->IsLongType()) { + return PerformRelationOperationOnTypes(left, right, operationType); + } + + return PerformRelationOperationOnTypes(left, right, operationType); +} + +std::tuple ETSChecker::CheckBinaryOperator(ir::Expression *left, ir::Expression *right, + lexer::TokenType operationType, lexer::SourcePosition pos) +{ + checker::Type *leftType = left->Check(this); + checker::Type *rightType = right->Check(this); + checker::Type *tsType {}; + + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: + case lexer::TokenType::PUNCTUATOR_MOD: + case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::ETS_NUMERIC); + + if (!promotedType && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + + if (bothConst) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = promotedType; + break; + } + + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { + if (leftType->IsETSStringType() || rightType->IsETSStringType()) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + + [[fallthrough]]; + } + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { + if (leftType->IsETSStringType() || rightType->IsETSStringType()) { + tsType = HandleStringConcatenation(leftType, rightType); + break; + } + + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::ETS_NUMERIC); + + if (!promotedType && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type or String.", pos); + } + + if (bothConst) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = promotedType; + break; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { + leftType = ApplyUnaryOperatorPromotion(leftType, false); + rightType = ApplyUnaryOperatorPromotion(rightType, false); + + if (!leftType->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL) || + !rightType->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL)) { + ThrowTypeError("Bad operand type, the types of the operands must be intergral type.", pos); + } + + if (leftType->HasTypeFlag(TypeFlag::CONSTANT) && rightType->HasTypeFlag(TypeFlag::CONSTANT)) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = leftType; + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { + if (leftType->IsETSBooleanType() && rightType->IsETSBooleanType()) { + tsType = HandleBooleanLogicalOperators(leftType, rightType, operationType); + break; + } + + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::ETS_INTEGRAL); + + if (!promotedType && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be intergral type.", pos); + } + + if (bothConst) { + tsType = HandleArithmeticOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = promotedType; + break; + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: + case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { + if (!leftType->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN) || + !rightType->HasTypeFlag(checker::TypeFlag::ETS_BOOLEAN)) { + ThrowTypeError("Bad operand type, the types of the operands must be boolean type.", pos); + } + + tsType = HandleBooleanLogicalOperators(leftType, rightType, operationType); + break; + } + + case lexer::TokenType::PUNCTUATOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + if ((leftType->IsETSObjectType() && rightType->IsETSObjectType()) || + (leftType->IsETSStringType() && rightType->IsETSStringType())) { + tsType = GlobalETSBooleanType(); + auto *opType = GlobalETSObjectType(); + return {tsType, opType}; + } + + if (leftType->IsETSBooleanType() && rightType->IsETSBooleanType()) { + if (leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) && + rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + bool res = leftType->AsETSBooleanType()->GetValue() == rightType->AsETSBooleanType()->GetValue(); + + tsType = CreateETSBooleanType(operationType == lexer::TokenType::PUNCTUATOR_EQUAL ? res : !res); + break; + } + + tsType = GlobalETSBooleanType(); + break; + } + + [[fallthrough]]; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + auto [promotedType, bothConst] = ApplyBinaryOperatorPromotion(leftType, rightType, TypeFlag::ETS_NUMERIC); + + if (!promotedType && !bothConst) { + ThrowTypeError("Bad operand type, the types of the operands must be numeric type.", pos); + } + + if (bothConst) { + tsType = HandleRelationOperationOnTypes(leftType, rightType, operationType); + break; + } + + tsType = GlobalETSBooleanType(); + auto *opType = promotedType; + return {tsType, opType}; + } + case lexer::TokenType::KEYW_INSTANCEOF: { + if (!leftType->HasTypeFlag(checker::TypeFlag::ETS_OBJECT) || + !rightType->HasTypeFlag(checker::TypeFlag::ETS_OBJECT)) { + ThrowTypeError("Bad operand type, the types of the operands must be same type.", pos); + } + + tsType = GlobalETSBooleanType(); + break; + } + default: { + // TODO + UNREACHABLE(); + break; + } + } + + return {tsType, tsType}; +} + +Type *ETSChecker::HandleArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + ASSERT(left->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC) && + right->HasTypeFlag(TypeFlag::CONSTANT | TypeFlag::ETS_NUMERIC)); + + if (left->IsDoubleType() || right->IsDoubleType()) { + return PerformArithmeticOperationOnTypes(left, right, operationType); + } + + if (left->IsFloatType() || right->IsFloatType()) { + return PerformArithmeticOperationOnTypes(left, right, operationType); + } + + if (left->IsLongType() || right->IsLongType()) { + return PerformArithmeticOperationOnTypes(left, right, operationType); + } + + return PerformArithmeticOperationOnTypes(left, right, operationType); +} + +} // namespace panda::es2panda::checker diff --git a/checker/ets/arithmetic.h b/checker/ets/arithmetic.h new file mode 100644 index 0000000000000000000000000000000000000000..24ca2ae3ed69f772f0d79e042a21ab26b10437f6 --- /dev/null +++ b/checker/ets/arithmetic.h @@ -0,0 +1,217 @@ +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H +#define ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H + +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsBooleanType.h" + +namespace panda::es2panda::checker { + +template +typename TargetType::UType ETSChecker::GetOperand(Type *type) +{ + switch (ETSType(type)) { + case TypeFlag::BYTE: { + return type->AsByteType()->GetValue(); + } + case TypeFlag::CHAR: { + return type->AsCharType()->GetValue(); + } + case TypeFlag::SHORT: { + return type->AsShortType()->GetValue(); + } + case TypeFlag::INT: { + return type->AsIntType()->GetValue(); + } + case TypeFlag::LONG: { + return type->AsLongType()->GetValue(); + } + case TypeFlag::FLOAT: { + return type->AsFloatType()->GetValue(); + } + case TypeFlag::DOUBLE: { + return type->AsDoubleType()->GetValue(); + } + default: { + UNREACHABLE(); + } + } +} + +template +Type *ETSChecker::PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + using UType = typename TargetType::UType; + + UType leftValue = GetOperand(left); + UType rightValue = GetOperand(right); + + bool result {}; + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + result = leftValue < rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { + result = leftValue <= rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { + result = leftValue > rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + result = leftValue >= rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_EQUAL: { + result = leftValue == rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + result = leftValue != rightValue; + break; + } + default: { + UNREACHABLE(); + } + } + + return CreateETSBooleanType(result); +} + +template +Type *ETSChecker::PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) +{ + using UType = typename TargetType::UType; + + UType leftValue = GetOperand(left); + UType rightValue = GetOperand(right); + auto result = leftValue; + + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { + result = leftValue + rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { + result = leftValue - rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: { + result = leftValue / rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: { + result = leftValue * rightValue; + break; + } + case lexer::TokenType::PUNCTUATOR_MOD: + case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { + result = HandleModulo(leftValue, rightValue); + break; + } + default: { + result = HandleBitWiseArithmetic(leftValue, rightValue, operationType); + } + } + + return allocator_.New(result); +} + +template <> +inline IntType::UType panda::es2panda::checker::ETSChecker::HandleModulo(IntType::UType leftValue, + IntType::UType rightValue) +{ + return leftValue % rightValue; +} + +template <> +inline LongType::UType panda::es2panda::checker::ETSChecker::HandleModulo(LongType::UType leftValue, + LongType::UType rightValue) +{ + return leftValue % rightValue; +} + +template <> +inline FloatType::UType panda::es2panda::checker::ETSChecker::HandleModulo( + FloatType::UType leftValue, FloatType::UType rightValue) +{ + return std::fmod(leftValue, rightValue); +} + +template <> +inline DoubleType::UType panda::es2panda::checker::ETSChecker::HandleModulo( + DoubleType::UType leftValue, DoubleType::UType rightValue) +{ + return std::fmod(leftValue, rightValue); +} + +template +UType ETSChecker::HandleBitWiseArithmetic(UType leftValue, UType rightValue, lexer::TokenType operationType) +{ + switch (operationType) { + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { + return leftValue & rightValue; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { + return leftValue | rightValue; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { + return leftValue ^ rightValue; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { + return leftValue << rightValue; + } + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { + return leftValue >> rightValue; + } + default: { + UNREACHABLE(); + } + } +} + +template <> +inline FloatType::UType ETSChecker::HandleBitWiseArithmetic( + [[maybe_unused]] FloatType::UType leftValue, [[maybe_unused]] FloatType::UType rightValue, + [[maybe_unused]] lexer::TokenType operationType) +{ + return 0.0; +} + +template <> +inline DoubleType::UType ETSChecker::HandleBitWiseArithmetic( + [[maybe_unused]] DoubleType::UType leftValue, [[maybe_unused]] DoubleType::UType rightValue, + [[maybe_unused]] lexer::TokenType operationType) +{ + return 0.0; +} +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/baseAnalyzer.cpp b/checker/ets/baseAnalyzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47fcdeabb464ab584bc12f60e2c44b24fb7b9b38 --- /dev/null +++ b/checker/ets/baseAnalyzer.cpp @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "baseAnalyzer.h" +#include "plugins/ecmascript/es2panda/ir/astNode.h" +#include "plugins/ecmascript/es2panda/ir/statements/breakStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/continueStatement.h" + +namespace panda::es2panda::checker { + +const ir::AstNode *BaseAnalyzer::GetJumpTarget(const ir::AstNode *node) const +{ + if (node->IsBreakStatement()) { + return node->AsBreakStatement()->Target(); + } + + ASSERT(node->IsContinueStatement()); + return node->AsContinueStatement()->Target(); +} + +LivenessStatus BaseAnalyzer::ResolveJump(const ir::AstNode *node, PendingExitsVector &oldPendingExits, + ir::AstNodeType jumpKind) +{ + bool resolved = false; + + for (auto &it : pendingExits_) { + if (it.Node()->Type() == jumpKind && node == GetJumpTarget(it.Node())) { + it.ResolveJump(); + resolved = true; + } else { + oldPendingExits.push_back(it); + } + } + + pendingExits_.swap(oldPendingExits); + return From(resolved); +} + +LivenessStatus BaseAnalyzer::ResolveContinues(const ir::AstNode *node) +{ + PendingExitsVector oldPendingExits; + return ResolveJump(node, oldPendingExits, ir::AstNodeType::CONTINUE_STATEMENT); +} + +LivenessStatus BaseAnalyzer::ResolveBreaks(const ir::AstNode *node, PendingExitsVector &oldPendingExits) +{ + return ResolveJump(node, oldPendingExits, ir::AstNodeType::BREAK_STATEMENT); +} + +} // namespace panda::es2panda::checker diff --git a/checker/ets/baseAnalyzer.h b/checker/ets/baseAnalyzer.h new file mode 100644 index 0000000000000000000000000000000000000000..73f8abf7603e0b4213cba19e53bc780cc5306e50 --- /dev/null +++ b/checker/ets/baseAnalyzer.h @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_BASE_ANALYZER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_BASE_ANALYZER_H + +#include "utils/arena_containers.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +namespace panda::es2panda::ir { +class AstNode; +enum class AstNodeType; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::checker { +class ETSChecker; + +enum class LivenessStatus { DEAD, ALIVE }; + +DEFINE_BITOPS(LivenessStatus) + +class PendingExit { +public: + using JumpResolver = std::function; + + explicit PendingExit( + const ir::AstNode *node, const JumpResolver &jumpResolver = [] {}) + : node_(node), jumpResolver_(jumpResolver) + { + } + ~PendingExit() = default; + + DEFAULT_COPY_SEMANTIC(PendingExit); + DEFAULT_NOEXCEPT_MOVE_SEMANTIC(PendingExit); + + void ResolveJump() const + { + jumpResolver_(); + } + + const ir::AstNode *Node() const + { + return node_; + } + +private: + const ir::AstNode *node_; + JumpResolver jumpResolver_; +}; + +using PendingExitsVector = std::vector; + +class BaseAnalyzer { +public: + explicit BaseAnalyzer() {} + + virtual void MarkDead() = 0; + + void RecordExit(PendingExit pe) + { + pendingExits_.push_back(pe); + MarkDead(); + } + + LivenessStatus From(bool value) + { + return value ? LivenessStatus::ALIVE : LivenessStatus::DEAD; + } + + LivenessStatus ResolveJump(const ir::AstNode *node, PendingExitsVector &oldPendingExits, ir::AstNodeType jumpKind); + LivenessStatus ResolveContinues(const ir::AstNode *node); + LivenessStatus ResolveBreaks(const ir::AstNode *node, PendingExitsVector &oldPendingExits); + const ir::AstNode *GetJumpTarget(const ir::AstNode *node) const; + +protected: + PendingExitsVector pendingExits_; +}; +} // namespace panda::es2panda::checker +#endif diff --git a/checker/ets/boxingConverter.cpp b/checker/ets/boxingConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe99abd9ca8ba289e4827f9ee2802f5f67134516 --- /dev/null +++ b/checker/ets/boxingConverter.cpp @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "boxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/checker/ets/primitiveWrappers.h" + +namespace panda::es2panda::checker { + +void BoxingConverter::ETSTypeFromSource(Type *source) +{ + auto typeKind = checker::ETSChecker::TypeKind(source); + + auto wrapMap = checker_->PrimitiveWrapper(); + + switch (typeKind) { + case checker::TypeFlag::BOOLEAN: { + auto res = wrapMap.find("Boolean"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::BYTE: { + auto res = wrapMap.find("Byte"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::SHORT: { + auto res = wrapMap.find("Short"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::CHAR: { + auto res = wrapMap.find("Char"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::INT: { + auto res = wrapMap.find("Int"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::LONG: { + auto res = wrapMap.find("Long"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::FLOAT: { + auto res = wrapMap.find("Float"); + result_ = res->second.first; + break; + } + case checker::TypeFlag::DOUBLE: { + auto res = wrapMap.find("Double"); + result_ = res->second.first; + break; + } + default: + break; + } +} + +} // namespace panda::es2panda::checker diff --git a/checker/ets/boxingConverter.h b/checker/ets/boxingConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..0e16555074548384fe0d16cb66d10350d1163f80 --- /dev/null +++ b/checker/ets/boxingConverter.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_BOXING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_BOXING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" + +namespace panda::es2panda::checker { +class BoxingConverter : public TypeConverter { +public: + BoxingConverter(ETSChecker *checker, TypeRelation *relation, Type *source, Type *target) + : TypeConverter(checker, relation, target, source) + { + ASSERT(relation->GetNode()); + + if (!target->IsETSObjectType()) { + return; + } + + ETSTypeFromSource(source); + } + + void ETSTypeFromSource(Type *source); + +private: + ETSObjectType *result_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/function.cpp b/checker/ets/function.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c71bd8c4bb499ad9b7e28252236d00786db6b6d7 --- /dev/null +++ b/checker/ets/function.cpp @@ -0,0 +1,487 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ets/typeRelationContext.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { + +bool ETSChecker::ValidateSignature(Signature *signature, const ArenaVector &arguments, + const lexer::SourcePosition &pos, TypeRelationFlag initialFlags) +{ + if ((arguments.size() < signature->MinArgCount()) || + (arguments.size() > signature->MinArgCount() && !signature->RestVar())) { + if (!(initialFlags & TypeRelationFlag::NO_THROW)) { + ThrowTypeError({"Expected ", signature->MinArgCount(), " arguments, got ", arguments.size(), " ."}, pos); + } + + return false; + } + + uint32_t index = 0; + bool validateRest = false; + + for (; index < arguments.size(); index++) { + if (index >= signature->MinArgCount()) { + ASSERT(signature->RestVar()); + validateRest = true; + break; + } + + Type *argType = arguments[index]->Check(this); + auto invocationtCtx = checker::InvocationContext( + relation_, arguments[index], argType, signature->Params()[index]->TsType(), arguments[index]->Start(), + {"Call argument at index ", index, " is not compatible with the signature's type at that index"}, + initialFlags); + + if (!invocationtCtx.IsInvocable()) { + return false; + } + } + + if ((initialFlags & TypeRelationFlag::SELF_REFERENCE) && (!signature->Function()->IsStatic()) && + (HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) && !signature->Function()->IsConstructor()) { + return false; + } + + if (!validateRest) { + return true; + } + + do { + Type *argType = arguments[index]->Check(this); + auto invocationtCtx = checker::InvocationContext( + relation_, arguments[index], argType, signature->RestVar()->TsType(), arguments[index]->Start(), + {"Call argument at index ", index, " is not compatible with the signature's rest parameter type"}, + initialFlags); + index++; + + if (!invocationtCtx.IsInvocable()) { + return false; + } + } while (index < arguments.size()); + + return true; +} + +Signature *ETSChecker::ValidateSignatures(ArenaVector &signatures, + const ArenaVector &arguments, + const lexer::SourcePosition &pos, std::string_view signatureKind, + TypeRelationFlag flags) +{ + for (auto *sig : signatures) { + if (ValidateSignature(sig, arguments, pos, flags | TypeRelationFlag::NO_THROW)) { + return sig; + } + } + + if (flags & TypeRelationFlag::WIDENING) { + ThrowTypeError({"No matching ", signatureKind, " signature"}, pos); + } + + return nullptr; +} + +Signature *ETSChecker::ResolveCallExpression(ArenaVector &signatures, + const ArenaVector &arguments, + const lexer::SourcePosition &pos, bool isIdentifier) +{ + auto flag = isIdentifier ? TypeRelationFlag::SELF_REFERENCE : TypeRelationFlag::NONE; + + auto *sig = ValidateSignatures(signatures, arguments, pos, "call", flag); + + if (sig) { + return sig; + } + + return ValidateSignatures(signatures, arguments, pos, "call", flag | TypeRelationFlag::WIDENING); +} + +Signature *ETSChecker::ResolveConstructExpression(ETSObjectType *type, const ArenaVector &arguments, + const lexer::SourcePosition &pos) +{ + auto *sig = ValidateSignatures(type->ConstructSignatures(), arguments, pos, "construct", TypeRelationFlag::NONE); + + if (sig) { + return sig; + } + + return ValidateSignatures(type->ConstructSignatures(), arguments, pos, "construct", TypeRelationFlag::WIDENING); +} + +checker::ETSFunctionType *ETSChecker::BuildMethodSignature(ir::MethodDefinition *method) +{ + if (method->TsType()) { + return method->TsType()->AsETSFunctionType(); + } + + bool isConstructSig = method->IsConstructor(); + + auto *funcType = BuildFunctionSignature(method->Function(), isConstructSig); + + auto overloadList = method->Overloads(); + + for (size_t baseFuncCounter = 0; baseFuncCounter < overloadList.size(); baseFuncCounter++) { + auto *currentFunc = overloadList.at(baseFuncCounter); + auto *overloadType = BuildFunctionSignature(currentFunc->Function(), isConstructSig); + CheckIdenticalOverloads(funcType, overloadType, currentFunc->Start()); + for (size_t compareFuncCounter = baseFuncCounter + 1; compareFuncCounter < overloadList.size(); + compareFuncCounter++) { + auto *compareFunc = overloadList.at(compareFuncCounter); + auto *compareOverloadType = BuildFunctionSignature(compareFunc->Function(), isConstructSig); + CheckIdenticalOverloads(overloadType, compareOverloadType, compareFunc->Start()); + } + currentFunc->SetTsType(overloadType); + funcType->AddCallSignature(currentFunc->Function()->Signature()); + } + + method->Id()->Variable()->SetTsType(funcType); + return funcType; +} + +void ETSChecker::CheckIdenticalOverloads(ETSFunctionType *func, ETSFunctionType *overload, + const lexer::SourcePosition &overloadStart) +{ + SavedTypeRelationFlagsContext savedFlagsCtx(relation_, TypeRelationFlag::NO_RETURN_TYPE_CHECK); + relation_->IsIdenticalTo(func, overload); + if (relation_->IsTrue()) { + ThrowTypeError("Function already declared.", overloadStart); + } +} + +checker::ETSFunctionType *ETSChecker::BuildFunctionSignature(ir::ScriptFunction *func, bool isConstructSig) +{ + auto *nameVar = func->Id()->Variable(); + + auto *signatureInfo = CreateSignatureInfo(); + signatureInfo->restVar = nullptr; + signatureInfo->minArgCount = 0; + + if ((func->IsConstructor() || !func->IsStatic()) && + !context_.ContainingClass()->HasObjectFlag(ETSObjectFlags::INTERFACE)) { + auto *thisVar = func->Scope()->ParamScope()->Params().front(); + thisVar->SetTsType(context_.ContainingClass()); + } + + for (auto *it : func->Params()) { + if (it->IsRestElement()) { + auto *restParam = it->AsRestElement(); + ASSERT(restParam->Argument()->IsIdentifier()); + + auto *restIdent = restParam->Argument()->AsIdentifier(); + + ASSERT(restIdent->Variable()); + signatureInfo->restVar = restIdent->Variable()->AsLocalVariable(); + + ASSERT(restParam->TypeAnnotation()); + signatureInfo->restVar->SetTsType(restParam->TypeAnnotation()->GetType(this)); + break; + } + + ASSERT(it->IsIdentifier()); + auto *paramIdent = it->AsIdentifier(); + + ASSERT(paramIdent->Variable()); + binder::Variable *paramVar = paramIdent->Variable(); + + ASSERT(paramIdent->TypeAnnotation()); + paramVar->SetTsType(paramIdent->TypeAnnotation()->GetType(this)); + signatureInfo->params.push_back(paramVar->AsLocalVariable()); + signatureInfo->minArgCount++; + } + + auto *returnTypeAnnotation = func->ReturnTypeAnnotation(); + checker::Type *returnType {}; + + ASSERT(returnTypeAnnotation || func->IsConstructor() || func->IsStaticBlock()); + + if (returnTypeAnnotation) { + returnType = returnTypeAnnotation->GetType(this); + returnTypeAnnotation->SetTsType(returnType); + } else { + returnType = GlobalVoidType(); + } + + auto *signature = CreateSignature(signatureInfo, returnType, func); + signature->SetOwner(context_.ContainingClass()); + + if (isConstructSig) { + signature->AddSignatureFlag(SignatureFlags::CONSTRUCT); + } else { + signature->AddSignatureFlag(SignatureFlags::CALL); + } + + auto *funcType = CreateETSFunctionType(signature); + func->SetSignature(signature); + funcType->SetVariable(nameVar); + + if (func->IsAbstract()) { + signature->AddSignatureFlag(SignatureFlags::ABSTRACT); + signature->AddSignatureFlag(SignatureFlags::VIRTUAL); + } + + if (func->IsStatic()) { + signature->AddSignatureFlag(SignatureFlags::STATIC); + } + + if (func->IsOpen()) { + if (!(func->Signature()->Owner()->GetDeclNode()->IsOpen() || + func->Signature()->Owner()->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT))) { + ThrowTypeError("Only open or abstract classes can have open method", func->Start()); + } + signature->AddSignatureFlag(SignatureFlags::OPEN); + signature->AddSignatureFlag(SignatureFlags::PUBLIC); + } + + if (func->IsPublic()) { + signature->AddSignatureFlag(SignatureFlags::PUBLIC); + } else if (func->IsProtected()) { + signature->AddSignatureFlag(SignatureFlags::PROTECTED); + } else if (func->IsPrivate()) { + signature->AddSignatureFlag(SignatureFlags::PRIVATE); + } + + nameVar->SetTsType(funcType); + + return funcType; +} + +Signature *ETSChecker::CheckEveryAbstractSignatureIsOverriden(ETSFunctionType *target, ETSFunctionType *source) +{ + for (auto targetSig = target->CallSignatures().begin(); targetSig != target->CallSignatures().end();) { + if (!(*targetSig)->HasSignatureFlag(SignatureFlags::ABSTRACT)) { + continue; + } + + bool isOverridden = false; + for (auto sourceSig : source->CallSignatures()) { + relation_->IsIdenticalTo(*targetSig, sourceSig); + if (relation_->IsTrue() && (*targetSig)->Function()->Id()->Name() == sourceSig->Function()->Id()->Name()) { + target->CallSignatures().erase(targetSig); + isOverridden = true; + break; + } + sourceSig++; + } + + if (!isOverridden) { + return *targetSig; + } + } + + return nullptr; +} + +bool ETSChecker::IsOverridableIn(Signature *signature) +{ + if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) { + return false; + } + + if (signature->HasSignatureFlag(SignatureFlags::PUBLIC)) { + return !FindAncestorGivenByType(signature->Function(), ir::AstNodeType::TS_INTERFACE_DECLARATION) || + signature->HasSignatureFlag(SignatureFlags::STATIC); + } + + if (signature->HasSignatureFlag(SignatureFlags::PROTECTED)) { + return true; + } + + return false; +} + +bool ETSChecker::IsMethodOverridesOther(Signature *target, Signature *source) +{ + if (source->Function()->IsConstructor()) { + return false; + } + + if (target == source) { + return true; + } + + if (IsOverridableIn(target)) { + SavedTypeRelationFlagsContext savedFlagsCtx(relation_, TypeRelationFlag::NO_RETURN_TYPE_CHECK); + relation_->IsIdenticalTo(target, source); + if (relation_->IsTrue()) { + if (!source->Function()->IsOverride()) { + ThrowTypeError("Method overriding requires 'override' modifier", source->Function()->Start()); + } + return true; + } + } + + return false; +} + +std::tuple ETSChecker::CheckOverride(Signature *signature, Signature *other) +{ + if (signature->HasSignatureFlag(SignatureFlags::STATIC) != other->HasSignatureFlag(SignatureFlags::STATIC)) { + return {false, OverrideErrorCode::OVERRIDING_STATIC}; + } + + if (!(other->HasSignatureFlag(SignatureFlags::OPEN) || other->Function()->IsOverride())) { + return {false, OverrideErrorCode::OVERRIDEN_NOT_OPEN}; + } + + if (!IsTypeAssignableTo(signature->ReturnType(), other->ReturnType())) { + return {false, OverrideErrorCode::INCOMPATIBLE_RETURN}; + } + + if (signature->ProtectionFlag() > other->ProtectionFlag()) { + return {false, OverrideErrorCode::OVERRIDEN_WEAKER}; + } + + return {true, OverrideErrorCode::NO_ERROR}; +} + +bool ETSChecker::CheckOverride(Signature *signature, ETSObjectType *site) +{ + auto *target = site->GetProperty(signature->Function()->Id()->Name(), PropertySearchFlags::NO_OPTS); + bool isOverridingAnySignature = false; + + if (!target || !target->TsType()->IsETSFunctionType()) { + return isOverridingAnySignature; + } + + for (auto *it : target->TsType()->AsETSFunctionType()->CallSignatures()) { + if (it->HasSignatureFlag(SignatureFlags::ABSTRACT) || site->HasObjectFlag(ETSObjectFlags::INTERFACE)) { + isOverridingAnySignature = true; + continue; + } + + if (!IsMethodOverridesOther(it, signature)) { + continue; + } + + auto [success, errorCode] = CheckOverride(signature, it); + + if (!success) { + const char *reason {}; + switch (errorCode) { + case OverrideErrorCode::OVERRIDING_STATIC: { + reason = "overriding method is static."; + break; + } + case OverrideErrorCode::OVERRIDEN_STATIC: { + reason = "overriden method is static."; + break; + } + case OverrideErrorCode::OVERRIDEN_NOT_OPEN: { + reason = "overriden method is not open."; + break; + } + case OverrideErrorCode::INCOMPATIBLE_RETURN: { + reason = "overriding return type is not compatible with the other return type."; + break; + } + case OverrideErrorCode::OVERRIDEN_WEAKER: { + reason = "overriden method has weaker access privilage."; + break; + } + default: { + UNREACHABLE(); + } + } + + ThrowTypeError({signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), + " cannot override ", it->Function()->Id()->Name(), it, " in ", it->Owner(), " because ", + reason}, + signature->Function()->Start()); + } + + isOverridingAnySignature = true; + it->AddSignatureFlag(SignatureFlags::VIRTUAL); + signature->AddSignatureFlag(SignatureFlags::OPEN); + } + + return isOverridingAnySignature; +} + +void ETSChecker::CheckOverride(Signature *signature) +{ + auto *owner = signature->Owner(); + bool isOverriding = false; + + if (!owner->HasObjectFlag(ETSObjectFlags::CLASS)) { + return; + } + + ETSObjectType *iter = owner->SuperType(); + + for (auto *it : owner->Interfaces()) { + isOverriding |= CheckOverride(signature, it); + } + + while (iter) { + isOverriding |= CheckOverride(signature, iter); + + for (auto *it : iter->Interfaces()) { + isOverriding |= CheckOverride(signature, it); + } + + iter = iter->SuperType(); + } + + if (!isOverriding && signature->Function()->IsOverride()) { + ThrowTypeError({"Method ", signature->Function()->Id()->Name(), signature, " in ", signature->Owner(), + " not overriding any method"}, + signature->Function()->Start()); + } +} + +Signature *ETSChecker::GetSignatureFromMethodDefinition(const ir::MethodDefinition *methodDef) +{ + ASSERT(methodDef->TsType() && methodDef->TsType()->IsETSFunctionType()); + + for (auto *it : methodDef->TsType()->AsETSFunctionType()->CallSignatures()) { + if (it->Function() == methodDef->Function()) { + return it; + } + } + + return nullptr; +} + +void ETSChecker::ValidateSignatureAccessibility(ETSObjectType *callee, Signature *signature, + const lexer::SourcePosition &pos) +{ + if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) { + if (context_.ContainingClass() == callee && callee->IsSignatureInherited(signature)) { + return; + } + + auto *currentOutermost = context_.ContainingClass()->OutermostClass(); + auto *objOutermost = callee->OutermostClass(); + + if (currentOutermost && objOutermost && currentOutermost == objOutermost && + callee->IsSignatureInherited(signature)) { + return; + } + + ThrowTypeError({"Signature ", signature->Function()->Id()->Name(), signature, " is not visible here."}, pos); + } +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/helpers.cpp b/checker/ets/helpers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30ae4f38428b0aeea11049f6a35bc8d2e29e4c25 --- /dev/null +++ b/checker/ets/helpers.cpp @@ -0,0 +1,645 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/statements/labelledStatement.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ets/typeRelationContext.h" +#include "plugins/ecmascript/es2panda/checker/ets/unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" + +namespace panda::es2panda::checker { +void ETSChecker::CheckTruthinessOfType(Type *type, const lexer::SourcePosition &pos) +{ + if (!type->IsETSBooleanType()) { + ThrowTypeError("Condition must be of type boolean", pos); + } +} + +Type *ETSChecker::GetDefaultTypeFromPrimitiveType(Type *type) +{ + if (!type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) { + return type; + } + + if (type->HasTypeFlag(TypeFlag::ETS_INTEGRAL)) { + return GlobalIntType(); + } + + if (type->HasTypeFlag(TypeFlag::FLOAT | TypeFlag::DOUBLE)) { + return GlobalDoubleType(); + } + + if (type->IsETSBooleanType()) { + return GlobalETSBooleanType(); + } + return type; +} + +bool ETSChecker::IsConstantExpression(ir::Expression *expr, Type *type) +{ + return (type->HasTypeFlag(TypeFlag::CONSTANT) && (expr->IsIdentifier() || expr->IsMemberExpression())); +} + +Type *ETSChecker::GetTypeOfVariable(binder::Variable *var) +{ + if (var->TsType()) { + return var->TsType(); + } + + binder::Decl *decl = var->Declaration(); + + switch (decl->Type()) { + case binder::DeclType::CLASS: { + auto *classDef = decl->Node()->AsClassDefinition(); + BuildClassProperties(classDef); + return classDef->TsType(); + } + case binder::DeclType::ENUM_LITERAL: + case binder::DeclType::CONST: + case binder::DeclType::EXPORT: + case binder::DeclType::LET: + case binder::DeclType::VAR: { + auto *declNode = decl->Node(); + + if (decl->Node()->IsIdentifier()) { + declNode = declNode->Parent(); + } + + return declNode->Check(this); + } + case binder::DeclType::FUNC: { + return decl->Node()->Check(this); + } + default: { + UNREACHABLE(); + } + } + + return var->TsType(); +} + +void ETSChecker::ValidatePropertyAccess(binder::Variable *var, ETSObjectType *obj, const lexer::SourcePosition &pos) +{ + if (!var->HasFlag(binder::VariableFlags::STATIC) && HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) { + ThrowTypeError("non-static variable cannot be referenced from a static context", pos); + } + + if (var->HasFlag(binder::VariableFlags::PRIVATE)) { + if (context_.ContainingClass() == obj && obj->IsPropertyInherited(var)) { + return; + } + + auto *currentOutermost = context_.ContainingClass()->OutermostClass(); + auto *objOutermost = obj->OutermostClass(); + + if (currentOutermost && objOutermost && currentOutermost == objOutermost && obj->IsPropertyInherited(var)) { + return; + } + + ThrowTypeError({"Property ", var->Name(), " is not visible here."}, pos); + } +} + +Type *ETSChecker::ResolveIdentifier(ir::Identifier *ident) +{ + if (ident->Variable()) { + if (ident->Variable()->Declaration()->Node()->IsClassProperty() && + !ident->Variable()->HasFlag(binder::VariableFlags::STATIC) && HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) { + ThrowTypeError("non-static variable cannot be referenced from a static context", ident->Start()); + } + + return GetTypeOfVariable(ident->Variable()); + } + + ETSObjectType *classType = context_.ContainingClass(); + + bool isTypeError = false; + if (!classType->SuperType() && classType->Interfaces().empty()) { + isTypeError = true; + } + + binder::Variable *resolved = classType->GetProperty(ident->Name(), PropertySearchFlags::SEARCH_ALL); + + if (!resolved) { + isTypeError = true; + } + + if (isTypeError || (resolved && resolved->TsType() == nullptr)) { + auto* signatureInfo = context_.ContainingSignature()->GetSignatureInfo(); + for (auto ¶m : signatureInfo->params) { + if (param->IsLocalVariable()) { + std::string_view var_name = std::string(param->Declaration()->Name()); + if (var_name == std::string(ident->Name())) { + resolved = param; + isTypeError = false; + } + } + } + } + + if (isTypeError) { + ThrowTypeError({"Cannot find variable '", ident->Name(), "'."}, ident->Start()); + } + + ValidatePropertyAccess(resolved, context_.ContainingClass(), ident->Start()); + ident->SetVariable(resolved); + return GetTypeOfVariable(ident->Variable()); +} + +void ETSChecker::ValidateUnaryOperatorOperand(binder::Variable *variable) +{ + if (variable->Declaration()->IsConstDecl()) { + if (HasStatus(CheckerStatus::IN_CONSTRUCTOR | CheckerStatus::IN_STATIC_BLOCK) && + !variable->HasFlag(binder::VariableFlags::EXPLICIT_INIT_REQUIRED)) { + ThrowTypeError({"Cannot reassign constant field ", variable->Name()}, + variable->Declaration()->Node()->Start()); + } + if (!HasStatus(CheckerStatus::IN_CONSTRUCTOR | CheckerStatus::IN_STATIC_BLOCK)) { + ThrowTypeError({"Cannot assign to a constant variable ", variable->Name()}, + variable->Declaration()->Node()->Start()); + } + } else if (!variable->Declaration()->IsLetDecl()) { + ThrowTypeError("Only variables can be assigned.", variable->Declaration()->Node()->Start()); + } +} + +std::tuple ETSChecker::ApplyBinaryOperatorPromotion(Type *left, Type *right, TypeFlag test) +{ + UnboxingConverter convL = UnboxingConverter(this, relation_, left, nullptr); + UnboxingConverter convR = UnboxingConverter(this, relation_, right, nullptr); + Type *unboxedL = convL.Result(); + Type *unboxedR = convR.Result(); + + if (!unboxedL->HasTypeFlag(test) || !unboxedR->HasTypeFlag(test)) { + return {nullptr, false}; + } + + if (unboxedL->HasTypeFlag(TypeFlag::CONSTANT) && unboxedR->HasTypeFlag(TypeFlag::CONSTANT)) { + return {nullptr, true}; + } + + if (unboxedL->HasTypeFlag(TypeFlag::ETS_NUMERIC) && unboxedR->HasTypeFlag(TypeFlag::ETS_NUMERIC)) { + if (unboxedL->IsDoubleType() || unboxedR->IsDoubleType()) { + return {GlobalDoubleType(), false}; + } + + if (unboxedL->IsFloatType() || unboxedR->IsFloatType()) { + return {GlobalFloatType(), false}; + } + + if (unboxedL->IsLongType() || unboxedR->IsLongType()) { + return {GlobalLongType(), false}; + } + + return {GlobalIntType(), false}; + } + + if (IsTypeIdenticalTo(unboxedL, unboxedR)) { + return {unboxedL, false}; + } + + return {globalBuiltinObjectType_, false}; +} + +Type *ETSChecker::ApplyUnaryOperatorPromotion(Type *type, bool createConst) +{ + UnboxingConverter conv = UnboxingConverter(this, relation_, type, nullptr); + switch (ETSType(conv.Result())) { + case TypeFlag::BYTE: + case TypeFlag::SHORT: + case TypeFlag::CHAR: { + if (!createConst) { + return GlobalIntType(); + } + + return CreateIntTypeFromType(conv.Result()); + } + default: { + return conv.Result(); + } + } +} + +Type *ETSChecker::HandleBooleanLogicalOperators(Type *leftType, Type *rightType, lexer::TokenType tokenType) +{ + using UType = typename ETSBooleanType::UType; + ASSERT(leftType->IsETSBooleanType() && rightType->IsETSBooleanType()); + + if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return GlobalETSBooleanType(); + } + + UType leftValue = leftType->AsETSBooleanType()->GetValue(); + UType rightValue = rightType->AsETSBooleanType()->GetValue(); + + switch (tokenType) { + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: { + return CreateETSBooleanType(leftValue ^ rightValue); + } + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { + return CreateETSBooleanType(leftValue & rightValue); + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { + return CreateETSBooleanType(leftValue | rightValue); + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { + return CreateETSBooleanType(leftValue || rightValue); + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { + return CreateETSBooleanType(leftValue && rightValue); + } + default: { + break; + } + } + + UNREACHABLE(); + return nullptr; +} + +checker::Type *ETSChecker::CheckVariableDeclaration(checker::ETSChecker *checker, ir::Identifier *ident, + ir::TypeNode *typeAnnotation, ir::Expression *init, + ir::ModifierFlags flags) +{ + const util::StringView &varName = ident->Name(); + ASSERT(ident->Variable()); + binder::Variable *bindingVar = ident->Variable(); + checker::Type *annotationType = nullptr; + + bool isConst = flags & ir::ModifierFlags::CONST; + + if (typeAnnotation) { + annotationType = typeAnnotation->GetType(checker); + bindingVar->SetTsType(annotationType); + } + + if (!init) { + return annotationType; + } + + checker::Type *initType = init->Check(checker); + + if (annotationType) { + AssignmentContext(checker->Relation(), init, initType, annotationType, init->Start(), + {"Initializers type is not assignable to the target type"}); + if (isConst && initType->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) { + bindingVar->SetTsType(init->TsType()); + } + } else if (!annotationType) { + bindingVar->SetTsType(isConst ? initType : checker->GetDefaultTypeFromPrimitiveType(initType)); + + if (bindingVar->TsType()->IsETSNullType()) { + checker->ThrowTypeError({"Cannot infer type for variable '", varName, "'."}, init->Start()); + } + } + + return bindingVar->TsType(); +} + +Type *ETSChecker::GetTypeFromInterfaceReference(binder::Variable *var) +{ + if (var->TsType()) { + return var->TsType(); + } + + auto *interfaceType = BuildInterfaceProperties(var->Declaration()->Node()->AsTSInterfaceDeclaration()); + var->SetTsType(interfaceType); + return interfaceType; +} + +Type *ETSChecker::GetTypeFromClassReference(binder::Variable *var) +{ + if (var->TsType()) { + return var->TsType(); + } + + auto *classType = BuildClassProperties(var->Declaration()->Node()->AsClassDefinition()); + var->SetTsType(classType); + return classType; +} + +Type *ETSChecker::GetTypeFromEnumReference([[maybe_unused]] binder::Variable *var) +{ + // TODO + return nullptr; +} + +Type *ETSChecker::GetTypeFromTypeParameterReference(binder::LocalVariable *var, const lexer::SourcePosition &pos) +{ + if (HasStatus(CheckerStatus::IN_STATIC_CONTEXT)) { + ThrowTypeError({"Cannot make a static reference to the non-static type ", var->Name()}, pos); + } + + auto *typeParam = var->TsType()->AsETSTypeParameter(); + return CreateTypeReference(typeParam->GetTypeRef(), typeParam->GetAssemblerTypeRef(), var); +} + +Type *ETSChecker::GetReferencedTypeFromBase([[maybe_unused]] Type *baseType, [[maybe_unused]] ir::Expression *name) +{ + // TODO + return nullptr; +} + +Type *ETSChecker::GetReferencedTypeBase(ir::Expression *name) +{ + if (name->IsTSQualifiedName()) { + // TODO + return nullptr; + } + + ASSERT(name->IsIdentifier() && name->AsIdentifier()->Variable()); + auto *refVar = name->AsIdentifier()->Variable()->AsLocalVariable(); + + switch (refVar->Declaration()->Node()->Type()) { + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + return GetTypeFromInterfaceReference(refVar); + } + case ir::AstNodeType::CLASS_DECLARATION: + case ir::AstNodeType::CLASS_DEFINITION: { + return GetTypeFromClassReference(refVar); + } + case ir::AstNodeType::TS_ENUM_DECLARATION: { + return GetTypeFromEnumReference(refVar); + } + case ir::AstNodeType::TS_TYPE_PARAMETER: { + return GetTypeFromTypeParameterReference(refVar, name->Start()); + } + default: { + UNREACHABLE(); + } + } +} + +void ETSChecker::ConcantConstantString(util::UString &target, Type *type) +{ + switch (ETSType(type)) { + case TypeFlag::ETS_OBJECT: { + ASSERT(type->IsETSStringType()); + target.Append(type->AsETSStringType()->GetValue()); + break; + } + case TypeFlag::ETS_BOOLEAN: { + ETSBooleanType::UType value = type->AsETSBooleanType()->GetValue(); + target.Append(value ? "true" : "false"); + break; + } + case TypeFlag::BYTE: { + ByteType::UType value = type->AsByteType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::CHAR: { + CharType::UType value = type->AsCharType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::SHORT: { + ShortType::UType value = type->AsShortType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::INT: { + IntType::UType value = type->AsIntType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::LONG: { + LongType::UType value = type->AsLongType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::FLOAT: { + FloatType::UType value = type->AsFloatType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + case TypeFlag::DOUBLE: { + DoubleType::UType value = type->AsDoubleType()->GetValue(); + target.Append(std::to_string(value)); + break; + } + default: { + UNREACHABLE(); + } + } +} + +Type *ETSChecker::HandleStringConcatenation(Type *leftType, Type *rightType) +{ + ASSERT(leftType->IsETSStringType() || rightType->IsETSStringType()); + + if (!leftType->HasTypeFlag(checker::TypeFlag::CONSTANT) || !rightType->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return GlobalETSStringType(); + } + + util::UString concatenated(&allocator_); + ConcantConstantString(concatenated, leftType); + ConcantConstantString(concatenated, rightType); + + return CreateETSStringType(concatenated.View()); +} + +ETSFunctionType *ETSChecker::FindFunctionInVectorGivenByName(util::StringView name, + ArenaVector &list) +{ + for (auto *it : list) { + if (it->Name() == name) { + return it; + } + } + + return nullptr; +} + +bool ETSChecker::IsFunctionContainsSignature(ETSFunctionType *funcType, Signature *signature) +{ + for (auto *it : funcType->CallSignatures()) { + relation_->IsIdenticalTo(it, signature); + if (relation_->IsTrue()) { + return true; + } + } + + return false; +} + +void ETSChecker::CheckFunctionContainsClashingSignature(const ETSFunctionType *funcType, Signature *signature) +{ + for (auto *it : funcType->CallSignatures()) { + SavedTypeRelationFlagsContext strfCtx(relation_, TypeRelationFlag::NO_RETURN_TYPE_CHECK); + relation_->IsIdenticalTo(it, signature); + if (relation_->IsTrue() && it->Function()->Id()->Name() == signature->Function()->Id()->Name()) { + std::stringstream ss; + it->ToString(ss, nullptr, true); + auto sigStr1 = ss.str(); + ss.str(std::string {}); // Clear buffer + signature->ToString(ss, nullptr, true); + auto sigStr2 = ss.str(); + ThrowTypeError({"Function '", it->Function()->Id()->Name(), sigStr1.c_str(), + "' is redeclared with different signature '", signature->Function()->Id()->Name(), + sigStr2.c_str(), "'"}, + signature->Function()->ReturnTypeAnnotation()->Start()); + } + } +} + +void ETSChecker::MergeSignatures(ETSFunctionType *target, ETSFunctionType *source) +{ + for (auto *s : source->CallSignatures()) { + if (IsFunctionContainsSignature(target, s)) { + continue; + } + + CheckFunctionContainsClashingSignature(target, s); + target->AddCallSignature(s); + } +} + +void ETSChecker::MergeComputedAbstracts(ArenaVector &merged, ArenaVector ¤t) +{ + for (auto *curr : current) { + auto name = curr->Name(); + auto *found = FindFunctionInVectorGivenByName(name, merged); + if (found) { + MergeSignatures(found, curr); + continue; + } + + merged.push_back(curr); + } +} + +ir::AstNode *ETSChecker::FindAncestorGivenByType(ir::AstNode *node, ir::AstNodeType type) +{ + auto *iter = node->Parent(); + + while (iter) { + if (iter->Type() == type) { + return iter; + } + + iter = iter->Parent(); + } + + return nullptr; +} + +util::StringView ETSChecker::GetContainingObjectNameFromSignature(Signature *signature) +{ + ASSERT(signature->Function()); + auto *iter = signature->Function()->Parent(); + + while (iter) { + if (iter->IsClassDefinition()) { + return iter->AsClassDefinition()->Ident()->Name(); + } + + if (iter->IsTSInterfaceDeclaration()) { + return iter->AsTSInterfaceDeclaration()->Id()->Name(); + } + + iter = iter->Parent(); + } + + UNREACHABLE(); + return {""}; +} + +bool ETSChecker::IsTypeBuiltinType(Type *type) +{ + if (!type->IsETSObjectType()) { + return false; + } + + switch (type->AsETSObjectType()->BuiltInKind()) { + case ETSObjectFlags::BUILTIN_BOOLEAN: + case ETSObjectFlags::BUILTIN_BYTE: + case ETSObjectFlags::BUILTIN_SHORT: + case ETSObjectFlags::BUILTIN_CHAR: + case ETSObjectFlags::BUILTIN_INT: + case ETSObjectFlags::BUILTIN_LONG: + case ETSObjectFlags::BUILTIN_FLOAT: + case ETSObjectFlags::BUILTIN_DOUBLE: { + return true; + } + default: + return false; + } +} + +const ir::AstNode *ETSChecker::FindJumpTarget(ir::AstNodeType nodeType, const ir::AstNode *node, + const ir::Identifier *target) +{ + const auto *iter = node->Parent(); + + while (iter) { + switch (iter->Type()) { + case ir::AstNodeType::LABELLED_STATEMENT: { + const auto *labelled = iter->AsLabelledStatement(); + if (labelled->Ident() == target) { + if (nodeType == ir::AstNodeType::CONTINUE_STATEMENT) { + return labelled->GetReferencedStatement(); + } + + return labelled; + } + + break; + } + case ir::AstNodeType::DO_WHILE_STATEMENT: + case ir::AstNodeType::WHILE_STATEMENT: + case ir::AstNodeType::FOR_UPDATE_STATEMENT: + case ir::AstNodeType::FOR_OF_STATEMENT: + case ir::AstNodeType::SWITCH_CASE_STATEMENT: + case ir::AstNodeType::SWITCH_STATEMENT: { + if (!target) { + return iter; + } + break; + } + default: { + break; + } + } + + iter = iter->Parent(); + } + + UNREACHABLE(); + return nullptr; +} + +binder::VariableFlags ETSChecker::GetAccessFlagFromNode(const ir::AstNode *node) +{ + if (node->IsPrivate()) { + return binder::VariableFlags::PRIVATE; + } + + if (node->IsProtected()) { + return binder::VariableFlags::PROTECTED; + } + + return binder::VariableFlags::PUBLIC; +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/narrowingConverter.cpp b/checker/ets/narrowingConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb70ab143ed4efd4cf76405ee2732521525a7ac8 --- /dev/null +++ b/checker/ets/narrowingConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "narrowingConverter.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/ets/narrowingConverter.h b/checker/ets/narrowingConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..6fa9d44d6920901ee2ce0dd273e55f61cfa52de9 --- /dev/null +++ b/checker/ets/narrowingConverter.h @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { +class NarrowingConverter : public TypeConverter { +public: + explicit NarrowingConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : TypeConverter(checker, relation, target, source) + { + if (!relation->ApplyNarrowing()) { + return; + } + + ASSERT(relation->GetNode()); + + switch (ETSChecker::ETSChecker::ETSType(target)) { + case TypeFlag::BYTE: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_BYTE); + break; + } + case TypeFlag::CHAR: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_CHAR); + break; + } + case TypeFlag::SHORT: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_SHORT); + break; + } + case TypeFlag::INT: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_INT); + break; + } + case TypeFlag::LONG: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_LONG); + break; + } + case TypeFlag::FLOAT: { + ApplyNarrowing(TypeFlag::NARROWABLE_TO_FLOAT); + break; + } + + default: { + break; + } + } + } + +private: + template + void ApplyNarrowing(TypeFlag flag) + { + if (!source_->HasTypeFlag(flag)) { + return; + } + + switch (ETSChecker::ETSChecker::ETSType(source_)) { + case TypeFlag::CHAR: { + ApplyNarrowing(); + break; + } + case TypeFlag::SHORT: { + ApplyNarrowing(); + break; + } + case TypeFlag::INT: { + ApplyNarrowing(); + break; + } + case TypeFlag::LONG: { + ApplyNarrowing(); + break; + } + case TypeFlag::FLOAT: { + ApplyNarrowing(); + break; + } + case TypeFlag::DOUBLE: { + ApplyNarrowing(); + break; + } + default: { + break; + } + } + } + + template + void ApplyNarrowing() + { + using SType = typename SourceType::UType; + using TType = typename TargetType::UType; + SType value = reinterpret_cast(source_)->GetValue(); + + if (util::Helpers::IsTargetFitInSourceRange(value)) { + relation_->GetNode()->SetTsType(checker_->Allocator()->New(static_cast(value))); + relation_->Result(true); + } else { + relation_->Result(RelationResult::ERROR); + } + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/narrowingWideningConverter.cpp b/checker/ets/narrowingWideningConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f79174d7f9089fee948a549982ce448c75f9ce39 --- /dev/null +++ b/checker/ets/narrowingWideningConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "narrowingWideningConverter.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/ets/narrowingWideningConverter.h b/checker/ets/narrowingWideningConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..0ba235c7632138a901ef7b66a0b1d9891a1b9c3a --- /dev/null +++ b/checker/ets/narrowingWideningConverter.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_WIDENING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_WIDENING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/ets/narrowingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/wideningConverter.h" + +namespace panda::es2panda::checker { +class NarrowingWideningConverter : public NarrowingConverter { +public: + explicit NarrowingWideningConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : NarrowingConverter(checker, relation, target, source) + { + if (relation_->IsTrue() || relation_->IsError()) { + return; + } + + WideningConverter(checker, relation, target, source); + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/object.cpp b/checker/ets/object.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0c50cc0d1f51b07fc249f4bcc689be8329e5969 --- /dev/null +++ b/checker/ets/object.cpp @@ -0,0 +1,794 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classElement.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classStaticBlock.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/ir/statements/expressionStatement.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/functionExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/callExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/thisExpression.h" +#include "plugins/ecmascript/es2panda/ir/statements/classDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsClassImplements.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceHeritage.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceBody.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" + +namespace panda::es2panda::checker { +ETSObjectType *ETSChecker::GetSuperType(ETSObjectType *type) +{ + if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_SUPER)) { + return type->SuperType(); + } + + ASSERT(type->Variable() && type->GetDeclNode()->IsClassDefinition()); + auto *classDef = type->GetDeclNode()->AsClassDefinition(); + + if (!classDef->Super()) { + type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER); + if (type != globalBuiltinObjectType_) { + type->SetSuperType(globalBuiltinObjectType_); + } + return globalBuiltinObjectType_; + } + + TypeStackElement tse(this, type, {"Cyclic inheritance involving ", type->Name(), "."}, classDef->Ident()->Start()); + + Type *superType = classDef->Super()->AsTypeNode()->GetType(this); + + if (!superType->IsETSObjectType() || !superType->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) { + ThrowTypeError("Super type is not extensible.", classDef->Super()->Start()); + } + + ETSObjectType *superObj = superType->AsETSObjectType(); + + if (!(superObj->GetDeclNode()->IsOpen() || superObj->GetDeclNode()->IsAbstract())) { + ThrowTypeError("Cannot inherit without 'open'.", classDef->Super()->Start()); + } + + type->SetSuperType(superObj); + GetSuperType(superObj); + + type->AddObjectFlag(ETSObjectFlags::RESOLVED_SUPER); + return type->SuperType(); +} + +void ETSChecker::ValidateImplementedInterface(ETSObjectType *type, Type *interface, + std::unordered_set *extendsSet, const lexer::SourcePosition &pos) +{ + if (!interface->IsETSObjectType() || !interface->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::INTERFACE)) { + ThrowTypeError("Interface expected here.", pos); + } + + if (!extendsSet->insert(interface).second) { + ThrowTypeError("Repeated interface.", pos); + } + + type->AddInterface(interface->AsETSObjectType()); + GetInterfacesOfInterface(interface->AsETSObjectType()); +} + +ArenaVector ETSChecker::GetInterfacesOfClass(ETSObjectType *type) +{ + const auto *declNode = type->GetDeclNode()->AsClassDefinition(); + + std::unordered_set extendsSet; + for (auto *it : declNode->Implements()) { + ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start()); + } + + return type->Interfaces(); +} + +ArenaVector ETSChecker::GetInterfacesOfInterface(ETSObjectType *type) +{ + const auto *declNode = type->GetDeclNode()->AsTSInterfaceDeclaration(); + + TypeStackElement tse(this, type, {"Cyclic inheritance involving ", type->Name(), "."}, declNode->Id()->Start()); + + std::unordered_set extendsSet; + for (auto *it : declNode->Extends()) { + ValidateImplementedInterface(type, it->Expr()->AsTypeNode()->GetType(this), &extendsSet, it->Start()); + } + + return type->Interfaces(); +} + +ArenaVector ETSChecker::GetInterfaces(ETSObjectType *type) +{ + if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES)) { + return type->Interfaces(); + } + + ASSERT(type->GetDeclNode()->IsClassDefinition() || type->GetDeclNode()->IsTSInterfaceDeclaration()); + + if (type->GetDeclNode()->IsClassDefinition()) { + GetInterfacesOfClass(type); + } else { + GetInterfacesOfInterface(type); + } + + type->AddObjectFlag(ETSObjectFlags::RESOLVED_INTERFACES); + return type->Interfaces(); +} + +void ETSChecker::SetTypeParameterType(ir::TSTypeParameter *typeParam, Type *assemblerType) +{ + auto *var = typeParam->Name()->Variable(); + auto *typeParamType = CreateTypeParameter(assemblerType); + typeParamType->SetVariable(var); + var->SetTsType(typeParamType); +} + +void ETSChecker::CreateTypeForTypeParameters(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParams) +{ + if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS)) { + return; + } + + checker::ScopeContext scopeCtx(this, typeParams->Scope()); + + for (auto *param : typeParams->Params()) { + Type *paramType = globalBuiltinObjectType_; + + if (param->Constraint()) { + auto *constraintType = param->Constraint()->GetType(this); + + if (!constraintType->IsETSObjectType()) { + ThrowTypeError("Extends constraint must be an object", param->Constraint()->Start()); + } + + paramType = constraintType; + } + + SetTypeParameterType(param, paramType); + } + + type->AddObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS); +} + +void ETSChecker::CreateTypeForInterfaceTypeParameters(ETSObjectType *type) +{ + ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + CreateTypeForTypeParameters(type, typeParams); +} + +void ETSChecker::CreateTypeForClassTypeParameters(ETSObjectType *type) +{ + ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->AsClassDefinition()->TypeParams(); + CreateTypeForTypeParameters(type, typeParams); +} + +ETSObjectType *ETSChecker::BuildInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl) +{ + auto *refVar = interfaceDecl->Id()->Variable(); + ASSERT(refVar); + refVar->AddFlag(binder::VariableFlags::INTERFACE); + + checker::ETSObjectType *interfaceType {}; + if (!refVar->TsType()) { + interfaceType = CreateETSObjectType(refVar->Name(), interfaceDecl, checker::ETSObjectFlags::INTERFACE); + interfaceType->SetVariable(refVar); + refVar->SetTsType(interfaceType); + } else { + interfaceType = refVar->TsType()->AsETSObjectType(); + } + + if (interfaceDecl->TypeParams()) { + CreateTypeForInterfaceTypeParameters(interfaceType); + } + + GetInterfacesOfInterface(interfaceType); + + checker::ScopeContext scopeCtx(this, interfaceDecl->Scope()); + auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_INTERFACE, interfaceType); + + ResolveDeclaredMembersOfObject(interfaceType); + + return interfaceType; +} + +ETSObjectType *ETSChecker::BuildClassProperties(ir::ClassDefinition *classDef) +{ + if (classDef->IsOpen() && classDef->IsAbstract()) { + ThrowTypeError("Cannot use both 'open' and 'abstract' modifiers.", classDef->Start()); + } + + const util::StringView &className = classDef->Ident()->Name(); + auto *classScope = classDef->Scope(); + binder::ScopeFindResult result = classScope->Find(className); + ASSERT(result.variable); + result.variable->AddFlag(binder::VariableFlags::CLASS); + + checker::ETSObjectType *classType {}; + if (!result.variable->TsType()) { + classType = CreateETSObjectType(className, classDef, checker::ETSObjectFlags::CLASS); + classType->SetVariable(result.variable); + result.variable->SetTsType(classType); + if (classDef->IsAbstract()) { + classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT); + } + } else { + classType = result.variable->TsType()->AsETSObjectType(); + } + + classDef->SetTsType(classType); + + if (classDef->TypeParams()) { + CreateTypeForClassTypeParameters(classType); + } + + if (!classType->HasObjectFlag(ETSObjectFlags::RESOLVED_SUPER)) { + GetSuperType(classType); + GetInterfacesOfClass(classType); + } + + if (classType->HasObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS)) { + return classType; + } + + checker::ScopeContext scopeCtx(this, classScope); + auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_CLASS, classType); + + ResolveDeclaredMembersOfObject(classType); + + return classType; +} + +ETSObjectType *ETSChecker::BuildAnonymousClassProperties(ir::ClassDefinition *classDef, ETSObjectType *superType) +{ + auto classType = CreateETSObjectType(classDef->Ident()->Name(), classDef, checker::ETSObjectFlags::CLASS); + classDef->SetTsType(classType); + classType->SetSuperType(superType); + classType->AddObjectFlag(checker::ETSObjectFlags::RESOLVED_SUPER); + + checker::ScopeContext scopeCtx(this, classDef->Scope()); + auto savedContext = checker::SavedCheckerContext(this, checker::CheckerStatus::IN_CLASS, classType); + + ResolveDeclaredMembersOfObject(classType); + + return classType; +} + +void ETSChecker::ResolveDeclaredMembersOfObject(ETSObjectType *type) +{ + if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS)) { + return; + } + + auto *declNode = type->GetDeclNode(); + auto &body = declNode->IsTSInterfaceDeclaration() ? declNode->AsTSInterfaceDeclaration()->Body()->Body() + : declNode->AsClassDefinition()->Body(); + + for (auto *it : body) { + bool addStatic = it->IsStatic(); + util::StringView memberName {}; + + switch (it->Type()) { + case ir::AstNodeType::CLASS_PROPERTY: { + auto *element = it->AsClassElement(); + memberName = element->Id()->Name(); + break; + } + case ir::AstNodeType::METHOD_DEFINITION: { + auto *methodDef = it->AsMethodDefinition(); + auto *funcType = BuildMethodSignature(methodDef); + methodDef->SetTsType(funcType); + memberName = methodDef->Id()->Name(); + + if (methodDef->IsConstructor()) { + addStatic = true; + type->AddConstructSignature(funcType->CallSignatures()); + } + + break; + } + case ir::AstNodeType::CLASS_DECLARATION: { + auto *classDecl = it->AsClassDeclaration(); + memberName = classDecl->Definition()->Ident()->Name(); + break; + } + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { + auto *interfaceDecl = it->AsTSInterfaceDeclaration(); + memberName = interfaceDecl->Id()->Name(); + break; + } + case ir::AstNodeType::CLASS_STATIC_BLOCK: { + memberName = compiler::Signatures::CCTOR; + break; + } + default: { + continue; + } + } + + binder::ScopeFindResult res = scope_->Find(memberName); + ASSERT(res.variable); + + if (addStatic) { + res.variable->AddFlag(binder::VariableFlags::STATIC); + } + + if (!it->IsMethodDefinition()) { + res.variable->AddFlag(GetAccessFlagFromNode(it)); + } + + type->AddProperty(res.variable->AsLocalVariable()); + } + + type->AddObjectFlag(ETSObjectFlags::RESOLVED_MEMBERS); + return; +} + +const std::vector ETSChecker::CollectAbstractSignaturesFromObject(ETSObjectType *objType) +{ + std::vector abstracts; + for (const auto &[_, prop] : objType->Properties()) { + if (!prop->TsType() || !prop->TsType()->IsETSFunctionType()) { + continue; + } + + auto *funcType = prop->TsType()->AsETSFunctionType(); + for (auto *sig : funcType->CallSignatures()) { + if (sig->HasSignatureFlag(SignatureFlags::ABSTRACT) && !sig->HasSignatureFlag(SignatureFlags::PRIVATE)) { + abstracts.push_back(sig); + } + } + } + + return abstracts; +} + +void ETSChecker::CreateFunctionTypesFromAbstracts(const std::vector &abstracts, + ArenaVector *target) +{ + for (auto *it : abstracts) { + auto name = it->Function()->Id()->Name(); + auto *found = FindFunctionInVectorGivenByName(name, *target); + if (found) { + found->AddCallSignature(it); + continue; + } + + auto *created = CreateETSFunctionType(it); + created->AddTypeFlag(TypeFlag::SYNTHETIC); + target->push_back(created); + } +} + +void ETSChecker::ComputeAbstractsFromInterface(ETSObjectType *interfaceType) +{ + auto cached = cachedComputedAbstracts_.find(interfaceType); + if (cached != cachedComputedAbstracts_.end()) { + return; + } + + for (auto *it : interfaceType->Interfaces()) { + ComputeAbstractsFromInterface(it); + } + + ArenaVector merged(allocator_.Adapter()); + CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(interfaceType), &merged); + std::unordered_set abstractInheritanceTarget; + + for (auto *interface : interfaceType->Interfaces()) { + auto found = cachedComputedAbstracts_.find(interface); + ASSERT(found != cachedComputedAbstracts_.end()); + + if (!abstractInheritanceTarget.insert(found->first).second) { + continue; + } + + MergeComputedAbstracts(merged, found->second.first); + + for (auto *base : found->second.second) { + abstractInheritanceTarget.insert(base); + } + } + + cachedComputedAbstracts_.insert({interfaceType, {merged, abstractInheritanceTarget}}); +} + +ArenaVector &ETSChecker::GetAbstractsForClass(ETSObjectType *classType) +{ + ArenaVector merged(allocator_.Adapter()); + CreateFunctionTypesFromAbstracts(CollectAbstractSignaturesFromObject(classType), &merged); + + std::unordered_set abstractInheritanceTarget; + if (classType->SuperType()) { + auto base = cachedComputedAbstracts_.find(classType->SuperType()); + ASSERT(base != cachedComputedAbstracts_.end()); + MergeComputedAbstracts(merged, base->second.first); + + abstractInheritanceTarget.insert(base->first); + for (auto *it : base->second.second) { + abstractInheritanceTarget.insert(it); + } + } + + for (auto *it : classType->Interfaces()) { + ComputeAbstractsFromInterface(it); + auto found = cachedComputedAbstracts_.find(it); + ASSERT(found != cachedComputedAbstracts_.end()); + + if (!abstractInheritanceTarget.insert(found->first).second) { + continue; + } + + MergeComputedAbstracts(merged, found->second.first); + + for (auto *interface : found->second.second) { + abstractInheritanceTarget.insert(interface); + } + } + + return cachedComputedAbstracts_.insert({classType, {merged, abstractInheritanceTarget}}).first->second.first; +} + +void ETSChecker::ValidateOverriding(ETSObjectType *classType, const lexer::SourcePosition &pos) +{ + if (classType->HasObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS)) { + return; + } + + bool throwError = true; + if (classType->HasObjectFlag(ETSObjectFlags::ABSTRACT)) { + throwError = false; + } + + if (classType->SuperType()) { + ValidateOverriding(classType->SuperType(), classType->SuperType()->GetDeclNode()->Start()); + } + + auto &abstractsToBeImplemented = GetAbstractsForClass(classType); + std::vector implementedSignatures; + + auto *superIter = classType; + do { + for (auto it = abstractsToBeImplemented.begin(); it != abstractsToBeImplemented.end(); it++) { + for (const auto &[_, prop] : superIter->Properties()) { + if (!prop || !prop->TsType() || !prop->TsType()->IsETSFunctionType()) { + continue; + } + AddImplementedSignature(&implementedSignatures, prop, *it); + } + } + superIter = superIter->SuperType(); + } while (superIter); + + SavedTypeRelationFlagsContext savedFlagsCtx(relation_, TypeRelationFlag::NO_RETURN_TYPE_CHECK); + bool functionOverridden; + bool foundSignature; + for (auto it = abstractsToBeImplemented.begin(); it != abstractsToBeImplemented.end();) { + functionOverridden = false; + for (auto abstractSignature = (*it)->CallSignatures().begin(); + abstractSignature != (*it)->CallSignatures().end();) { + foundSignature = false; + for (auto implemented : implementedSignatures) { + if (relation_->IsIdenticalTo(*abstractSignature, implemented) && + (*abstractSignature)->Function()->Id()->Name() == implemented->Function()->Id()->Name() && + IsTypeAssignableTo(implemented->ReturnType(), (*abstractSignature)->ReturnType())) { + if (!implemented->Function()->IsOverride() && (implemented->Owner() == classType)) { + ThrowTypeError("Method overriding is only allowed with 'override' modifier", + implemented->Function()->Start()); + } + if ((*it)->CallSignatures().size() > 1) { + abstractSignature = (*it)->CallSignatures().erase(abstractSignature); + foundSignature = true; + } else { + it = abstractsToBeImplemented.erase(it); + functionOverridden = true; + } + implemented->AddSignatureFlag(SignatureFlags::OPEN); + + break; + } + } + if (functionOverridden) { + break; + } + if (!foundSignature) { + abstractSignature++; + } + } + if (!functionOverridden) { + it++; + } + } + + if (abstractsToBeImplemented.size() > 0 && throwError) { + auto unimplementedSignature = abstractsToBeImplemented.front()->CallSignatures().front(); + ThrowTypeError({classType->Name(), " is not abstract and does not override abstract method ", + unimplementedSignature->Function()->Id()->Name(), unimplementedSignature, " in ", + GetContainingObjectNameFromSignature(unimplementedSignature)}, + pos); + } + + classType->AddObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS); +} + +void ETSChecker::AddImplementedSignature(std::vector *implementedSignatures, + binder::LocalVariable *function, ETSFunctionType *it) +{ + for (auto signature : function->TsType()->AsETSFunctionType()->CallSignatures()) { + if (signature->Function()->IsAbstract() || signature->Function()->IsStatic()) { + continue; + } + if (signature->Function()->Id()->Name() == it->Name()) { + implementedSignatures->emplace_back(signature); + } + } +} + +void ETSChecker::CheckClassDefinition(ir::ClassDefinition *classDef) +{ + auto *classType = classDef->TsType()->AsETSObjectType(); + auto *enclosingClass = context_.ContainingClass(); + auto newStatus = checker::CheckerStatus::IN_CLASS; + classType->SetEnclosingType(enclosingClass); + + if (!classDef->IsStatic() && enclosingClass && !enclosingClass->HasObjectFlag(ETSObjectFlags::GLOBAL)) { + newStatus |= CheckerStatus::INNER_CLASS; + } + + if (classDef->IsGlobal()) { + classType->AddObjectFlag(checker::ETSObjectFlags::GLOBAL); + } + + checker::ScopeContext scopeCtx(this, classDef->Scope()); + auto savedContext = SavedCheckerContext(this, newStatus, classType); + + if (classDef->IsAbstract()) { + AddStatus(checker::CheckerStatus::IN_ABSTRACT); + classType->AddObjectFlag(checker::ETSObjectFlags::ABSTRACT); + } + + if (classDef->IsStatic() && !context_.ContainingClass()->HasObjectFlag(ETSObjectFlags::GLOBAL)) { + AddStatus(checker::CheckerStatus::IN_STATIC_CONTEXT); + } + + for (auto *it : classDef->Body()) { + if (it->IsClassProperty()) { + it->Check(this); + } + } + + for (auto *it : classDef->Body()) { + if (!it->IsClassProperty()) { + it->Check(this); + } + } + + if (classDef->IsGlobal()) { + return; + } + + for (auto *it : classType->ConstructSignatures()) { + CheckCyclicContructorCall(it); + } + + ValidateOverriding(classType, classDef->Start()); + CheckConstFields(classType); +} + +void ETSChecker::CheckConstFields(const ETSObjectType *classType) +{ + for (const auto &[_, prop] : classType->Properties()) { + if (!prop->Declaration()->IsConstDecl() || !prop->HasFlag(binder::VariableFlags::EXPLICIT_INIT_REQUIRED)) { + continue; + } + CheckConstFieldInitialized(classType, prop); + } +} + +void ETSChecker::CheckConstFieldInitialized(const ETSObjectType *classType, binder::LocalVariable *classVar) +{ + const bool classVarStatic = classVar->Declaration()->Node()->AsClassProperty()->IsStatic(); + for (const auto &[_, prop] : classType->Properties()) { + if (!prop->TsType()->IsETSFunctionType()) { + continue; + } + + const auto &callSigs = prop->TsType()->AsETSFunctionType()->CallSignatures(); + for (const auto *signature : callSigs) { + if ((signature->Function()->IsConstructor() && !classVarStatic) || + (signature->Function()->IsStaticBlock() && classVarStatic)) { + CheckConstFieldInitialized(signature, classVar); + } + } + } +} + +void ETSChecker::FindAssignment(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized) +{ + if (node->IsAssignmentExpression() && node->AsAssignmentExpression()->Target() == classVar) { + if (initialized) { + ThrowTypeError({"Variable '", classVar->Declaration()->Name(), "' might already have been initialized"}, + node->Start()); + } + initialized = true; + return; + } + FindAssignments(node, classVar, initialized); +} + +void ETSChecker::FindAssignments(const ir::AstNode *node, const binder::LocalVariable *classVar, bool &initialized) +{ + node->Iterate( + [this, classVar, &initialized](ir::AstNode *childNode) { FindAssignment(childNode, classVar, initialized); }); +} + +void ETSChecker::CheckConstFieldInitialized(const Signature *signature, binder::LocalVariable *classVar) +{ + bool initialized = false; + const auto &stmts = signature->Function()->Body()->AsBlockStatement()->Statements(); + const auto it = stmts.begin(); + + if (it != stmts.end()) { + if (const auto *first = *it; + first->IsExpressionStatement() && first->AsExpressionStatement()->GetExpression()->IsCallExpression() && + first->AsExpressionStatement()->GetExpression()->AsCallExpression()->Callee()->IsThisExpression()) { + initialized = true; + } + } + + // TODO(szd) control flow + FindAssignments(signature->Function()->Body(), classVar, initialized); + if (!initialized) { + ThrowTypeError({"Variable '", classVar->Declaration()->Name(), "' might not have been initialized"}, + signature->Function()->End()); + } + + classVar->RemoveFlag(binder::VariableFlags::EXPLICIT_INIT_REQUIRED); +} + +void ETSChecker::CheckInnerClassMembers(const ETSObjectType *classType) +{ + const auto &innerProps = classType->Properties(); + for (const auto &[_, innerProp] : innerProps) { + if (innerProp->TsType()->IsETSFunctionType()) { + const auto &callSigs = innerProp->TsType()->AsETSFunctionType()->CallSignatures(); + for (auto *sig : callSigs) { + if (sig->Function()->IsStatic()) { + ThrowTypeError("Inner class cannot have static methods", sig->Function()->Id()->Start()); + } + } + } else if (innerProp->Declaration()->IsLetOrConstDecl() && + innerProp->Declaration()->Node()->IsClassProperty()) { + const auto *classProp = innerProp->Declaration()->Node()->AsClassProperty(); + if (classProp->IsStatic() && !(classProp->IsConst())) { + ThrowTypeError("Inner class cannot have non-const static properties", classProp->Start()); + } + } + } +} + +Type *ETSChecker::ValidateArrayIndex(ir::Expression *expr) +{ + Type *indexType = ApplyUnaryOperatorPromotion(expr->Check(this)); + + if (!indexType->HasTypeFlag(TypeFlag::ETS_ARRAY_INDEX)) { + ThrowTypeError("Only intergal types can be used as index.", expr->Start()); + } + + return indexType; +} + +Type *ETSChecker::CheckArrayElementAccess(ir::MemberExpression *expr) +{ + Type *arrayType = expr->Object()->Check(this); + + if (!arrayType->IsETSArrayType()) { + ThrowTypeError("Indexed access expression can only be used in array type.", expr->Object()->Start()); + } + + ValidateArrayIndex(expr->Property()); + + // TODO: apply capture conversion on this type + return arrayType->AsETSArrayType()->ElementType(); +} + +ETSObjectType *ETSChecker::CheckThisOrSuperAccess(ir::Expression *node, ETSObjectType *classType, std::string_view msg) +{ + if (classType->GetDeclNode()->AsClassDefinition()->IsGlobal() || + (!node->Parent()->IsMemberExpression() && !node->Parent()->IsCallExpression())) { + ThrowTypeError({"Cannot reference", msg, "in this context."}, node->Start()); + } + + return classType; +} + +void ETSChecker::CheckCyclicContructorCall(Signature *signature) +{ + ASSERT(signature->Function()); + + if (!signature->Function()->Body()) { + return; + } + + auto *funcBody = signature->Function()->Body()->AsBlockStatement(); + + TypeStackElement tse(this, signature, "Recursive constructor invocation", signature->Function()->Start()); + + if (!funcBody->Statements().empty() && funcBody->Statements()[0]->IsExpressionStatement() && + funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->IsCallExpression() && + funcBody->Statements()[0] + ->AsExpressionStatement() + ->GetExpression() + ->AsCallExpression() + ->Callee() + ->IsThisExpression()) { + auto *constructorCall = funcBody->Statements()[0]->AsExpressionStatement()->GetExpression()->AsCallExpression(); + ASSERT(constructorCall->Signature()); + CheckCyclicContructorCall(constructorCall->Signature()); + } +} + +ETSObjectType *ETSChecker::CheckExceptionType(checker::Type *type, lexer::SourcePosition pos) +{ + auto *exceptionType = + CheckException(type, pos, globalBuiltinExceptionType_, compiler::Signatures::BUILTIN_EXCEPTION_CLASS); + + if (relation_->IsAssignableTo(exceptionType, globalBuiltinRuntimeExceptionType_)) { + ThrowTypeError({"Recover clause must be used for any instance of '", exceptionType->Name(), "'"}, pos); + } + + return exceptionType; +} + +ETSObjectType *ETSChecker::CheckRuntimeExceptionType(checker::Type *type, lexer::SourcePosition pos) +{ + return CheckException(type, pos, globalBuiltinRuntimeExceptionType_, + compiler::Signatures::BUILTIN_RUNTIME_EXCEPTION_CLASS); +} + +ETSObjectType *ETSChecker::CheckException(checker::Type *type, lexer::SourcePosition pos, ETSObjectType *expected, + std::string_view msg) +{ + if (!type->IsETSObjectType() || !relation_->IsAssignableTo(type, expected)) { + ThrowTypeError({"Argument must be an instance of '", msg, "'"}, pos); + } + + return type->AsETSObjectType(); +} + +Type *ETSChecker::TryToInstantiate(Type *type, ArenaAllocator *allocator, TypeRelation *relation, + GlobalTypesHolder *globalTypes) +{ + if (type->IsETSTypeReference() || type->IsETSFunctionType() || + (type->IsETSObjectType() && type->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::UNCOMPLETE_INSTANTIATION))) { + return type->Instantiate(allocator, relation, globalTypes); + } + + return type; +} + +} // namespace panda::es2panda::checker diff --git a/checker/ets/primitiveWrappers.cpp b/checker/ets/primitiveWrappers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fba7f28ccf9125aabd3b3f5e612a050e98bb5970 --- /dev/null +++ b/checker/ets/primitiveWrappers.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "primitiveWrappers.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/ets/primitiveWrappers.h b/checker/ets/primitiveWrappers.h new file mode 100644 index 0000000000000000000000000000000000000000..d4da71c31a755a875023449aaa059a6e012b01e1 --- /dev/null +++ b/checker/ets/primitiveWrappers.h @@ -0,0 +1,58 @@ + +/** + * Copyright (c) 2021 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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_PRIMITIVEWRAPPERS_H +#define ES2PANDA_COMPILER_CHECKER_ETS_PRIMITIVEWRAPPERS_H + +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" + +namespace panda::es2panda::checker { +class ETSObjectType; + +using WrapperDesc = ArenaUnorderedMap>; + +class PrimitiveWrappers { +public: + explicit PrimitiveWrappers(ArenaAllocator *allocator) : wrappers_(allocator->Adapter()) + { + wrappers_.insert({"Boolean", {nullptr, ETSObjectFlags::BUILTIN_BOOLEAN}}); + wrappers_.insert({"Byte", {nullptr, ETSObjectFlags::BUILTIN_BYTE}}); + wrappers_.insert({"Char", {nullptr, ETSObjectFlags::BUILTIN_CHAR}}); + wrappers_.insert({"Short", {nullptr, ETSObjectFlags::BUILTIN_SHORT}}); + wrappers_.insert({"Int", {nullptr, ETSObjectFlags::BUILTIN_INT}}); + wrappers_.insert({"Long", {nullptr, ETSObjectFlags::BUILTIN_LONG}}); + wrappers_.insert({"Float", {nullptr, ETSObjectFlags::BUILTIN_FLOAT}}); + wrappers_.insert({"Double", {nullptr, ETSObjectFlags::BUILTIN_DOUBLE}}); + } + NO_COPY_SEMANTIC(PrimitiveWrappers); + NO_MOVE_SEMANTIC(PrimitiveWrappers); + ~PrimitiveWrappers() = default; + + WrapperDesc &Wrappers() + { + return wrappers_; + } + + const WrapperDesc &Wrappers() const + { + return wrappers_; + } + +private: + WrapperDesc wrappers_; +}; +} // namespace panda::es2panda::checker +#endif diff --git a/checker/ets/typeConverter.cpp b/checker/ets/typeConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90beaa5358fa30e46ff17873ed24cf193b4305d1 --- /dev/null +++ b/checker/ets/typeConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "typeConverter.h" + +namespace panda::es2panda::checker { +} diff --git a/checker/ets/typeConverter.h b/checker/ets/typeConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..6b321d9ad3ebd87134866670dfa7226f4f61eec4 --- /dev/null +++ b/checker/ets/typeConverter.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_TYPE_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_TYPE_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ETSChecker; + +class TypeConverter { +public: + TypeConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : checker_(checker), relation_(relation), target_(target), source_(source) + { + } + + Type *Result() + { + return result_; + } + +protected: + ETSChecker *checker_; + TypeRelation *relation_; + Type *target_; + Type *source_; + Type *result_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/typeCreation.cpp b/checker/ets/typeCreation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74d04cb244cfd0a1b89c2c0d679c91ff5ea0aaec --- /dev/null +++ b/checker/ets/typeCreation.cpp @@ -0,0 +1,277 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsScript.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { +ByteType *ETSChecker::CreateByteType(int8_t value) +{ + return allocator_.New(value); +} + +ETSBooleanType *ETSChecker::CreateETSBooleanType(bool value) +{ + return allocator_.New(value); +} + +DoubleType *ETSChecker::CreateDoubleType(double value) +{ + return allocator_.New(value); +} + +FloatType *ETSChecker::CreateFloatType(float value) +{ + return allocator_.New(value); +} + +IntType *ETSChecker::CreateIntType(int32_t value) +{ + return allocator_.New(value); +} + +IntType *ETSChecker::CreateIntTypeFromType(Type *type) +{ + if (!type->HasTypeFlag(TypeFlag::CONSTANT)) { + return GlobalIntType()->AsIntType(); + } + + if (type->IsIntType()) { + return type->AsIntType(); + } + + switch (ETSType(type)) { + case TypeFlag::CHAR: { + return CreateIntType(static_cast(type->AsCharType()->GetValue())); + } + case TypeFlag::BYTE: { + return CreateIntType(static_cast(type->AsByteType()->GetValue())); + } + case TypeFlag::SHORT: { + return CreateIntType(static_cast(type->AsShortType()->GetValue())); + } + default: { + return nullptr; + } + } +} + +LongType *ETSChecker::CreateLongType(int64_t value) +{ + return allocator_.New(value); +} + +ShortType *ETSChecker::CreateShortType(int16_t value) +{ + return allocator_.New(value); +} + +CharType *ETSChecker::CreateCharType(char16_t value) +{ + return allocator_.New(value); +} + +ETSStringType *ETSChecker::CreateETSStringType(util::StringView value) +{ + return allocator_.New(&allocator_, globalBuiltinStringType_, value); +} + +ETSArrayType *ETSChecker::CreateETSArrayType(Type *elementType) +{ + auto res = arrayTypes_.find(elementType); + + if (res != arrayTypes_.end()) { + return res->second; + } + + auto *arrayType = allocator_.New(elementType); + arrayTypes_.insert({elementType, arrayType}); + + return arrayType; +} + +ETSFunctionType *ETSChecker::CreateETSFunctionType(Signature *signature) +{ + return allocator_.New(signature->Function()->Id()->Name(), signature, &allocator_); +} + +Signature *ETSChecker::CreateSignature(SignatureInfo *info, Type *returnType, ir::ScriptFunction *func) +{ + return allocator_.New(info, returnType, func); +} + +Signature *ETSChecker::CreateSignature(SignatureInfo *info, Type *returnType, util::StringView internalName) +{ + return allocator_.New(info, returnType, internalName); +} + +SignatureInfo *ETSChecker::CreateSignatureInfo() +{ + return allocator_.New(&allocator_); +} + +ETSTypeParameter *ETSChecker::CreateTypeParameter(Type *assemblerType) +{ + return allocator_.New(assemblerType); +} + +ETSTypeReference *ETSChecker::CreateTypeReference(Type **ref, Type **assemblerRef, binder::LocalVariable *refVar) +{ + return allocator_.New(ref, assemblerRef, refVar); +} + +ETSFunctionType *ETSChecker::CreateETSFunctionType(util::StringView name) +{ + return allocator_.New(name, &allocator_); +} + +ETSObjectType *ETSChecker::CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, + ETSObjectFlags flags) +{ + if (name == compiler::Signatures::BUILTIN_STRING_CLASS) { + if (globalBuiltinStringType_) { + return globalBuiltinStringType_; + } + globalBuiltinStringType_ = + CreateNewETSObjectType(name, declNode, flags | ETSObjectFlags::BUILTIN_STRING | ETSObjectFlags::STRING); + + globalTypes_->GlobalTypes()[static_cast(GlobalTypeId::ETS_STRING)] = + allocator_.New(&allocator_, globalBuiltinStringType_); + return globalBuiltinStringType_; + } + + auto *objType = CreateNewETSObjectType(name, declNode, flags); + + if (name == compiler::Signatures::BUILTIN_OBJECT_CLASS) { + if (globalBuiltinObjectType_) { + return globalBuiltinObjectType_; + } + globalBuiltinObjectType_ = objType; + } else if (name == compiler::Signatures::BUILTIN_EXCEPTION_CLASS) { + if (globalBuiltinExceptionType_) { + return globalBuiltinExceptionType_; + } + globalBuiltinExceptionType_ = objType; + } else if (name == compiler::Signatures::BUILTIN_RUNTIME_EXCEPTION_CLASS) { + if (globalBuiltinRuntimeExceptionType_) { + return globalBuiltinRuntimeExceptionType_; + } + globalBuiltinRuntimeExceptionType_ = objType; + } else if (name == compiler::Signatures::BUILTIN_CLASS_CLASS) { + if (globalBuiltinClassType_) { + return globalBuiltinClassType_; + } + globalBuiltinClassType_ = objType; + } + + return objType; +} + +ETSObjectType *ETSChecker::CreateETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags) +{ + auto res = primitiveWrappers_.Wrappers().find(name); + if (res == primitiveWrappers_.Wrappers().end()) { + return CreateETSObjectTypeCheckBuiltins(name, declNode, flags); + } + + if (res->second.first) { + return res->second.first; + } + + auto *objType = CreateNewETSObjectType(name, declNode, flags | res->second.second); + primitiveWrappers_.Wrappers().at(name).first = objType; + return objType; +} + +ETSObjectType *ETSChecker::CreateNewETSObjectType(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags) +{ + util::StringView assemblerName = name; + util::StringView prefix {}; + + auto *containingClass = util::Helpers::GetContainingClassDefinition(declNode->Parent()); + + if (containingClass) { + prefix = containingClass->TsType()->AsETSObjectType()->AssemblerName(); + } else { + auto *containingInterface = util::Helpers::GetContainingClassDefinition(declNode->Parent()); + + if (containingInterface) { + prefix = containingInterface->TsType()->AsETSObjectType()->AssemblerName(); + } else { + auto *program = static_cast(declNode->GetTopStatement())->Program(); + prefix = program->GetPackageName(); + } + } + + if (!prefix.Empty()) { + util::UString fullPath(prefix, &allocator_); + fullPath.Append('.'); + fullPath.Append(name); + assemblerName = fullPath.View(); + } + + return allocator_.New(&allocator_, name, assemblerName, declNode, flags); +} + +std::tuple ETSChecker::CreateBuiltinArraySignatureInfo(ETSArrayType *arrayType, + size_t dim) +{ + std::stringstream ss; + arrayType->ToAssemblerType(ss); + ss << compiler::Signatures::METHOD_SEPARATOR << compiler::Signatures::CTOR << compiler::Signatures::MANGLE_BEGIN; + arrayType->ToAssemblerType(ss); + + auto *info = CreateSignatureInfo(); + info->minArgCount = dim; + + for (size_t i = 0; i < dim; i++) { + util::UString param(std::to_string(i), Allocator()); + auto *paramVar = binder::Scope::CreateVar(Allocator(), param.View(), binder::VariableFlags::NONE, nullptr); + paramVar->SetTsType(GlobalIntType()); + + info->params.push_back(paramVar); + + ss << compiler::Signatures::MANGLE_SEPARATOR << compiler::Signatures::PRIMITIVE_INT; + } + + ss << compiler::Signatures::MANGLE_SEPARATOR << compiler::Signatures::PRIMITIVE_VOID + << compiler::Signatures::MANGLE_SEPARATOR; + auto internalName = util::UString(ss.str(), Allocator()).View(); + + return {internalName, info}; +} + +Signature *ETSChecker::CreateBuiltinArraySignature(ETSArrayType *arrayType, size_t dim) +{ + auto res = globalArraySignatures_.find(arrayType); + + if (res != globalArraySignatures_.end()) { + return res->second; + } + + auto [internalName, info] = CreateBuiltinArraySignatureInfo(arrayType, dim); + auto *signature = CreateSignature(info, GlobalVoidType(), internalName); + globalArraySignatures_.insert({arrayType, signature}); + + return signature; +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/typeRelationContext.cpp b/checker/ets/typeRelationContext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..211f8b826c4d02e452d041b80601fa5fd4aaab41 --- /dev/null +++ b/checker/ets/typeRelationContext.cpp @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "typeRelationContext.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" +#include "plugins/ecmascript/es2panda/ir/expressions/arrayExpression.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsArrayType.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" + +namespace panda::es2panda::checker { +void AssignmentContext::ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node, + ETSArrayType *target) +{ + for (uint32_t index = 0; index < node->Elements().size(); index++) { + ir::Expression *currentArrayElem = node->Elements()[index]; + AssignmentContext(relation, currentArrayElem, currentArrayElem->Check(relation->GetChecker()->AsETSChecker()), + target->ElementType(), currentArrayElem->Start(), + {"Array element at index ", index, " is not compatible with the target array element type."}); + } +} + +bool InstantiationContext::ValidateTypeArguments(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs, + const lexer::SourcePosition &pos) +{ + if (typeParamDecl && !typeArgs) { + checker_->ThrowTypeError({"Type '", type, "' is generic but type argument were not provided."}, pos); + } + + if (!typeArgs) { + result_ = type; + return true; + } + + if (typeParamDecl->Params().size() != typeArgs->Params().size()) { + checker_->ThrowTypeError({"Type '", type, "' has ", typeParamDecl->Params().size(), + " number of type parameters, but ", typeArgs->Params().size(), + " type arguments were provided."}, + pos); + } + + return false; +} + +util::StringView InstantiationContext::GetHashFromTypeArguments(ArenaVector &typeArgTypes) +{ + std::stringstream ss; + + for (auto *it : typeArgTypes) { + // TODO: this is not the best solution, since A and A will produce the same string in their ToString + // method, but they are two different types + it->ToString(ss); + ss << compiler::Signatures::MANGLE_SEPARATOR; + } + + return util::UString(ss.str(), checker_->Allocator()).View(); +} + +void InstantiationContext::InstantiateType(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs) +{ + ArenaVector typeArgTypes(checker_->Allocator()->Adapter()); + typeArgTypes.reserve(typeArgs->Params().size()); + + auto flags = ETSObjectFlags::NO_OPTS; + + for (auto *it : typeArgs->Params()) { + auto *paramType = it->GetType(checker_); + typeArgTypes.push_back(it->GetType(checker_)); + + if (paramType->IsETSTypeReference()) { + flags |= ETSObjectFlags::UNCOMPLETE_INSTANTIATION; + } + } + + InstantiateType(type, typeParamDecl, typeArgTypes); + result_->AddObjectFlag(flags); +} + +void InstantiationContext::InstantiateType(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ArenaVector &typeArgTypes) +{ + util::StringView hash = GetHashFromTypeArguments(typeArgTypes); + auto *found = type->GetInstantiatedType(hash); + + if (found) { + result_ = found; + return; + } + + checker::ScopeContext scopeCtx(checker_, typeParamDecl->Scope()); + + for (size_t idx = 0; idx < typeParamDecl->Params().size(); idx++) { + auto *paramVar = typeParamDecl->Params()[idx]->Name()->Variable()->AsLocalVariable(); + auto *typeParam = paramVar->TsType()->AsETSTypeParameter(); + + typeParam->SetType(typeArgTypes[idx]); + typeArgVars_.push_back(paramVar); + } + + result_ = type->Instantiate(checker_->Allocator(), checker_->Relation(), checker_->GetGlobalTypesHolder()) + ->AsETSObjectType(); + result_->SetTypeArguments(std::move(typeArgTypes)); + type->GetInstantiationMap().insert({hash, result_}); + + for (auto *it : typeArgVars_) { + it->TsType()->AsETSTypeParameter()->SetType(nullptr); + } +} +} // namespace panda::es2panda::checker diff --git a/checker/ets/typeRelationContext.h b/checker/ets/typeRelationContext.h new file mode 100644 index 0000000000000000000000000000000000000000..50dfba110787397377d20e15fd2e6e16c5001361 --- /dev/null +++ b/checker/ets/typeRelationContext.h @@ -0,0 +1,165 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_TYPE_RELATION_CONTEXT_H +#define ES2PANDA_COMPILER_CHECKER_ETS_TYPE_RELATION_CONTEXT_H + +#include "plugins/ecmascript/es2panda/ir/expression.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterInstantiation.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +class ETSChecker; + +class AssignmentContext { +public: + AssignmentContext(TypeRelation *relation, ir::Expression *node, Type *source, Type *target, + const lexer::SourcePosition &pos, std::initializer_list list, + TypeRelationFlag flags = TypeRelationFlag::NONE) + { + if (node->IsArrayExpression() && target->IsETSArrayType()) { + ValidateArrayTypeInitializerByElement(relation, node->AsArrayExpression(), target->AsETSArrayType()); + return; + } + + flags_ |= flags; + relation->SetNode(node); + + if (source->HasTypeFlag(TypeFlag::CONSTANT)) { + flags_ |= TypeRelationFlag::NARROWING; + } + + relation->SetFlags(flags_); + + if (!relation->IsAssignableTo(source, target) && !(flags_ & TypeRelationFlag::NO_THROW)) { + relation->RaiseError(list, pos); + } + + relation->SetNode(nullptr); + relation->SetFlags(TypeRelationFlag::NONE); + assignable_ = true; + } + + bool IsAssigable() const + { + return assignable_; + } + + void ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node, ETSArrayType *target); + +private: + TypeRelationFlag flags_ = TypeRelationFlag::ASSIGNMENT_CONTEXT; + bool assignable_ {false}; +}; + +class InvocationContext { +public: + InvocationContext(TypeRelation *relation, ir::Expression *node, Type *source, Type *target, + const lexer::SourcePosition &pos, std::initializer_list list, + TypeRelationFlag initialFlags = TypeRelationFlag::NONE) + { + relation->SetNode(node); + + relation->SetFlags(flags_ | initialFlags); + + bool assignable = relation->IsAssignableTo(source, target); + + relation->SetNode(nullptr); + relation->SetFlags(TypeRelationFlag::NONE); + + if (!assignable) { + if (!(initialFlags & TypeRelationFlag::NO_THROW)) { + relation->RaiseError(list, pos); + } + return; + } + + invocable_ = true; + } + + bool IsInvocable() const + { + return invocable_; + } + +private: + TypeRelationFlag flags_ = TypeRelationFlag::BOXING | TypeRelationFlag::UNBOXING; + bool invocable_ {false}; +}; + +class InstantiationContext { +public: + InstantiationContext(ETSChecker *checker, ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs, + const lexer::SourcePosition &pos) + : checker_(checker), typeArgVars_(checker->Allocator()->Adapter()) + { + ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; + + if (type->HasObjectFlag(ETSObjectFlags::CLASS)) { + typeParamDecl = type->GetDeclNode()->AsClassDefinition()->TypeParams(); + } else { + ASSERT(type->HasObjectFlag(ETSObjectFlags::INTERFACE)) + typeParamDecl = type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + } + + if (ValidateTypeArguments(type, typeParamDecl, typeArgs, pos)) { + return; + } + + InstantiateType(type, typeParamDecl, typeArgs); + } + + InstantiationContext(ETSChecker *checker, ETSObjectType *type, ArenaVector &typeArgs) + : checker_(checker), typeArgVars_(checker->Allocator()->Adapter()) + { + ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; + + if (type->HasObjectFlag(ETSObjectFlags::CLASS)) { + typeParamDecl = type->GetDeclNode()->AsClassDefinition()->TypeParams(); + } else { + ASSERT(type->HasObjectFlag(ETSObjectFlags::INTERFACE)) + typeParamDecl = type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); + } + + InstantiateType(type, typeParamDecl, typeArgs); + } + + ETSObjectType *Result() + { + return result_; + } + +private: + bool ValidateTypeArguments(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs, const lexer::SourcePosition &pos); + void InstantiateType(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ir::TSTypeParameterInstantiation *typeArgs); + + void InstantiateType(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParamDecl, + ArenaVector &typeArgTypes); + util::StringView GetHashFromTypeArguments(ArenaVector &typeArgTypes); + + ETSChecker *checker_; + ArenaVector typeArgVars_; + ETSObjectType *result_ {}; +}; + +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/unboxingConverter.cpp b/checker/ets/unboxingConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a5f2053c317012cfb3ce367f29558d53de6520e --- /dev/null +++ b/checker/ets/unboxingConverter.cpp @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "unboxingConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::checker { + +checker::Type *UnboxingConverter::GlobalTypeFromSource(ETSObjectFlags type) +{ + switch (type) { + case ETSObjectFlags::BUILTIN_BOOLEAN: { + return checker_->GlobalETSBooleanType(); + } + case ETSObjectFlags::BUILTIN_BYTE: { + return checker_->GlobalByteType(); + } + case ETSObjectFlags::BUILTIN_SHORT: { + return checker_->GlobalShortType(); + } + case ETSObjectFlags::BUILTIN_CHAR: { + return checker_->GlobalCharType(); + } + case ETSObjectFlags::BUILTIN_INT: { + return checker_->GlobalIntType(); + } + case ETSObjectFlags::BUILTIN_LONG: { + return checker_->GlobalLongType(); + } + case ETSObjectFlags::BUILTIN_FLOAT: { + return checker_->GlobalFloatType(); + } + case ETSObjectFlags::BUILTIN_DOUBLE: { + return checker_->GlobalDoubleType(); + } + default: + return source_; + } +} + +} // namespace panda::es2panda::checker diff --git a/checker/ets/unboxingConverter.h b/checker/ets/unboxingConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..99cf7faeb2dd93660abbfbb831197cfe53ea0e72 --- /dev/null +++ b/checker/ets/unboxingConverter.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_UNBOXING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_UNBOXING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" + +namespace panda::es2panda::checker { + +class UnboxingConverter : public TypeConverter { +public: + UnboxingConverter(ETSChecker *checker, TypeRelation *relation, Type *source, Type *target) + : TypeConverter(checker, relation, target, source) + { + result_ = source_; + + if (!source_->IsETSObjectType()) { + return; + } + + result_ = GlobalTypeFromSource(source_->AsETSObjectType()->BuiltInKind()); + + if (relation->GetNode()) { + relation_->GetNode()->SetTsType(result_); + } + + relation_->Result(true); + } + + checker::Type *GlobalTypeFromSource(ETSObjectFlags type); +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/ets/wideningConverter.cpp b/checker/ets/wideningConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c7e36c5d74c40f2a85a9cf1679ba847c909811a --- /dev/null +++ b/checker/ets/wideningConverter.cpp @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "wideningConverter.h" + +namespace panda::es2panda::checker { +} // namespace panda::es2panda::checker diff --git a/checker/ets/wideningConverter.h b/checker/ets/wideningConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..8d458ddc6cf095c71f2c729a5bf89ca204452f60 --- /dev/null +++ b/checker/ets/wideningConverter.h @@ -0,0 +1,195 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_ETS_WIDENING_CONVERTER_H +#define ES2PANDA_COMPILER_CHECKER_ETS_WIDENING_CONVERTER_H + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { + +class WideningConverter : public TypeConverter { +public: + explicit WideningConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source) + : TypeConverter(checker, relation, target, source) + { + ASSERT(relation->GetNode()); + + if (!relation_->ApplyWidening()) { + return; + } + + if (!source_->HasTypeFlag(TypeFlag::CONSTANT)) { + ApplyGlobalWidening(); + } else { + ApplyConstWidening(); + } + } + +private: + void ApplyConstWidening() + { + switch (ETSChecker::ETSChecker::ETSType(target_)) { + case TypeFlag::SHORT: { + ApplyWidening(TypeFlag::WIDENABLE_TO_SHORT); + break; + } + case TypeFlag::INT: { + ApplyWidening(TypeFlag::WIDENABLE_TO_INT); + break; + } + case TypeFlag::LONG: { + ApplyWidening(TypeFlag::WIDENABLE_TO_LONG); + break; + } + case TypeFlag::FLOAT: { + ApplyWidening(TypeFlag::WIDENABLE_TO_FLOAT); + break; + } + case TypeFlag::DOUBLE: { + ApplyWidening(TypeFlag::WIDENABLE_TO_DOUBLE); + break; + } + default: { + break; + } + } + } + + void ApplyGlobalWidening() + { + switch (ETSChecker::ETSChecker::ETSType(target_)) { + case TypeFlag::SHORT: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_SHORT); + break; + } + case TypeFlag::INT: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_INT); + break; + } + case TypeFlag::LONG: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_LONG); + break; + } + case TypeFlag::FLOAT: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_FLOAT); + break; + } + case TypeFlag::DOUBLE: { + ApplyGlobalWidening(TypeFlag::WIDENABLE_TO_DOUBLE); + break; + } + default: { + break; + } + } + } + + void ApplyGlobalWidening(TypeFlag flag) + { + if (!source_->HasTypeFlag(flag)) { + return; + } + + switch (ETSChecker::ETSChecker::ETSType(source_)) { + case TypeFlag::BYTE: { + relation_->GetNode()->SetTsType(checker_->GlobalByteType()); + break; + } + case TypeFlag::SHORT: { + relation_->GetNode()->SetTsType(checker_->GlobalShortType()); + break; + } + case TypeFlag::INT: { + relation_->GetNode()->SetTsType(checker_->GlobalIntType()); + break; + } + case TypeFlag::LONG: { + relation_->GetNode()->SetTsType(checker_->GlobalLongType()); + break; + } + case TypeFlag::FLOAT: { + relation_->GetNode()->SetTsType(checker_->GlobalFloatType()); + break; + } + case TypeFlag::DOUBLE: { + relation_->GetNode()->SetTsType(checker_->GlobalDoubleType()); + break; + } + default: { + return; + } + } + + relation_->Result(true); + } + + template + void ApplyWidening(TypeFlag flag) + { + if (!source_->HasTypeFlag(flag)) { + return; + } + + switch (ETSChecker::ETSChecker::ETSType(source_)) { + case TypeFlag::BYTE: { + ApplyWidening(); + break; + } + case TypeFlag::CHAR: { + ApplyWidening(); + break; + } + case TypeFlag::SHORT: { + ApplyWidening(); + break; + } + case TypeFlag::INT: { + ApplyWidening(); + break; + } + case TypeFlag::LONG: { + ApplyWidening(); + break; + } + case TypeFlag::FLOAT: { + ApplyWidening(); + break; + } + case TypeFlag::DOUBLE: { + ApplyWidening(); + break; + } + default: { + return; + } + } + relation_->Result(true); + } + + template + void ApplyWidening() + { + using SType = typename SourceType::UType; + using TType = typename TargetType::UType; + SType value = reinterpret_cast(source_)->GetValue(); + + relation_->GetNode()->SetTsType(checker_->Allocator()->New(static_cast(value))); + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/typescript/core/binaryLikeExpression.cpp b/checker/ts/binaryLikeExpression.cpp similarity index 85% rename from typescript/core/binaryLikeExpression.cpp rename to checker/ts/binaryLikeExpression.cpp index b5009ff7be83e169c50f1d84f2426b7f94052da0..425a391e035da95db6338f46ed7389411f1e918a 100644 --- a/typescript/core/binaryLikeExpression.cpp +++ b/checker/ts/binaryLikeExpression.cpp @@ -16,11 +16,11 @@ #include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -Type *Checker::CheckBinaryOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op) +Type *TSChecker::CheckBinaryOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, + ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) { CheckNonNullType(leftType, leftExpr->Start()); CheckNonNullType(rightType, rightExpr->Start()); @@ -90,8 +90,8 @@ Type *Checker::CheckBinaryOperator(Type *leftType, Type *rightType, const ir::Ex return resultType; } -Type *Checker::CheckPlusOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op) +Type *TSChecker::CheckPlusOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr, lexer::TokenType op) { if (!leftType->HasTypeFlag(TypeFlag::STRING_LIKE) && !rightType->HasTypeFlag(TypeFlag::STRING_LIKE)) { CheckNonNullType(leftType, leftExpr->Start()); @@ -122,8 +122,8 @@ Type *Checker::CheckPlusOperator(Type *leftType, Type *rightType, const ir::Expr return resultType; } -Type *Checker::CheckCompareOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr, lexer::TokenType op) +Type *TSChecker::CheckCompareOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr, + ir::Expression *rightExpr, ir::AstNode *expr, lexer::TokenType op) { CheckNonNullType(leftType, leftExpr->Start()); CheckNonNullType(rightType, rightExpr->Start()); @@ -138,7 +138,7 @@ Type *Checker::CheckCompareOperator(Type *leftType, Type *rightType, const ir::E return GlobalAnyType(); } -Type *Checker::CheckAndOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr) +Type *TSChecker::CheckAndOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr) { CheckTruthinessOfType(leftType, leftExpr->Start()); @@ -150,7 +150,7 @@ Type *Checker::CheckAndOperator(Type *leftType, Type *rightType, const ir::Expre return leftType; } -Type *Checker::CheckOrOperator(Type *leftType, Type *rightType, const ir::Expression *leftExpr) +Type *TSChecker::CheckOrOperator(Type *leftType, Type *rightType, ir::Expression *leftExpr) { CheckTruthinessOfType(leftType, leftExpr->Start()); @@ -169,8 +169,8 @@ static bool TypeHasCallOrConstructSignatures(Type *type) (!type->AsObjectType()->CallSignatures().empty() || !type->AsObjectType()->ConstructSignatures().empty()); } -Type *Checker::CheckInstanceofExpression(Type *leftType, Type *rightType, const ir::Expression *rightExpr, - const ir::AstNode *expr) +Type *TSChecker::CheckInstanceofExpression(Type *leftType, Type *rightType, ir::Expression *rightExpr, + ir::AstNode *expr) { if (leftType->TypeFlags() != TypeFlag::ANY && IsAllTypesAssignableTo(leftType, GlobalPrimitiveType())) { ThrowTypeError({"The left-hand side of an 'instanceof' expression must be of type 'any',", @@ -188,8 +188,8 @@ Type *Checker::CheckInstanceofExpression(Type *leftType, Type *rightType, const return GlobalBooleanType(); } -Type *Checker::CheckInExpression(Type *leftType, Type *rightType, const ir::Expression *leftExpr, - const ir::Expression *rightExpr, const ir::AstNode *expr) +Type *TSChecker::CheckInExpression(Type *leftType, Type *rightType, ir::Expression *leftExpr, ir::Expression *rightExpr, + ir::AstNode *expr) { CheckNonNullType(leftType, leftExpr->Start()); CheckNonNullType(rightType, rightExpr->Start()); @@ -209,8 +209,7 @@ Type *Checker::CheckInExpression(Type *leftType, Type *rightType, const ir::Expr return GlobalBooleanType(); } -void Checker::CheckAssignmentOperator(lexer::TokenType op, const ir::Expression *leftExpr, Type *leftType, - Type *valueType) +void TSChecker::CheckAssignmentOperator(lexer::TokenType op, ir::Expression *leftExpr, Type *leftType, Type *valueType) { if (IsAssignmentOperator(op)) { CheckReferenceExpression( diff --git a/typescript/core/destructuringContext.cpp b/checker/ts/destructuringContext.cpp similarity index 95% rename from typescript/core/destructuringContext.cpp rename to checker/ts/destructuringContext.cpp index 046ff5f385ee23a1b45348b40c9ba22b64c7a494..8dd3b23dcf768c7fe1b42904ec90525beee82785 100644 --- a/typescript/core/destructuringContext.cpp +++ b/checker/ts/destructuringContext.cpp @@ -27,12 +27,12 @@ #include "plugins/ecmascript/es2panda/ir/expression.h" namespace panda::es2panda::checker { -void DestructuringContext::Prepare(const ir::Expression *typeAnnotation, const ir::Expression *initializer, +void DestructuringContext::Prepare(ir::TypeNode *typeAnnotation, ir::Expression *initializer, const lexer::SourcePosition &loc) { if (typeAnnotation != nullptr) { typeAnnotation->Check(checker_); - Type *annotationType = typeAnnotation->AsTypeNode()->GetType(checker_); + Type *annotationType = typeAnnotation->GetType(checker_); if (initializer != nullptr) { checker_->ElaborateElementwise(annotationType, initializer, loc); @@ -52,8 +52,7 @@ void DestructuringContext::Prepare(const ir::Expression *typeAnnotation, const i } } -void DestructuringContext::HandleDestructuringAssignment(const ir::Identifier *ident, Type *inferedType, - Type *defaultType) +void DestructuringContext::HandleDestructuringAssignment(ir::Identifier *ident, Type *inferedType, Type *defaultType) { if (ident->Variable() == nullptr) { checker_->ThrowTypeError({"Cannot find name '", ident->Name(), "'."}, ident->Start()); @@ -96,7 +95,7 @@ void DestructuringContext::SetInferedTypeForVariable(binder::Variable *var, Type var->SetTsType(inferedType); } -void DestructuringContext::ValidateObjectLiteralType(ObjectType *obj_type, const ir::ObjectExpression *obj_pattern) +void DestructuringContext::ValidateObjectLiteralType(ObjectType *obj_type, ir::ObjectExpression *obj_pattern) { for (const auto *sourceProp : obj_type->Properties()) { const util::StringView &sourceName = sourceProp->Name(); @@ -124,7 +123,7 @@ void DestructuringContext::ValidateObjectLiteralType(ObjectType *obj_type, const } } -void DestructuringContext::HandleAssignmentPattern(const ir::AssignmentExpression *assignmentPattern, Type *inferedType, +void DestructuringContext::HandleAssignmentPattern(ir::AssignmentExpression *assignmentPattern, Type *inferedType, bool validateDefault) { if (!assignmentPattern->Left()->IsArrayPattern()) { @@ -368,7 +367,7 @@ Type *ArrayDestructuringContext::GetRestType([[maybe_unused]] const lexer::Sourc return checker_->CreateUnionType(std::move(tupleUnion)); } -void ArrayDestructuringContext::HandleRest(const ir::SpreadElement *rest) +void ArrayDestructuringContext::HandleRest(ir::SpreadElement *rest) { Type *inferedRestType = GetRestType(rest->Start()); @@ -397,7 +396,7 @@ void ArrayDestructuringContext::HandleRest(const ir::SpreadElement *rest) nextContext.Start(); } -Type *ArrayDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) +Type *ArrayDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) { if (!convertTupleToArray_) { return type; @@ -419,7 +418,7 @@ Type *ArrayDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const ir return type; } -static void SetParameterType(const ir::AstNode *parent, Type *type) +static void SetParameterType(ir::AstNode *parent, Type *type) { parent->Iterate([type](ir::AstNode *childNode) -> void { if (childNode->IsIdentifier() && childNode->AsIdentifier()->Variable() != nullptr) { @@ -434,7 +433,7 @@ static void SetParameterType(const ir::AstNode *parent, Type *type) void ArrayDestructuringContext::SetRemainingPatameterTypes() { do { - const auto *it = id_->AsArrayPattern()->Elements()[index_]; + auto *it = id_->AsArrayPattern()->Elements()[index_]; ASSERT(it); SetParameterType(it, checker_->GlobalAnyType()); } while (++index_ != id_->AsArrayPattern()->Elements().size()); @@ -448,7 +447,7 @@ void ArrayDestructuringContext::Start() util::StringView name = util::Helpers::ToStringView(checker_->Allocator(), 0); - for (const auto *it : id_->AsArrayPattern()->Elements()) { + for (auto *it : id_->AsArrayPattern()->Elements()) { if (it->IsRestElement()) { HandleRest(it->AsRestElement()); break; @@ -521,7 +520,7 @@ void ObjectDestructuringContext::ValidateInferedType() ValidateObjectLiteralType(inferedType_->AsObjectType(), id_->AsObjectPattern()); } -void ObjectDestructuringContext::HandleRest(const ir::SpreadElement *rest) +void ObjectDestructuringContext::HandleRest(ir::SpreadElement *rest) { Type *inferedRestType = GetRestType(rest->Start()); ASSERT(rest->Argument()->IsIdentifier()); @@ -577,7 +576,7 @@ Type *ObjectDestructuringContext::GetRestType([[maybe_unused]] const lexer::Sour checker_->ThrowTypeError("Rest types may only be created from object types.", loc); } -Type *ObjectDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) +Type *ObjectDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) { if (!convertTupleToArray_) { return type; @@ -589,7 +588,7 @@ Type *ObjectDestructuringContext::ConvertTupleTypeToArrayTypeIfNecessary(const i ASSERT(node->IsProperty()); - const ir::Property *property = node->AsProperty(); + ir::Property *property = node->AsProperty(); if (property->Value()->IsArrayPattern()) { return type; @@ -641,10 +640,10 @@ void ObjectDestructuringContext::Start() ValidateInferedType(); } - for (const auto *it : id_->AsObjectPattern()->Properties()) { + for (auto *it : id_->AsObjectPattern()->Properties()) { switch (it->Type()) { case ir::AstNodeType::PROPERTY: { - const ir::Property *property = it->AsProperty(); + ir::Property *property = it->AsProperty(); if (property->IsComputed()) { // TODO(aszilagyi) diff --git a/typescript/core/destructuringContext.h b/checker/ts/destructuringContext.h similarity index 64% rename from typescript/core/destructuringContext.h rename to checker/ts/destructuringContext.h index 5e0619773450a483e70909c195730af04b5f17b1..2f649e8595b3ca2b686fe5d6c0c7a1d01be5c17a 100644 --- a/typescript/core/destructuringContext.h +++ b/checker/ts/destructuringContext.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_TYPESCIRPT_CORE_DESTRUCTURING_CONTEXT_H -#define ES2PANDA_TYPESCIRPT_CORE_DESTRUCTURING_CONTEXT_H +#ifndef ES2PANDA_CHECKER_TS_DESTRUCTURING_CONTEXT_H +#define ES2PANDA_CHECKER_TS_DESTRUCTURING_CONTEXT_H -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" #include "plugins/ecmascript/es2panda/ir/expression.h" #include @@ -31,8 +31,8 @@ class Type; class DestructuringContext { public: - DestructuringContext(Checker *checker, const ir::Expression *id, bool inAssignment, bool convertTupleToArray, - const ir::Expression *typeAnnotation, const ir::Expression *initializer) + DestructuringContext(TSChecker *checker, ir::Expression *id, bool inAssignment, bool convertTupleToArray, + ir::TypeNode *typeAnnotation, ir::Expression *initializer) : checker_(checker), id_(id), inAssignment_(inAssignment), convertTupleToArray_(convertTupleToArray) { Prepare(typeAnnotation, initializer, id->Start()); @@ -53,13 +53,11 @@ public: return inferedType_; } - void ValidateObjectLiteralType(ObjectType *obj_type, const ir::ObjectExpression *obj_pattern); - void HandleDestructuringAssignment(const ir::Identifier *ident, Type *inferedType, Type *defaultType); - void HandleAssignmentPattern(const ir::AssignmentExpression *assignmentPattern, Type *inferedType, - bool validateDefault); + void ValidateObjectLiteralType(ObjectType *obj_type, ir::ObjectExpression *obj_pattern); + void HandleDestructuringAssignment(ir::Identifier *ident, Type *inferedType, Type *defaultType); + void HandleAssignmentPattern(ir::AssignmentExpression *assignmentPattern, Type *inferedType, bool validateDefault); void SetInferedTypeForVariable(binder::Variable *var, Type *inferedType, const lexer::SourcePosition &loc); - void Prepare(const ir::Expression *typeAnnotation, const ir::Expression *initializer, - const lexer::SourcePosition &loc); + void Prepare(ir::TypeNode *typeAnnotation, ir::Expression *initializer, const lexer::SourcePosition &loc); DEFAULT_COPY_SEMANTIC(DestructuringContext); DEFAULT_MOVE_SEMANTIC(DestructuringContext); @@ -68,14 +66,14 @@ public: virtual void Start() = 0; virtual void ValidateInferedType() = 0; virtual Type *NextInferedType([[maybe_unused]] const util::StringView &searchName, bool throwError) = 0; - virtual void HandleRest(const ir::SpreadElement *rest) = 0; + virtual void HandleRest(ir::SpreadElement *rest) = 0; virtual Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) = 0; - virtual Type *ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) = 0; + virtual Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) = 0; protected: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - Checker *checker_; - const ir::Expression *id_; + TSChecker *checker_; + ir::Expression *id_; bool inAssignment_; bool convertTupleToArray_; Type *inferedType_ {}; @@ -87,8 +85,8 @@ protected: class ArrayDestructuringContext : public DestructuringContext { public: - ArrayDestructuringContext(Checker *checker, const ir::Expression *id, bool inAssignment, bool convertTupleToArray, - const ir::Expression *typeAnnotation, const ir::Expression *initializer) + ArrayDestructuringContext(TSChecker *checker, ir::Expression *id, bool inAssignment, bool convertTupleToArray, + ir::TypeNode *typeAnnotation, ir::Expression *initializer) : DestructuringContext(checker, id, inAssignment, convertTupleToArray, typeAnnotation, initializer) { } @@ -101,9 +99,9 @@ public: void Start() override; void ValidateInferedType() override; Type *NextInferedType([[maybe_unused]] const util::StringView &searchName, bool throwError) override; - void HandleRest(const ir::SpreadElement *rest) override; + void HandleRest(ir::SpreadElement *rest) override; Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) override; - Type *ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) override; + Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) override; private: uint32_t index_ {0}; @@ -111,8 +109,8 @@ private: class ObjectDestructuringContext : public DestructuringContext { public: - ObjectDestructuringContext(Checker *checker, const ir::Expression *id, bool inAssignment, bool convertTupleToArray, - const ir::Expression *typeAnnotation, const ir::Expression *initializer) + ObjectDestructuringContext(TSChecker *checker, ir::Expression *id, bool inAssignment, bool convertTupleToArray, + ir::TypeNode *typeAnnotation, ir::Expression *initializer) : DestructuringContext(checker, id, inAssignment, convertTupleToArray, typeAnnotation, initializer) { } @@ -122,9 +120,9 @@ public: void Start() override; void ValidateInferedType() override; Type *NextInferedType([[maybe_unused]] const util::StringView &searchName, bool throwError) override; - void HandleRest(const ir::SpreadElement *rest) override; + void HandleRest(ir::SpreadElement *rest) override; Type *GetRestType([[maybe_unused]] const lexer::SourcePosition &loc) override; - Type *ConvertTupleTypeToArrayTypeIfNecessary(const ir::AstNode *node, Type *type) override; + Type *ConvertTupleTypeToArrayTypeIfNecessary(ir::AstNode *node, Type *type) override; }; } // namespace panda::es2panda::checker diff --git a/typescript/core/function.cpp b/checker/ts/function.cpp similarity index 76% rename from typescript/core/function.cpp rename to checker/ts/function.cpp index 479384a3ff335187baef8a68017ad0b3b411d71e..8c963f5cc0771a0b6753644ae33cffc9b55b39f8 100644 --- a/typescript/core/function.cpp +++ b/checker/ts/function.cpp @@ -33,10 +33,10 @@ #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/binder/declaration.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/core/destructuringContext.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectDescriptor.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectType.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ts/destructuringContext.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectDescriptor.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectType.h" #include #include @@ -44,11 +44,11 @@ #include namespace panda::es2panda::checker { -Type *Checker::HandleFunctionReturn(const ir::ScriptFunction *func) +Type *TSChecker::HandleFunctionReturn(ir::ScriptFunction *func) { if (func->ReturnTypeAnnotation() != nullptr) { func->ReturnTypeAnnotation()->Check(this); - Type *returnType = func->ReturnTypeAnnotation()->AsTypeNode()->GetType(this); + Type *returnType = func->ReturnTypeAnnotation()->GetType(this); if (func->IsArrow() && func->Body()->IsExpression()) { ElaborateElementwise(returnType, func->Body()->AsExpression(), func->Body()->Start()); @@ -76,7 +76,7 @@ Type *Checker::HandleFunctionReturn(const ir::ScriptFunction *func) return func->Body()->Check(this); } - ArenaVector returnTypes(allocator_->Adapter()); + ArenaVector returnTypes(allocator_.Adapter()); CollectTypesFromReturnStatements(func->Body(), &returnTypes); if (returnTypes.empty()) { @@ -96,7 +96,7 @@ Type *Checker::HandleFunctionReturn(const ir::ScriptFunction *func) return CreateUnionType(std::move(returnTypes)); } -void Checker::ThrowReturnTypeCircularityError(const ir::ScriptFunction *func) +void TSChecker::ThrowReturnTypeCircularityError(ir::ScriptFunction *func) { if (func->ReturnTypeAnnotation() != nullptr) { ThrowTypeError("Return type annotation circularly reference itself", func->ReturnTypeAnnotation()->Start()); @@ -115,8 +115,8 @@ void Checker::ThrowReturnTypeCircularityError(const ir::ScriptFunction *func) func->Start()); } -std::tuple Checker::CheckFunctionIdentifierParameter( - const ir::Identifier *param) +std::tuple TSChecker::CheckFunctionIdentifierParameter( + ir::Identifier *param) { ASSERT(param->Variable()); binder::Variable *param_var = param->Variable(); @@ -131,11 +131,11 @@ std::tuple Checker::Chec } param->TypeAnnotation()->Check(this); - param_var->SetTsType(param->TypeAnnotation()->AsTypeNode()->GetType(this)); + param_var->SetTsType(param->TypeAnnotation()->GetType(this)); return {param_var->AsLocalVariable(), nullptr, is_optional}; } -Type *Checker::CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpression *arrayPattern, Type *inferedType) +Type *TSChecker::CreateParameterTypeForArrayAssignmentPattern(ir::ArrayExpression *arrayPattern, Type *inferedType) { if (!inferedType->IsObjectType()) { return inferedType; @@ -148,12 +148,13 @@ Type *Checker::CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpre return inferedType; } - TupleType *newTuple = inferedTuple->Instantiate(allocator_, relation_, globalTypes_)->AsObjectType()->AsTupleType(); + TupleType *newTuple = + inferedTuple->Instantiate(&allocator_, relation_, globalTypes_)->AsObjectType()->AsTupleType(); for (uint32_t index = inferedTuple->FixedLength(); index < arrayPattern->Elements().size(); index++) { - util::StringView memberIndex = util::Helpers::ToStringView(allocator_, index); + util::StringView memberIndex = util::Helpers::ToStringView(&allocator_, index); binder::LocalVariable *newMember = binder::Scope::CreateVar( - allocator_, memberIndex, binder::VariableFlags::PROPERTY | binder::VariableFlags::OPTIONAL, nullptr); + &allocator_, memberIndex, binder::VariableFlags::PROPERTY | binder::VariableFlags::OPTIONAL, nullptr); newMember->SetTsType(GlobalAnyType()); newTuple->AddProperty(newMember); } @@ -161,21 +162,20 @@ Type *Checker::CreateParameterTypeForArrayAssignmentPattern(const ir::ArrayExpre return newTuple; } -Type *Checker::CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExpression *objectPattern, - Type *inferedType) +Type *TSChecker::CreateParameterTypeForObjectAssignmentPattern(ir::ObjectExpression *objectPattern, Type *inferedType) { if (!inferedType->IsObjectType()) { return inferedType; } - ObjectType *newObject = inferedType->Instantiate(allocator_, relation_, globalTypes_)->AsObjectType(); + ObjectType *newObject = inferedType->Instantiate(&allocator_, relation_, globalTypes_)->AsObjectType(); - for (const auto *it : objectPattern->Properties()) { + for (auto *it : objectPattern->Properties()) { if (it->IsRestElement()) { continue; } - const ir::Property *prop = it->AsProperty(); + ir::Property *prop = it->AsProperty(); binder::LocalVariable *foundVar = newObject->GetProperty(prop->Key()->AsIdentifier()->Name(), true); if (foundVar != nullptr) { @@ -187,10 +187,10 @@ Type *Checker::CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExp } ASSERT(prop->Value()->IsAssignmentPattern()); - const ir::AssignmentExpression *assignmentPattern = prop->Value()->AsAssignmentPattern(); + ir::AssignmentExpression *assignmentPattern = prop->Value()->AsAssignmentPattern(); binder::LocalVariable *newProp = - binder::Scope::CreateVar(allocator_, prop->Key()->AsIdentifier()->Name(), + binder::Scope::CreateVar(&allocator_, prop->Key()->AsIdentifier()->Name(), binder::VariableFlags::PROPERTY | binder::VariableFlags::OPTIONAL, nullptr); newProp->SetTsType(GetBaseTypeOfLiteralType(CheckTypeCached(assignmentPattern->Right()))); newObject->AddProperty(newProp); @@ -200,17 +200,17 @@ Type *Checker::CreateParameterTypeForObjectAssignmentPattern(const ir::ObjectExp return newObject; } -std::tuple Checker::CheckFunctionAssignmentPatternParameter( - const ir::AssignmentExpression *param) +std::tuple TSChecker::CheckFunctionAssignmentPatternParameter( + ir::AssignmentExpression *param) { if (param->Left()->IsIdentifier()) { - const ir::Identifier *paramIdent = param->Left()->AsIdentifier(); + ir::Identifier *paramIdent = param->Left()->AsIdentifier(); binder::Variable *paramVar = paramIdent->Variable(); ASSERT(paramVar); if (paramIdent->TypeAnnotation() != nullptr) { paramIdent->TypeAnnotation()->Check(this); - Type *paramType = paramIdent->TypeAnnotation()->AsTypeNode()->GetType(this); + Type *paramType = paramIdent->TypeAnnotation()->GetType(this); paramVar->SetTsType(paramType); ElaborateElementwise(paramType, param->Right(), paramIdent->Start()); return {paramVar->AsLocalVariable(), nullptr, true}; @@ -227,14 +227,14 @@ std::tuple Checker::Chec auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE | CheckerStatus::IN_PARAMETER); if (param->Left()->IsArrayPattern()) { - const ir::ArrayExpression *arrayPattern = param->Left()->AsArrayPattern(); + ir::ArrayExpression *arrayPattern = param->Left()->AsArrayPattern(); auto context = ArrayDestructuringContext(this, arrayPattern, false, true, arrayPattern->TypeAnnotation(), param->Right()); context.Start(); paramType = CreateParameterTypeForArrayAssignmentPattern(arrayPattern, context.InferedType()); CreatePatternParameterName(param->Left(), ss); } else { - const ir::ObjectExpression *objectPattern = param->Left()->AsObjectPattern(); + ir::ObjectExpression *objectPattern = param->Left()->AsObjectPattern(); auto context = ObjectDestructuringContext(this, objectPattern, false, true, objectPattern->TypeAnnotation(), param->Right()); context.Start(); @@ -242,41 +242,27 @@ std::tuple Checker::Chec CreatePatternParameterName(param->Left(), ss); } - util::UString pn(ss.str(), allocator_); + util::UString pn(ss.str(), &allocator_); binder::LocalVariable *patternVar = - binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param); + binder::Scope::CreateVar(&allocator_, pn.View(), binder::VariableFlags::NONE, param); patternVar->SetTsType(paramType); patternVar->AddFlag(binder::VariableFlags::OPTIONAL); return {patternVar->AsLocalVariable(), nullptr, true}; } -std::tuple Checker::CheckFunctionRestParameter( - const ir::SpreadElement *param, SignatureInfo *signatureInfo) +std::tuple TSChecker::CheckFunctionRestParameter( + ir::SpreadElement *param, SignatureInfo *signatureInfo) { - const ir::Expression *typeAnnotation = nullptr; - switch (param->Argument()->Type()) { - case ir::AstNodeType::IDENTIFIER: { - typeAnnotation = param->Argument()->AsIdentifier()->TypeAnnotation(); - break; - } - case ir::AstNodeType::OBJECT_PATTERN: { - typeAnnotation = param->Argument()->AsArrayPattern()->TypeAnnotation(); - break; - } - case ir::AstNodeType::ARRAY_PATTERN: { - typeAnnotation = param->Argument()->AsObjectPattern()->TypeAnnotation(); - break; - } - default: { - UNREACHABLE(); - } + ir::TypeNode *typeAnnotation = nullptr; + if (param->Argument()) { + typeAnnotation = param->Argument()->AsAnnotatedExpression()->TypeAnnotation(); } - Type *restType = allocator_->New(GlobalAnyType()); + Type *restType = allocator_.New(GlobalAnyType()); if (typeAnnotation != nullptr) { typeAnnotation->Check(this); - restType = typeAnnotation->AsTypeNode()->GetType(this); + restType = typeAnnotation->GetType(this); if (!restType->IsArrayType()) { ThrowTypeError("A rest parameter must be of an array type", param->Start()); } @@ -284,7 +270,7 @@ std::tuple Checker::Chec switch (param->Argument()->Type()) { case ir::AstNodeType::IDENTIFIER: { - const ir::Identifier *restIdent = param->Argument()->AsIdentifier(); + ir::Identifier *restIdent = param->Argument()->AsIdentifier(); ASSERT(restIdent->Variable()); restIdent->Variable()->SetTsType(restType->AsArrayType()->ElementType()); return {nullptr, restIdent->Variable()->AsLocalVariable(), false}; @@ -314,14 +300,14 @@ std::tuple Checker::Chec } } -std::tuple Checker::CheckFunctionArrayPatternParameter( - const ir::ArrayExpression *param) +std::tuple TSChecker::CheckFunctionArrayPatternParameter( + ir::ArrayExpression *param) { std::stringstream ss; CreatePatternParameterName(param, ss); - util::UString pn(ss.str(), allocator_); + util::UString pn(ss.str(), &allocator_); binder::LocalVariable *patternVar = - binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param); + binder::Scope::CreateVar(&allocator_, pn.View(), binder::VariableFlags::NONE, param); if (param->TypeAnnotation() != nullptr) { auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE); @@ -336,14 +322,14 @@ std::tuple Checker::Chec return {patternVar->AsLocalVariable(), nullptr, false}; } -std::tuple Checker::CheckFunctionObjectPatternParameter( - const ir::ObjectExpression *param) +std::tuple TSChecker::CheckFunctionObjectPatternParameter( + ir::ObjectExpression *param) { std::stringstream ss; CreatePatternParameterName(param, ss); - util::UString pn(ss.str(), allocator_); + util::UString pn(ss.str(), &allocator_); binder::LocalVariable *patternVar = - binder::Scope::CreateVar(allocator_, pn.View(), binder::VariableFlags::NONE, param); + binder::Scope::CreateVar(&allocator_, pn.View(), binder::VariableFlags::NONE, param); if (param->TypeAnnotation() != nullptr) { auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE); @@ -358,13 +344,12 @@ std::tuple Checker::Chec return {patternVar->AsLocalVariable(), nullptr, false}; } -std::tuple Checker::CheckFunctionParameter( - const ir::Expression *param, SignatureInfo *signatureInfo) +std::tuple TSChecker::CheckFunctionParameter( + ir::Expression *param, SignatureInfo *signatureInfo) { - auto found = nodeCache_.find(param); - if (found != nodeCache_.end()) { - ASSERT(found->second->Variable()); - binder::Variable *var = found->second->Variable(); + if (param->TsType()) { + ASSERT(param->TsType()->Variable()); + binder::Variable *var = param->TsType()->Variable(); return {var->AsLocalVariable(), nullptr, var->HasFlag(binder::VariableFlags::OPTIONAL)}; } @@ -399,16 +384,16 @@ std::tuple Checker::Chec } if (cache) { - Type *placeholder = allocator_->New(GlobalAnyType()); + Type *placeholder = allocator_.New(GlobalAnyType()); placeholder->SetVariable(std::get<0>(result)); - nodeCache_.insert({param, placeholder}); + param->SetTsType(placeholder); } return result; } -void Checker::CheckFunctionParameterDeclarations(const ArenaVector ¶ms, - SignatureInfo *signatureInfo) +void TSChecker::CheckFunctionParameterDeclarations(const ArenaVector ¶ms, + SignatureInfo *signatureInfo) { signatureInfo->restVar = nullptr; signatureInfo->minArgCount = 0; @@ -433,14 +418,14 @@ void Checker::CheckFunctionParameterDeclarations(const ArenaVectorIsArrayPattern() || prop_value->IsObjectPattern() || (prop_value->IsAssignmentPattern() && (prop_value->AsAssignmentPattern()->Left()->IsArrayPattern() || prop_value->AsAssignmentPattern()->Left()->IsObjectPattern())); } -void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstream &ss) +void TSChecker::CreatePatternParameterName(ir::AstNode *node, std::stringstream &ss) { switch (node->Type()) { case ir::AstNodeType::IDENTIFIER: { @@ -480,7 +465,7 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr break; } case ir::AstNodeType::PROPERTY: { - const ir::Property *prop = node->AsProperty(); + ir::Property *prop = node->AsProperty(); util::StringView propName; if (prop->Key()->IsIdentifier()) { @@ -488,7 +473,8 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr } else { switch (prop->Key()->Type()) { case ir::AstNodeType::NUMBER_LITERAL: { - propName = util::Helpers::ToStringView(allocator_, prop->Key()->AsNumberLiteral()->Number()); + propName = util::Helpers::ToStringView(&allocator_, + prop->Key()->AsNumberLiteral()->Number().GetDouble()); break; } case ir::AstNodeType::BIGINT_LITERAL: { @@ -510,14 +496,14 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr if (ShouldCreatePropertyValueName(prop->Value())) { ss << ": "; - Checker::CreatePatternParameterName(prop->Value(), ss); + TSChecker::CreatePatternParameterName(prop->Value(), ss); } break; } case ir::AstNodeType::REST_ELEMENT: { ss << "..."; - Checker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss); + TSChecker::CreatePatternParameterName(node->AsRestElement()->Argument(), ss); break; } default: @@ -525,7 +511,7 @@ void Checker::CreatePatternParameterName(const ir::AstNode *node, std::stringstr } } -const ir::Statement *FindSubsequentFunctionNode(const ir::BlockStatement *block, const ir::ScriptFunction *node) +ir::Statement *FindSubsequentFunctionNode(ir::BlockStatement *block, ir::ScriptFunction *node) { for (auto it = block->Statements().begin(); it != block->Statements().end(); it++) { if ((*it)->IsFunctionDeclaration() && (*it)->AsFunctionDeclaration()->Function() == node) { @@ -537,22 +523,21 @@ const ir::Statement *FindSubsequentFunctionNode(const ir::BlockStatement *block, return nullptr; } -void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar) +void TSChecker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, binder::Variable *funcVar) { - const ir::ScriptFunction *bodyDeclaration = decl->Decls().back(); + ir::ScriptFunction *bodyDeclaration = decl->Decls().back(); if (bodyDeclaration->IsOverload()) { ThrowTypeError("Function implementation is missing or not immediately following the declaration.", bodyDeclaration->Id()->Start()); } - ObjectDescriptor *descWithOverload = allocator_->New(allocator_); + ObjectDescriptor *descWithOverload = allocator_.New(&allocator_); for (auto it = decl->Decls().begin(); it != decl->Decls().end() - 1; it++) { - const ir::ScriptFunction *func = *it; + ir::ScriptFunction *func = *it; ASSERT(func->IsOverload() && (*it)->Parent()->Parent()->IsBlockStatement()); - const ir::Statement *subsequentNode = - FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func); + ir::Statement *subsequentNode = FindSubsequentFunctionNode((*it)->Parent()->Parent()->AsBlockStatement(), func); ASSERT(subsequentNode); if (!subsequentNode->IsFunctionDeclaration()) { @@ -560,7 +545,7 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin func->Id()->Start()); } - const ir::ScriptFunction *subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function(); + ir::ScriptFunction *subsequentFunc = subsequentNode->AsFunctionDeclaration()->Function(); if (subsequentFunc->Id()->Name() != func->Id()->Name()) { ThrowTypeError("Function implementation is missing or not immediately following the declaration.", @@ -573,26 +558,25 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin ScopeContext scopeCtx(this, func->Scope()); - auto *overloadSignatureInfo = allocator_->New(allocator_); + auto *overloadSignatureInfo = allocator_.New(&allocator_); CheckFunctionParameterDeclarations(func->Params(), overloadSignatureInfo); Type *returnType = GlobalAnyType(); if (func->ReturnTypeAnnotation() != nullptr) { func->ReturnTypeAnnotation()->Check(this); - returnType = func->ReturnTypeAnnotation()->AsTypeNode()->GetType(this); + returnType = func->ReturnTypeAnnotation()->GetType(this); } - Signature *overloadSignature = allocator_->New(overloadSignatureInfo, returnType); - overloadSignature->SetNode(func); + Signature *overloadSignature = allocator_.New(overloadSignatureInfo, returnType, func); descWithOverload->callSignatures.push_back(overloadSignature); } ScopeContext scopeCtx(this, bodyDeclaration->Scope()); - auto *signatureInfo = allocator_->New(allocator_); + auto *signatureInfo = allocator_.New(&allocator_); CheckFunctionParameterDeclarations(bodyDeclaration->Params(), signatureInfo); - auto *bodyCallSignature = allocator_->New(signatureInfo, GlobalResolvingReturnType()); + auto *bodyCallSignature = allocator_.New(signatureInfo, GlobalResolvingReturnType()); if (descWithOverload->callSignatures.empty()) { Type *funcType = CreateFunctionTypeWithSignature(bodyCallSignature); @@ -603,7 +587,7 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin bodyCallSignature->SetReturnType(HandleFunctionReturn(bodyDeclaration)); if (!descWithOverload->callSignatures.empty()) { - Type *funcType = allocator_->New(descWithOverload); + Type *funcType = allocator_.New(descWithOverload); funcType->SetVariable(funcVar); funcVar->SetTsType(funcType); @@ -618,14 +602,14 @@ void Checker::InferFunctionDeclarationType(const binder::FunctionDecl *decl, bin } } - ASSERT(iter->Node() && iter->Node()->IsScriptFunction()); + ASSERT(iter->Function()); ThrowTypeError("This overload signature is not compatible with its implementation signature", - iter->Node()->AsScriptFunction()->Id()->Start()); + iter->Function()->Id()->Start()); } } } -void Checker::CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaVector *returnTypes) +void TSChecker::CollectTypesFromReturnStatements(ir::AstNode *parent, ArenaVector *returnTypes) { parent->Iterate([this, returnTypes](ir::AstNode *childNode) -> void { if (childNode->IsScriptFunction()) { @@ -647,11 +631,11 @@ void Checker::CollectTypesFromReturnStatements(const ir::AstNode *parent, ArenaV }); } -static bool SearchForReturnOrThrow(const ir::AstNode *parent) +static bool SearchForReturnOrThrow(ir::AstNode *parent) { bool found = false; - parent->Iterate([&found](const ir::AstNode *childNode) -> void { + parent->Iterate([&found](ir::AstNode *childNode) -> void { if (childNode->IsThrowStatement() || childNode->IsReturnStatement()) { found = true; return; @@ -667,8 +651,8 @@ static bool SearchForReturnOrThrow(const ir::AstNode *parent) return found; } -void Checker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFunction *func, - lexer::SourcePosition lineInfo, const char *errMsg) +void TSChecker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(ir::ScriptFunction *func, + lexer::SourcePosition lineInfo, const char *errMsg) { if (!SearchForReturnOrThrow(func->Body())) { ThrowTypeError(errMsg, lineInfo); @@ -677,8 +661,9 @@ void Checker::CheckAllCodePathsInNonVoidFunctionReturnOrThrow(const ir::ScriptFu // noImplicitReturn compiler option for TypeScript we should update this function } -ArgRange Checker::GetArgRange(const ArenaVector &signatures, ArenaVector *potentialSignatures, - uint32_t callArgsSize, bool *haveSignatureWithRest) +ArgRange TSChecker::GetArgRange(const ArenaVector &signatures, + ArenaVector *potentialSignatures, uint32_t callArgsSize, + bool *haveSignatureWithRest) { uint32_t minArg = UINT32_MAX; uint32_t maxArg = 0; @@ -704,7 +689,7 @@ ArgRange Checker::GetArgRange(const ArenaVector &signatures, ArenaV return {minArg, maxArg}; } -bool Checker::CallMatchesSignature(const ArenaVector &args, Signature *signature, bool throwError) +bool TSChecker::CallMatchesSignature(const ArenaVector &args, Signature *signature, bool throwError) { for (size_t index = 0; index < args.size(); index++) { checker::Type *sigArgType = nullptr; @@ -739,14 +724,15 @@ bool Checker::CallMatchesSignature(const ArenaVector &args, Si return true; } -Type *Checker::resolveCallOrNewExpression(const ArenaVector &signatures, - ArenaVector arguments, const lexer::SourcePosition &errPos) +Type *TSChecker::resolveCallOrNewExpression(const ArenaVector &signatures, + ArenaVector arguments, + const lexer::SourcePosition &errPos) { if (signatures.empty()) { ThrowTypeError("This expression is not callable.", errPos); } - ArenaVector potentialSignatures(allocator_->Adapter()); + ArenaVector potentialSignatures(allocator_.Adapter()); bool haveSignatureWithRest = false; auto argRange = GetArgRange(signatures, &potentialSignatures, arguments.size(), &haveSignatureWithRest); diff --git a/typescript/core/helpers.cpp b/checker/ts/helpers.cpp similarity index 73% rename from typescript/core/helpers.cpp rename to checker/ts/helpers.cpp index 5d57490f28ac460d4cf79fe781e8b2d0ec60e2b2..44d3bc3a6b729ff73bdfce05ac4e34be19fa96da 100644 --- a/typescript/core/helpers.cpp +++ b/checker/ts/helpers.cpp @@ -21,26 +21,27 @@ #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/statements/variableDeclarator.h" #include "plugins/ecmascript/es2panda/ir/ts/tsQualifiedName.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsPropertySignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsPropertySignature.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeAliasDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeReference.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" -#include "plugins/ecmascript/es2panda/typescript/core/typeElaborationContext.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/ts/typeElaborationContext.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -void Checker::CheckTruthinessOfType(Type *type, lexer::SourcePosition lineInfo) +void TSChecker::CheckTruthinessOfType(Type *type, lexer::SourcePosition lineInfo) { if (type->IsVoidType()) { ThrowTypeError("An expression of type void cannot be tested for truthiness", lineInfo); } } -Type *Checker::CheckNonNullType(Type *type, lexer::SourcePosition lineInfo) +Type *TSChecker::CheckNonNullType(Type *type, lexer::SourcePosition lineInfo) { if (type->IsNullType()) { ThrowTypeError("Object is possibly 'null'.", lineInfo); @@ -53,7 +54,7 @@ Type *Checker::CheckNonNullType(Type *type, lexer::SourcePosition lineInfo) return type; } -Type *Checker::GetBaseTypeOfLiteralType(Type *type) +Type *TSChecker::GetBaseTypeOfLiteralType(Type *type) { if (HasStatus(CheckerStatus::KEEP_LITERAL_TYPE)) { return type; @@ -77,7 +78,7 @@ Type *Checker::GetBaseTypeOfLiteralType(Type *type) if (type->IsUnionType()) { auto &constituentTypes = type->AsUnionType()->ConstituentTypes(); - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); newConstituentTypes.reserve(constituentTypes.size()); for (auto *it : constituentTypes) { @@ -90,8 +91,8 @@ Type *Checker::GetBaseTypeOfLiteralType(Type *type) return type; } -void Checker::CheckReferenceExpression(const ir::Expression *expr, const char *invalidReferenceMsg, - const char *invalidOptionalChainMsg) +void TSChecker::CheckReferenceExpression(ir::Expression *expr, const char *invalidReferenceMsg, + const char *invalidOptionalChainMsg) { if (expr->IsIdentifier()) { const util::StringView &name = expr->AsIdentifier()->Name(); @@ -110,14 +111,14 @@ void Checker::CheckReferenceExpression(const ir::Expression *expr, const char *i } } -void Checker::CheckTestingKnownTruthyCallableOrAwaitableType([[maybe_unused]] const ir::Expression *condExpr, - [[maybe_unused]] Type *type, - [[maybe_unused]] const ir::AstNode *body) +void TSChecker::CheckTestingKnownTruthyCallableOrAwaitableType([[maybe_unused]] ir::Expression *condExpr, + [[maybe_unused]] Type *type, + [[maybe_unused]] ir::AstNode *body) { // TODO(aszilagyi) rework this } -Type *Checker::ExtractDefinitelyFalsyTypes(Type *type) +Type *TSChecker::ExtractDefinitelyFalsyTypes(Type *type) { if (type->IsStringType()) { return GlobalEmptyStringType(); @@ -141,7 +142,7 @@ Type *Checker::ExtractDefinitelyFalsyTypes(Type *type) if (type->IsUnionType()) { auto &constituentTypes = type->AsUnionType()->ConstituentTypes(); - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); newConstituentTypes.reserve(constituentTypes.size()); for (auto &it : constituentTypes) { @@ -154,12 +155,12 @@ Type *Checker::ExtractDefinitelyFalsyTypes(Type *type) return GlobalNeverType(); } -Type *Checker::RemoveDefinitelyFalsyTypes(Type *type) +Type *TSChecker::RemoveDefinitelyFalsyTypes(Type *type) { if ((static_cast(GetFalsyFlags(type)) & static_cast(TypeFlag::DEFINITELY_FALSY)) != 0U) { if (type->IsUnionType()) { auto &constituentTypes = type->AsUnionType()->ConstituentTypes(); - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); for (auto &it : constituentTypes) { if ((static_cast(GetFalsyFlags(it)) & static_cast(TypeFlag::DEFINITELY_FALSY)) == @@ -185,7 +186,7 @@ Type *Checker::RemoveDefinitelyFalsyTypes(Type *type) return type; } -TypeFlag Checker::GetFalsyFlags(Type *type) +TypeFlag TSChecker::GetFalsyFlags(Type *type) { if (type->IsStringLiteralType()) { return type->AsStringLiteralType()->Value().Empty() ? TypeFlag::STRING_LITERAL : TypeFlag::NONE; @@ -217,11 +218,11 @@ TypeFlag Checker::GetFalsyFlags(Type *type) return static_cast(type->TypeFlags() & TypeFlag::POSSIBLY_FALSY); } -bool Checker::IsVariableUsedInConditionBody(const ir::AstNode *parent, binder::Variable *searchVar) +bool TSChecker::IsVariableUsedInConditionBody(ir::AstNode *parent, binder::Variable *searchVar) { bool found = false; - parent->Iterate([this, searchVar, &found](const ir::AstNode *childNode) -> void { + parent->Iterate([this, searchVar, &found](ir::AstNode *childNode) -> void { binder::Variable *resultVar = nullptr; if (childNode->IsIdentifier()) { binder::ScopeFindResult result = scope_->Find(childNode->AsIdentifier()->Name()); @@ -242,11 +243,11 @@ bool Checker::IsVariableUsedInConditionBody(const ir::AstNode *parent, binder::V return found; } -bool Checker::FindVariableInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar) +bool TSChecker::FindVariableInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar) { bool found = false; - parent->Iterate([this, searchVar, &found](const ir::AstNode *childNode) -> void { + parent->Iterate([this, searchVar, &found](ir::AstNode *childNode) -> void { if (childNode->IsIdentifier()) { binder::ScopeFindResult result = scope_->Find(childNode->AsIdentifier()->Name()); ASSERT(result.variable); @@ -262,7 +263,7 @@ bool Checker::FindVariableInBinaryExpressionChain(const ir::AstNode *parent, bin return found; } -bool Checker::IsVariableUsedInBinaryExpressionChain(const ir::AstNode *parent, binder::Variable *searchVar) +bool TSChecker::IsVariableUsedInBinaryExpressionChain(ir::AstNode *parent, binder::Variable *searchVar) { while (parent->IsBinaryExpression() && parent->AsBinaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) { @@ -276,7 +277,8 @@ bool Checker::IsVariableUsedInBinaryExpressionChain(const ir::AstNode *parent, b return false; } -void Checker::ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *rightType, lexer::SourcePosition lineInfo) +void TSChecker::ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *rightType, + lexer::SourcePosition lineInfo) { if (!HasStatus(CheckerStatus::IN_CONST_CONTEXT)) { ThrowTypeError({"operator ", op, " cannot be applied to types ", leftType, " and ", AsSrc(rightType)}, @@ -286,7 +288,7 @@ void Checker::ThrowBinaryLikeError(lexer::TokenType op, Type *leftType, Type *ri ThrowTypeError({"operator ", op, " cannot be applied to types ", leftType, " and ", rightType}, lineInfo); } -void Checker::ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosition lineInfo, bool isAsSrcLeftType) +void TSChecker::ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosition lineInfo, bool isAsSrcLeftType) { if (isAsSrcLeftType || !target->HasTypeFlag(TypeFlag::LITERAL)) { ThrowTypeError({"Type '", AsSrc(source), "' is not assignable to type '", target, "'."}, lineInfo); @@ -295,11 +297,11 @@ void Checker::ThrowAssignmentError(Type *source, Type *target, lexer::SourcePosi ThrowTypeError({"Type '", source, "' is not assignable to type '", target, "'."}, lineInfo); } -Type *Checker::GetUnaryResultType(Type *operandType) +Type *TSChecker::GetUnaryResultType(Type *operandType) { - if (checker::Checker::MaybeTypeOfKind(operandType, checker::TypeFlag::BIGINT_LIKE)) { + if (checker::TSChecker::MaybeTypeOfKind(operandType, checker::TypeFlag::BIGINT_LIKE)) { if (operandType->HasTypeFlag(checker::TypeFlag::UNION_OR_INTERSECTION) && - checker::Checker::MaybeTypeOfKind(operandType, checker::TypeFlag::NUMBER_LIKE)) { + checker::TSChecker::MaybeTypeOfKind(operandType, checker::TypeFlag::NUMBER_LIKE)) { return GlobalNumberOrBigintType(); } @@ -309,7 +311,7 @@ Type *Checker::GetUnaryResultType(Type *operandType) return GlobalNumberType(); } -void Checker::ElaborateElementwise(Type *targetType, const ir::Expression *sourceNode, const lexer::SourcePosition &pos) +void TSChecker::ElaborateElementwise(Type *targetType, ir::Expression *sourceNode, const lexer::SourcePosition &pos) { auto savedContext = SavedCheckerContext(this, CheckerStatus::FORCE_TUPLE | CheckerStatus::KEEP_LITERAL_TYPE); @@ -332,7 +334,7 @@ void Checker::ElaborateElementwise(Type *targetType, const ir::Expression *sourc ThrowAssignmentError(sourceType, targetType, pos); } -void Checker::InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *declarator) +void TSChecker::InferSimpleVariableDeclaratorType(ir::VariableDeclarator *declarator) { ASSERT(declarator->Id()->IsIdentifier()); @@ -340,7 +342,7 @@ void Checker::InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *de ASSERT(var); if (declarator->Id()->AsIdentifier()->TypeAnnotation() != nullptr) { - var->SetTsType(declarator->Id()->AsIdentifier()->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(declarator->Id()->AsIdentifier()->TypeAnnotation()->GetType(this)); return; } @@ -353,20 +355,19 @@ void Checker::InferSimpleVariableDeclaratorType(const ir::VariableDeclarator *de declarator->Id()->Start()); } -Type *Checker::GetTypeOfVariable(binder::Variable *var) +Type *TSChecker::GetTypeOfVariable(binder::Variable *var) { if (var->TsType() != nullptr) { return var->TsType(); } - const binder::Decl *decl = var->Declaration(); + binder::Decl *decl = var->Declaration(); - if (!typeStack_.insert(decl->Node()).second) { - ThrowTypeError({"'", var->Name(), - "' is referenced directly or indirectly in its " - "own initializer ot type annotation."}, - decl->Node()->Start()); - } + TypeStackElement tse(this, decl->Node(), + {"'", var->Name(), + "' is referenced directly or indirectly in its " + "own initializer ot type annotation."}, + decl->Node()->Start()); switch (decl->Type()) { case binder::DeclType::CONST: @@ -380,7 +381,8 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) [[fallthrough]]; } case binder::DeclType::VAR: { - const ir::AstNode *declarator = FindAncestorGivenByType(decl->Node(), ir::AstNodeType::VARIABLE_DECLARATOR); + ir::AstNode *declarator = + util::Helpers::FindAncestorGivenByType(decl->Node(), ir::AstNodeType::VARIABLE_DECLARATOR); ASSERT(declarator); if (declarator->AsVariableDeclarator()->Id()->IsIdentifier()) { @@ -392,12 +394,12 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) break; } case binder::DeclType::PROPERTY: { - var->SetTsType(decl->Node()->AsTSPropertySignature()->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(decl->Node()->AsTSPropertySignature()->TypeAnnotation()->GetType(this)); break; } case binder::DeclType::METHOD: { - auto *signatureInfo = allocator_->New(allocator_); - auto *callSignature = allocator_->New(signatureInfo, GlobalAnyType()); + auto *signatureInfo = allocator_.New(&allocator_); + auto *callSignature = allocator_.New(signatureInfo, GlobalAnyType()); var->SetTsType(CreateFunctionTypeWithSignature(callSignature)); break; } @@ -407,13 +409,13 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) break; } case binder::DeclType::PARAM: { - const ir::AstNode *declaration = FindAncestorUntilGivenType(decl->Node(), ir::AstNodeType::SCRIPT_FUNCTION); + ir::AstNode *declaration = FindAncestorUntilGivenType(decl->Node(), ir::AstNodeType::SCRIPT_FUNCTION); if (declaration->IsIdentifier()) { - const ir::Identifier *ident = declaration->AsIdentifier(); + auto *ident = declaration->AsIdentifier(); if (ident->TypeAnnotation() != nullptr) { ASSERT(ident->Variable() == var); - var->SetTsType(ident->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(ident->TypeAnnotation()->GetType(this)); break; } @@ -421,11 +423,11 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) } if (declaration->IsAssignmentPattern() && declaration->AsAssignmentPattern()->Left()->IsIdentifier()) { - const ir::Identifier *ident = declaration->AsAssignmentPattern()->Left()->AsIdentifier(); + ir::Identifier *ident = declaration->AsAssignmentPattern()->Left()->AsIdentifier(); if (ident->TypeAnnotation() != nullptr) { ASSERT(ident->Variable() == var); - var->SetTsType(ident->TypeAnnotation()->AsTypeNode()->GetType(this)); + var->SetTsType(ident->TypeAnnotation()->GetType(this)); break; } @@ -458,18 +460,16 @@ Type *Checker::GetTypeOfVariable(binder::Variable *var) } } - typeStack_.erase(decl->Node()); return var->TsType(); } -Type *Checker::GetTypeFromClassOrInterfaceReference([[maybe_unused]] const ir::TSTypeReference *node, - binder::Variable *var) +Type *TSChecker::GetTypeFromClassOrInterfaceReference([[maybe_unused]] ir::TSTypeReference *node, binder::Variable *var) { Type *resolvedType = var->TsType(); if (resolvedType == nullptr) { - ObjectDescriptor *desc = allocator_->New(allocator_); - resolvedType = allocator_->New(allocator_, var->Name(), desc); + ObjectDescriptor *desc = allocator_.New(&allocator_); + resolvedType = allocator_.New(&allocator_, var->Name(), desc); resolvedType->SetVariable(var); var->SetTsType(resolvedType); } @@ -477,27 +477,25 @@ Type *Checker::GetTypeFromClassOrInterfaceReference([[maybe_unused]] const ir::T return resolvedType; } -Type *Checker::GetTypeFromTypeAliasReference(const ir::TSTypeReference *node, binder::Variable *var) +Type *TSChecker::GetTypeFromTypeAliasReference(ir::TSTypeReference *node, binder::Variable *var) { Type *resolvedType = var->TsType(); - if (resolvedType == nullptr) { - if (!typeStack_.insert(var).second) { - ThrowTypeError({"Type alias ", var->Name(), " circularly refences itself"}, node->Start()); - } + if (resolvedType != nullptr) { + return resolvedType; + } - ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSTypeAliasDeclaration()); - const ir::TSTypeAliasDeclaration *declaration = var->Declaration()->Node()->AsTSTypeAliasDeclaration(); - resolvedType = declaration->TypeAnnotation()->AsTypeNode()->GetType(this); - var->SetTsType(resolvedType); + TypeStackElement tse(this, var, {"Type alias ", var->Name(), " circularly refences itself"}, node->Start()); - typeStack_.erase(var); - } + ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSTypeAliasDeclaration()); + ir::TSTypeAliasDeclaration *declaration = var->Declaration()->Node()->AsTSTypeAliasDeclaration(); + resolvedType = declaration->TypeAnnotation()->GetType(this); + var->SetTsType(resolvedType); return resolvedType; } -Type *Checker::GetTypeReferenceType(const ir::TSTypeReference *node, binder::Variable *var) +Type *TSChecker::GetTypeReferenceType(ir::TSTypeReference *node, binder::Variable *var) { ASSERT(var->Declaration()); binder::Decl *decl = var->Declaration(); diff --git a/typescript/core/object.cpp b/checker/ts/object.cpp similarity index 78% rename from typescript/core/object.cpp rename to checker/ts/object.cpp index d25b48d4ff3a4249e75643ec14c09de323a76bc3..cd4f1c586b457b79d5d5851cd35c6484e7ea43ee 100644 --- a/typescript/core/object.cpp +++ b/checker/ts/object.cpp @@ -22,10 +22,10 @@ #include "plugins/ecmascript/es2panda/ir/base/property.h" #include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" #include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsIndexSignature.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsMethodSignature.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsPropertySignature.h" -#include "plugins/ecmascript/es2panda/ir/ts/tsSignatureDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/base/tsIndexSignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsMethodSignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsPropertySignature.h" +#include "plugins/ecmascript/es2panda/ir/base/tsSignatureDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsTypeLiteral.h" #include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" #include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceHeritage.h" @@ -34,11 +34,11 @@ #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/binder/scope.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" namespace panda::es2panda::checker { -void Checker::CheckIndexConstraints(Type *type) +void TSChecker::CheckIndexConstraints(Type *type) { if (!type->IsObjectType()) { return; @@ -80,7 +80,7 @@ void Checker::CheckIndexConstraints(Type *type) } } -void Checker::ResolveStructuredTypeMembers(Type *type) +void TSChecker::ResolveStructuredTypeMembers(Type *type) { if (type->IsObjectType()) { ObjectType *obj_type = type->AsObjectType(); @@ -102,17 +102,17 @@ void Checker::ResolveStructuredTypeMembers(Type *type) } } -void Checker::ResolveUnionTypeMembers(UnionType *type) +void TSChecker::ResolveUnionTypeMembers(UnionType *type) { if (type->MergedObjectType() != nullptr) { return; } - ObjectDescriptor *desc = allocator_->New(allocator_); - ArenaVector stringInfoTypes(allocator_->Adapter()); - ArenaVector numberInfoTypes(allocator_->Adapter()); - ArenaVector callSignatures(allocator_->Adapter()); - ArenaVector constructSignatures(allocator_->Adapter()); + ObjectDescriptor *desc = allocator_.New(&allocator_); + ArenaVector stringInfoTypes(allocator_.Adapter()); + ArenaVector numberInfoTypes(allocator_.Adapter()); + ArenaVector callSignatures(allocator_.Adapter()); + ArenaVector constructSignatures(allocator_.Adapter()); for (auto *it : type->AsUnionType()->ConstituentTypes()) { if (!it->IsObjectType()) { @@ -147,19 +147,19 @@ void Checker::ResolveUnionTypeMembers(UnionType *type) desc->constructSignatures = constructSignatures; if (!stringInfoTypes.empty()) { - desc->stringIndexInfo = allocator_->New(CreateUnionType(std::move(stringInfoTypes)), "x", false); + desc->stringIndexInfo = allocator_.New(CreateUnionType(std::move(stringInfoTypes)), "x", false); } if (!numberInfoTypes.empty()) { - desc->numberIndexInfo = allocator_->New(CreateUnionType(std::move(numberInfoTypes)), "x", false); + desc->numberIndexInfo = allocator_.New(CreateUnionType(std::move(numberInfoTypes)), "x", false); } - ObjectType *merged_type = allocator_->New(desc); + ObjectType *merged_type = allocator_.New(desc); merged_type->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); type->SetMergedObjectType(merged_type); } -void Checker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type) +void TSChecker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type) { if (type->HasObjectFlag(ObjectFlags::RESOLVED_MEMBERS)) { return; @@ -171,16 +171,16 @@ void Checker::ResolveInterfaceOrClassTypeMembers(InterfaceType *type) type->AddObjectFlag(ObjectFlags::RESOLVED_MEMBERS); } -void Checker::ResolveObjectTypeMembers(ObjectType *type) +void TSChecker::ResolveObjectTypeMembers(ObjectType *type) { if (!type->IsObjectLiteralType() || type->HasObjectFlag(ObjectFlags::RESOLVED_MEMBERS)) { return; } ASSERT(type->Variable() && type->Variable()->Declaration()->Node()->IsTSTypeLiteral()); - const auto *typeLiteral = type->Variable()->Declaration()->Node()->AsTSTypeLiteral(); - ArenaVector signatureDeclarations(allocator_->Adapter()); - ArenaVector indexDeclarations(allocator_->Adapter()); + auto *typeLiteral = type->Variable()->Declaration()->Node()->AsTSTypeLiteral(); + ArenaVector signatureDeclarations(allocator_.Adapter()); + ArenaVector indexDeclarations(allocator_.Adapter()); for (auto *it : typeLiteral->Members()) { ResolvePropertiesOfObjectType(type, it, signatureDeclarations, indexDeclarations, false); @@ -192,10 +192,9 @@ void Checker::ResolveObjectTypeMembers(ObjectType *type) ResolveIndexInfosOfObjectType(type, indexDeclarations); } -void Checker::ResolvePropertiesOfObjectType(ObjectType *type, const ir::Expression *member, - ArenaVector &signatureDeclarations, - ArenaVector &indexDeclarations, - bool isInterface) +void TSChecker::ResolvePropertiesOfObjectType(ObjectType *type, ir::AstNode *member, + ArenaVector &signatureDeclarations, + ArenaVector &indexDeclarations, bool isInterface) { if (member->IsTSPropertySignature()) { binder::Variable *prop = member->AsTSPropertySignature()->Variable(); @@ -228,8 +227,8 @@ void Checker::ResolvePropertiesOfObjectType(ObjectType *type, const ir::Expressi indexDeclarations.push_back(member->AsTSIndexSignature()); } -void Checker::ResolveSignaturesOfObjectType(ObjectType *type, - ArenaVector &signatureDeclarations) +void TSChecker::ResolveSignaturesOfObjectType(ObjectType *type, + ArenaVector &signatureDeclarations) { for (auto *it : signatureDeclarations) { Type *placeholderObj = it->Check(this); @@ -243,8 +242,7 @@ void Checker::ResolveSignaturesOfObjectType(ObjectType *type, type->AddConstructSignature(placeholderObj->AsObjectType()->ConstructSignatures()[0]); } } -void Checker::ResolveIndexInfosOfObjectType(ObjectType *type, - ArenaVector &indexDeclarations) +void TSChecker::ResolveIndexInfosOfObjectType(ObjectType *type, ArenaVector &indexDeclarations) { for (auto *it : indexDeclarations) { Type *placeholderObj = it->Check(this); @@ -270,8 +268,8 @@ void Checker::ResolveIndexInfosOfObjectType(ObjectType *type, } } -binder::Variable *Checker::GetPropertyOfType(Type *type, const util::StringView &name, bool getPartial, - binder::VariableFlags propagateFlags) +binder::Variable *TSChecker::GetPropertyOfType(Type *type, const util::StringView &name, bool getPartial, + binder::VariableFlags propagateFlags) { if (type->IsObjectType()) { ResolveObjectTypeMembers(type->AsObjectType()); @@ -285,8 +283,8 @@ binder::Variable *Checker::GetPropertyOfType(Type *type, const util::StringView return nullptr; } -binder::Variable *Checker::GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, - binder::VariableFlags propagateFlags) +binder::Variable *TSChecker::GetPropertyOfUnionType(UnionType *type, const util::StringView &name, bool getPartial, + binder::VariableFlags propagateFlags) { auto found = type->CachedSyntheticPropertis().find(name); @@ -295,7 +293,7 @@ binder::Variable *Checker::GetPropertyOfUnionType(UnionType *type, const util::S } binder::VariableFlags flags = binder::VariableFlags::PROPERTY; - ArenaVector collectedTypes(allocator_->Adapter()); + ArenaVector collectedTypes(allocator_.Adapter()); for (auto *it : type->ConstituentTypes()) { binder::Variable *prop = GetPropertyOfType(it, name); @@ -341,17 +339,16 @@ binder::Variable *Checker::GetPropertyOfUnionType(UnionType *type, const util::S return nullptr; } - binder::Variable *syntheticProp = binder::Scope::CreateVar(allocator_, name, flags, nullptr); + binder::Variable *syntheticProp = binder::Scope::CreateVar(&allocator_, name, flags, nullptr); syntheticProp->SetTsType(CreateUnionType(std::move(collectedTypes))); type->CachedSyntheticPropertis().insert({name, syntheticProp}); return syntheticProp; } -Type *Checker::CheckComputedPropertyName(const ir::Expression *key) +Type *TSChecker::CheckComputedPropertyName(ir::Expression *key) { - auto found = nodeCache_.find(key); - if (found != nodeCache_.end()) { - return found->second; + if (key->TsType()) { + return key->TsType(); } Type *keyType = key->Check(this); @@ -364,11 +361,11 @@ Type *Checker::CheckComputedPropertyName(const ir::Expression *key) key->Start()); } - nodeCache_.insert({key, keyType}); + key->SetTsType(keyType); return keyType; } -IndexInfo *Checker::GetApplicableIndexInfo(Type *type, Type *indexType) +IndexInfo *TSChecker::GetApplicableIndexInfo(Type *type, Type *indexType) { ResolveStructuredTypeMembers(type); bool getNumberInfo = indexType->HasTypeFlag(TypeFlag::NUMBER_LIKE); @@ -394,7 +391,7 @@ IndexInfo *Checker::GetApplicableIndexInfo(Type *type, Type *indexType) return nullptr; } -Type *Checker::GetPropertyTypeForIndexType(Type *type, Type *indexType) +Type *TSChecker::GetPropertyTypeForIndexType(Type *type, Type *indexType) { if (type->IsArrayType()) { return type->AsArrayType()->ElementType(); @@ -407,7 +404,7 @@ Type *Checker::GetPropertyTypeForIndexType(Type *type, Type *indexType) prop = GetPropertyOfType(type, indexType->AsStringLiteralType()->Value()); } else { util::StringView prop_name = - util::Helpers::ToStringView(allocator_, indexType->AsNumberLiteralType()->Value()); + util::Helpers::ToStringView(&allocator_, indexType->AsNumberLiteralType()->Value()); prop = GetPropertyOfType(type, prop_name); } @@ -439,7 +436,7 @@ Type *Checker::GetPropertyTypeForIndexType(Type *type, Type *indexType) return nullptr; } -ArenaVector Checker::GetBaseTypes(InterfaceType *type) +ArenaVector TSChecker::GetBaseTypes(InterfaceType *type) { if (type->HasObjectFlag(ObjectFlags::RESOLVED_BASE_TYPES)) { return type->Bases(); @@ -448,18 +445,16 @@ ArenaVector Checker::GetBaseTypes(InterfaceType *type) ASSERT(type->Variable() && type->Variable()->Declaration()->IsInterfaceDecl()); binder::InterfaceDecl *decl = type->Variable()->Declaration()->AsInterfaceDecl(); - if (!typeStack_.insert(type).second) { - ThrowTypeError({"Type ", type->Name(), " recursively references itself as a base type."}, - decl->Node()->AsTSInterfaceDeclaration()->Id()->Start()); - } + TypeStackElement tse(this, type, {"Type ", type->Name(), " recursively references itself as a base type."}, + decl->Node()->AsTSInterfaceDeclaration()->Id()->Start()); for (const auto *declaration : decl->Decls()) { if (declaration->Extends().empty()) { continue; } - for (const auto *extends : declaration->Extends()) { - Type *baseType = extends->Expr()->AsTypeNode()->GetType(this); + for (auto *extends : declaration->Extends()) { + Type *baseType = extends->Expr()->GetType(this); if (!baseType->HasTypeFlag(TypeFlag::OBJECT | TypeFlag::NON_PRIMITIVE | TypeFlag::ANY)) { ThrowTypeError( @@ -497,11 +492,10 @@ ArenaVector Checker::GetBaseTypes(InterfaceType *type) } type->AddObjectFlag(ObjectFlags::RESOLVED_BASE_TYPES); - typeStack_.erase(type); return type->Bases(); } -void Checker::ResolveDeclaredMembers(InterfaceType *type) +void TSChecker::ResolveDeclaredMembers(InterfaceType *type) { if (type->HasObjectFlag(ObjectFlags::RESOLVED_DECLARED_MEMBERS)) { return; @@ -510,11 +504,11 @@ void Checker::ResolveDeclaredMembers(InterfaceType *type) ASSERT(type->Variable() && type->Variable()->Declaration()->IsInterfaceDecl()); binder::InterfaceDecl *decl = type->Variable()->Declaration()->AsInterfaceDecl(); - ArenaVector signatureDeclarations(allocator_->Adapter()); - ArenaVector indexDeclarations(allocator_->Adapter()); + ArenaVector signatureDeclarations(allocator_.Adapter()); + ArenaVector indexDeclarations(allocator_.Adapter()); for (const auto *declaration : decl->Decls()) { - for (const auto *member : declaration->Body()->Body()) { + for (auto *member : declaration->Body()->Body()) { ResolvePropertiesOfObjectType(type, member, signatureDeclarations, indexDeclarations, true); } @@ -525,8 +519,8 @@ void Checker::ResolveDeclaredMembers(InterfaceType *type) } } -bool Checker::ValidateInterfaceMemberRedeclaration(ObjectType *type, binder::Variable *prop, - const lexer::SourcePosition &locInfo) +bool TSChecker::ValidateInterfaceMemberRedeclaration(ObjectType *type, binder::Variable *prop, + const lexer::SourcePosition &locInfo) { if (prop->HasFlag(binder::VariableFlags::COMPUTED)) { return true; diff --git a/typescript/core/typeCreation.cpp b/checker/ts/typeCreation.cpp similarity index 50% rename from typescript/core/typeCreation.cpp rename to checker/ts/typeCreation.cpp index dde86e22d41daa1e8a5b19dbca0fc5351daa8875..fdde6075c7f2ee9fc5bab7904949650b0dcc9c46 100644 --- a/typescript/core/typeCreation.cpp +++ b/checker/ts/typeCreation.cpp @@ -13,49 +13,49 @@ * limitations under the License. */ -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" namespace panda::es2panda::checker { -Type *Checker::CreateNumberLiteralType(double value) +Type *TSChecker::CreateNumberLiteralType(double value) { auto search = numberLiteralMap_.find(value); if (search != numberLiteralMap_.end()) { return search->second; } - auto *newNumLiteralType = allocator_->New(value); + auto *newNumLiteralType = allocator_.New(value); numberLiteralMap_.insert({value, newNumLiteralType}); return newNumLiteralType; } -Type *Checker::CreateBigintLiteralType(const util::StringView &str, bool negative) +Type *TSChecker::CreateBigintLiteralType(const util::StringView &str, bool negative) { auto search = bigintLiteralMap_.find(str); if (search != bigintLiteralMap_.end()) { return search->second; } - auto *newBigiLiteralType = allocator_->New(str, negative); + auto *newBigiLiteralType = allocator_.New(str, negative); bigintLiteralMap_.insert({str, newBigiLiteralType}); return newBigiLiteralType; } -Type *Checker::CreateStringLiteralType(const util::StringView &str) +Type *TSChecker::CreateStringLiteralType(const util::StringView &str) { auto search = stringLiteralMap_.find(str); if (search != stringLiteralMap_.end()) { return search->second; } - auto *newStrLiteralType = allocator_->New(str); + auto *newStrLiteralType = allocator_.New(str); stringLiteralMap_.insert({str, newStrLiteralType}); return newStrLiteralType; } -Type *Checker::CreateUnionType(std::initializer_list constituentTypes) +Type *TSChecker::CreateUnionType(std::initializer_list constituentTypes) { - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); for (auto *it : constituentTypes) { newConstituentTypes.push_back(it); @@ -64,9 +64,9 @@ Type *Checker::CreateUnionType(std::initializer_list constituentTypes) return CreateUnionType(std::move(newConstituentTypes)); } -Type *Checker::CreateUnionType(ArenaVector &constituentTypes) +Type *TSChecker::CreateUnionType(ArenaVector &constituentTypes) { - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); for (auto *it : constituentTypes) { if (it->IsUnionType()) { @@ -86,18 +86,18 @@ Type *Checker::CreateUnionType(ArenaVector &constituentTypes) return newConstituentTypes[0]; } - auto *newUnionType = allocator_->New(newConstituentTypes); + auto *newUnionType = allocator_.New(newConstituentTypes); return UnionType::HandleUnionType(newUnionType, globalTypes_); } -Type *Checker::CreateUnionType(ArenaVector &&constituentTypes) +Type *TSChecker::CreateUnionType(ArenaVector &&constituentTypes) { if (constituentTypes.empty()) { return nullptr; } - ArenaVector newConstituentTypes(allocator_->Adapter()); + ArenaVector newConstituentTypes(allocator_.Adapter()); for (auto *it : constituentTypes) { if (it->IsUnionType()) { @@ -117,57 +117,57 @@ Type *Checker::CreateUnionType(ArenaVector &&constituentTypes) return newConstituentTypes[0]; } - auto *newUnionType = allocator_->New(std::move(newConstituentTypes)); + auto *newUnionType = allocator_.New(std::move(newConstituentTypes)); return UnionType::HandleUnionType(newUnionType, globalTypes_); } -Type *Checker::CreateObjectTypeWithCallSignature(Signature *callSignature) +Type *TSChecker::CreateObjectTypeWithCallSignature(Signature *callSignature) { - auto *objType = allocator_->New(allocator_->New(allocator_)); + auto *objType = allocator_.New(allocator_.New(&allocator_)); objType->AddCallSignature(callSignature); return objType; } -Type *Checker::CreateObjectTypeWithConstructSignature(Signature *constructSignature) +Type *TSChecker::CreateObjectTypeWithConstructSignature(Signature *constructSignature) { - auto *objType = allocator_->New(allocator_->New(allocator_)); + auto *objType = allocator_.New(allocator_.New(&allocator_)); objType->AddConstructSignature(constructSignature); return objType; } -Type *Checker::CreateFunctionTypeWithSignature(Signature *callSignature) +Type *TSChecker::CreateFunctionTypeWithSignature(Signature *callSignature) { - auto *funcObjType = allocator_->New(allocator_->New(allocator_)); + auto *funcObjType = allocator_.New(allocator_.New(&allocator_)); funcObjType->AddCallSignature(callSignature); return funcObjType; } -Type *Checker::CreateConstructorTypeWithSignature(Signature *constructSignature) +Type *TSChecker::CreateConstructorTypeWithSignature(Signature *constructSignature) { - auto *constructObjType = allocator_->New(allocator_->New(allocator_)); + auto *constructObjType = allocator_.New(allocator_.New(&allocator_)); constructObjType->AddConstructSignature(constructSignature); return constructObjType; } -Type *Checker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, - ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly) +Type *TSChecker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, + ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly) { - desc->stringIndexInfo = allocator_->New(GlobalAnyType(), "x", readonly); - return allocator_->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); + desc->stringIndexInfo = allocator_.New(GlobalAnyType(), "x", readonly); + return allocator_.New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); } -Type *Checker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, - ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly, - NamedTupleMemberPool &&namedMembers) +Type *TSChecker::CreateTupleType(ObjectDescriptor *desc, ArenaVector &&elementFlags, + ElementFlags combinedFlags, uint32_t minLength, uint32_t fixedLength, bool readonly, + NamedTupleMemberPool &&namedMembers) { - desc->stringIndexInfo = allocator_->New(GlobalAnyType(), "x", readonly); + desc->stringIndexInfo = allocator_.New(GlobalAnyType(), "x", readonly); if (!namedMembers.empty()) { - return allocator_->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, - readonly, std::move(namedMembers)); + return allocator_.New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly, + std::move(namedMembers)); } - return allocator_->New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); + return allocator_.New(desc, std::move(elementFlags), combinedFlags, minLength, fixedLength, readonly); } } // namespace panda::es2panda::checker diff --git a/typescript/core/typeElaborationContext.cpp b/checker/ts/typeElaborationContext.cpp similarity index 94% rename from typescript/core/typeElaborationContext.cpp rename to checker/ts/typeElaborationContext.cpp index cc448257a059cd3492325c718aa7c4f46f183963..ee616ad678dea141af337c97981f938f3ff819b9 100644 --- a/typescript/core/typeElaborationContext.cpp +++ b/checker/ts/typeElaborationContext.cpp @@ -26,7 +26,7 @@ #include "plugins/ecmascript/es2panda/ir/base/property.h" namespace panda::es2panda::checker { -Type *ElaborationContext::GetBestMatchingType(Type *indexType, const ir::Expression *sourceNode) +Type *ElaborationContext::GetBestMatchingType(Type *indexType, ir::Expression *sourceNode) { ArenaVector bestMatchingType(checker_->Allocator()->Adapter()); Type *sourceType = sourceNode != nullptr ? checker_->CheckTypeCached(sourceNode) : checker_->GlobalAnyType(); @@ -105,7 +105,7 @@ void ObjectElaborationContext::Start() continue; } - const ir::Property *prop = it->AsProperty(); + ir::Property *prop = it->AsProperty(); Type *propKeyType = nullptr; if (prop->IsComputed()) { @@ -117,8 +117,8 @@ void ObjectElaborationContext::Start() break; } case ir::AstNodeType::NUMBER_LITERAL: { - propKeyType = - checker_->Allocator()->New(prop->Key()->AsNumberLiteral()->Number()); + propKeyType = checker_->Allocator()->New( + prop->Key()->AsNumberLiteral()->Number().GetDouble()); break; } case ir::AstNodeType::STRING_LITERAL: { diff --git a/typescript/core/typeElaborationContext.h b/checker/ts/typeElaborationContext.h similarity index 76% rename from typescript/core/typeElaborationContext.h rename to checker/ts/typeElaborationContext.h index 4dc247ee4682de97ae940da767b2507fc32e612d..df8925df2e82842ca59c1c050a8f491fb2c9ba7d 100644 --- a/typescript/core/typeElaborationContext.h +++ b/checker/ts/typeElaborationContext.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_TYPESCIRPT_CORE_TYPE_ELABORATION_CONTEXT_H -#define ES2PANDA_TYPESCIRPT_CORE_TYPE_ELABORATION_CONTEXT_H +#ifndef ES2PANDA_CHECKER_TS_TYPE_ELABORATION_CONTEXT_H +#define ES2PANDA_CHECKER_TS_TYPE_ELABORATION_CONTEXT_H -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" #include "plugins/ecmascript/es2panda/ir/expression.h" #include @@ -31,7 +31,7 @@ class Type; class ElaborationContext { public: - ElaborationContext(Checker *checker, Type *targetType, Type *sourceType, const ir::Expression *sourceNode, + ElaborationContext(TSChecker *checker, Type *targetType, Type *sourceType, ir::Expression *sourceNode, const lexer::SourcePosition &startPos) : checker_(checker), targetType_(targetType), @@ -45,14 +45,14 @@ public: virtual void Start() = 0; virtual void RemoveUnnecessaryTypes() = 0; - Type *GetBestMatchingType(Type *indexType, const ir::Expression *sourceNode); + Type *GetBestMatchingType(Type *indexType, ir::Expression *sourceNode); protected: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - Checker *checker_; + TSChecker *checker_; Type *targetType_; Type *sourceType_; - const ir::Expression *sourceNode_; + ir::Expression *sourceNode_; const lexer::SourcePosition startPos_; ArenaVector potentialTypes_; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -60,7 +60,7 @@ protected: class ArrayElaborationContext : public ElaborationContext { public: - ArrayElaborationContext(Checker *checker, Type *targetType, Type *sourceType, const ir::Expression *sourceNode, + ArrayElaborationContext(TSChecker *checker, Type *targetType, Type *sourceType, ir::Expression *sourceNode, const lexer::SourcePosition &startPos) : ElaborationContext(checker, targetType, sourceType, sourceNode, startPos) { @@ -75,7 +75,7 @@ private: class ObjectElaborationContext : public ElaborationContext { public: - ObjectElaborationContext(Checker *checker, Type *targetType, Type *sourceType, const ir::Expression *sourceNode, + ObjectElaborationContext(TSChecker *checker, Type *targetType, Type *sourceType, ir::Expression *sourceNode, const lexer::SourcePosition &startPos) : ElaborationContext(checker, targetType, sourceType, sourceNode, startPos) { diff --git a/typescript/core/util.cpp b/checker/ts/util.cpp similarity index 76% rename from typescript/core/util.cpp rename to checker/ts/util.cpp index 779729f20887543e94a61d72e8187a8559b6a32a..0d6f24ba634f8cfa1a9318d05dc30d13f996e037 100644 --- a/typescript/core/util.cpp +++ b/checker/ts/util.cpp @@ -19,23 +19,12 @@ #include "plugins/ecmascript/es2panda/ir/expressions/templateLiteral.h" #include "plugins/ecmascript/es2panda/ir/ts/tsQualifiedName.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -const ir::TSQualifiedName *Checker::ResolveLeftMostQualifiedName(const ir::TSQualifiedName *qualifiedName) +ir::MemberExpression *TSChecker::ResolveLeftMostMemberExpression(ir::MemberExpression *expr) { - const ir::TSQualifiedName *iter = qualifiedName; - - while (iter->Left()->IsTSQualifiedName()) { - iter = iter->Left()->AsTSQualifiedName(); - } - - return iter; -} - -const ir::MemberExpression *Checker::ResolveLeftMostMemberExpression(const ir::MemberExpression *expr) -{ - const ir::MemberExpression *iter = expr; + ir::MemberExpression *iter = expr; while (iter->Object()->IsMemberExpression()) { iter = iter->Object()->AsMemberExpression(); @@ -44,9 +33,9 @@ const ir::MemberExpression *Checker::ResolveLeftMostMemberExpression(const ir::M return iter; } -bool Checker::InAssignment(const ir::AstNode *node) +bool TSChecker::InAssignment(ir::AstNode *node) { - const ir::AstNode *parent = node; + ir::AstNode *parent = node; while (parent->Parent() != nullptr) { if (parent->Parent()->IsAssignmentExpression()) { @@ -54,7 +43,7 @@ bool Checker::InAssignment(const ir::AstNode *node) } if (parent->Parent()->IsBinaryExpression()) { - const ir::BinaryExpression *binaryExpr = parent->Parent()->AsBinaryExpression(); + ir::BinaryExpression *binaryExpr = parent->Parent()->AsBinaryExpression(); return IsAssignmentOperator(binaryExpr->OperatorType()) && binaryExpr->Left() == parent; } @@ -67,7 +56,7 @@ bool Checker::InAssignment(const ir::AstNode *node) return false; } -bool Checker::IsAssignmentOperator(lexer::TokenType op) +bool TSChecker::IsAssignmentOperator(lexer::TokenType op) { switch (op) { case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: @@ -91,7 +80,7 @@ bool Checker::IsAssignmentOperator(lexer::TokenType op) } } -bool Checker::IsLiteralType(const Type *type) +bool TSChecker::IsLiteralType(const Type *type) { if (type->IsBooleanType()) { return true; @@ -109,23 +98,7 @@ bool Checker::IsLiteralType(const Type *type) return type->HasTypeFlag(TypeFlag::UNIT); } -const ir::AstNode *Checker::FindAncestorGivenByType(const ir::AstNode *node, ir::AstNodeType type) -{ - node = node->Parent(); - - while (node->Type() != type) { - if (node->Parent() != nullptr) { - node = node->Parent(); - continue; - } - - return nullptr; - } - - return node; -} - -const ir::AstNode *Checker::FindAncestorUntilGivenType(const ir::AstNode *node, ir::AstNodeType stop) +ir::AstNode *TSChecker::FindAncestorUntilGivenType(ir::AstNode *node, ir::AstNodeType stop) { while (node->Parent()->Type() != stop) { if (node->Parent() != nullptr) { @@ -139,7 +112,7 @@ const ir::AstNode *Checker::FindAncestorUntilGivenType(const ir::AstNode *node, return node; } -bool Checker::MaybeTypeOfKind(const Type *type, TypeFlag flags) +bool TSChecker::MaybeTypeOfKind(const Type *type, TypeFlag flags) { if (type->HasTypeFlag(flags)) { return true; @@ -159,7 +132,7 @@ bool Checker::MaybeTypeOfKind(const Type *type, TypeFlag flags) return false; } -bool Checker::MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind) +bool TSChecker::MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind) { if (type->IsObjectType() && type->AsObjectType()->Kind() == kind) { return true; @@ -179,7 +152,7 @@ bool Checker::MaybeTypeOfKind(const Type *type, ObjectType::ObjectTypeKind kind) return false; } -bool Checker::IsConstantMemberAccess(const ir::Expression *expr) +bool TSChecker::IsConstantMemberAccess(ir::Expression *expr) { switch (expr->Type()) { case ir::AstNodeType::IDENTIFIER: { @@ -196,7 +169,7 @@ bool Checker::IsConstantMemberAccess(const ir::Expression *expr) } } -bool Checker::IsStringLike(const ir::Expression *expr) +bool TSChecker::IsStringLike(ir::Expression *expr) { if (expr->IsStringLiteral()) { return true; diff --git a/checker/types/ets/byteType.cpp b/checker/types/ets/byteType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a61b7e418b51f0c3be49b5607dfd17523b05682 --- /dev/null +++ b/checker/types/ets/byteType.cpp @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "byteType.h" +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +void ByteType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsByteType()) { + relation->Result(true); + } +} + +void ByteType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +Type *ByteType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/byteType.h b/checker/types/ets/byteType.h new file mode 100644 index 0000000000000000000000000000000000000000..6ac78499449322125de407d78cd9379a9e0ee402 --- /dev/null +++ b/checker/types/ets/byteType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_BYTE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_BYTE_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ByteType : public Type { +public: + using UType = int8_t; + + ByteType() : Type(TypeFlag::BYTE), size_(8) {} + ByteType(UType value) : Type(TypeFlag::BYTE | TypeFlag::CONSTANT), size_(8), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "byte"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_BYTE; + } + +private: + size_t size_; + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/charType.cpp b/checker/types/ets/charType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d5c1092db198dd7e3f1d7e330dd1ca0e3d6be33 --- /dev/null +++ b/checker/types/ets/charType.cpp @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "charType.h" +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +void CharType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsCharType()) { + relation->Result(true); + } +} + +void CharType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +Type *CharType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/charType.h b/checker/types/ets/charType.h new file mode 100644 index 0000000000000000000000000000000000000000..928bcc83e31b13906ad9c1ca46b7b16a838cc972 --- /dev/null +++ b/checker/types/ets/charType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_CHAR_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_CHAR_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class CharType : public Type { +public: + using UType = char16_t; + + CharType() : Type(TypeFlag::CHAR), size_(16) {} + CharType(UType value) : Type(TypeFlag::CHAR | TypeFlag::CONSTANT), size_(16), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "char"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_CHAR; + } + +private: + size_t size_; + UType value_ {'\0'}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/doubleType.cpp b/checker/types/ets/doubleType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de848d04275c259b186d8a7d4a84712fc7c0e20f --- /dev/null +++ b/checker/types/ets/doubleType.cpp @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "doubleType.h" +#include "plugins/ecmascript/es2panda/checker/ets/wideningConverter.h" + +namespace panda::es2panda::checker { +void DoubleType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsDoubleType()) { + relation->Result(true); + } +} + +void DoubleType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + WideningConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +Type *DoubleType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/doubleType.h b/checker/types/ets/doubleType.h new file mode 100644 index 0000000000000000000000000000000000000000..fd0a64d3de86e444ad8a4a9b1bb817e2e6f98bda --- /dev/null +++ b/checker/types/ets/doubleType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_DOUBLE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_DOUBLE_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class DoubleType : public Type { +public: + using UType = double; + + DoubleType() : Type(TypeFlag::DOUBLE), size_(64) {} + DoubleType(UType value) : Type(TypeFlag::DOUBLE | TypeFlag::CONSTANT), size_(64), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "double"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_DOUBLE; + } + +private: + size_t size_; + UType value_ {0.0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/etsArrayType.cpp b/checker/types/ets/etsArrayType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d9a98dcc1eda4f1f457f498dcc43509ab85b056 --- /dev/null +++ b/checker/types/ets/etsArrayType.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "etsArrayType.h" + +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +void ETSArrayType::ToString(std::stringstream &ss) const +{ + element_->ToString(ss); + ss << "[]"; +} + +void ETSArrayType::ToAssemblerType(std::stringstream &ss) const +{ + element_->ToAssemblerType(ss); + ss << "[]"; +} + +uint32_t ETSArrayType::Rank() const +{ + uint32_t rank = 1; + auto iter = element_; + while (iter->IsETSArrayType()) { + iter = iter->AsETSArrayType()->ElementType(); + rank++; + } + + return rank; +} + +void ETSArrayType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsETSArrayType()) { + relation->IsIdenticalTo(element_, other->AsETSArrayType()->ElementType()); + } +} + +void ETSArrayType::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (source->IsETSArrayType()) { + relation->IsAssignableTo(source->AsETSArrayType()->ElementType(), element_); + } +} + +Type *ETSArrayType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + return relation->GetChecker()->AsETSChecker()->CreateETSArrayType( + element_->Instantiate(allocator, relation, globalTypes)); +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsArrayType.h b/checker/types/ets/etsArrayType.h new file mode 100644 index 0000000000000000000000000000000000000000..0c2dd71d1529af81796ca020779473fc51adf5d4 --- /dev/null +++ b/checker/types/ets/etsArrayType.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_ARRAY_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_ARRAY_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ETSArrayType : public Type { +public: + explicit ETSArrayType(Type *elementType) : Type(TypeFlag::ETS_ARRAY), element_(elementType) {} + + Type *ElementType() + { + return element_; + } + + const Type *ElementType() const + { + return element_; + } + + void ToString(std::stringstream &ss) const override; + void ToAssemblerType(std::stringstream &ss) const override; + uint32_t Rank() const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + +private: + Type *element_; +}; +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_ARRAY_TYPE_H */ diff --git a/checker/types/ets/etsBooleanType.cpp b/checker/types/ets/etsBooleanType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ba7cec594a31ea7f96567c9cf7063f05d1ebf36 --- /dev/null +++ b/checker/types/ets/etsBooleanType.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "etsBooleanType.h" + +namespace panda::es2panda::checker { +void ETSBooleanType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsETSBooleanType()) { + relation->Result(true); + } +} + +void ETSBooleanType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *ETSBooleanType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsBooleanType.h b/checker/types/ets/etsBooleanType.h new file mode 100644 index 0000000000000000000000000000000000000000..9526e1d780633c65c5cd1984674765741ecdcb6b --- /dev/null +++ b/checker/types/ets/etsBooleanType.h @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_BOOLEAN_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_BOOLEAN_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ETSBooleanType : public Type { +public: + using UType = bool; + ETSBooleanType() : Type(TypeFlag::ETS_BOOLEAN), size_(1) {} + ETSBooleanType(UType value) : Type(TypeFlag::ETS_BOOLEAN | TypeFlag::CONSTANT), size_(1), value_(value) {} + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + UType GetValue() const + { + return value_; + } + + void ToString(std::stringstream &ss) const override + { + ss << "boolean"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_BOOLEAN; + } + +private: + size_t size_; + UType value_ {false}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/etsFunctionType.cpp b/checker/types/ets/etsFunctionType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5096d83ffba9df84486455672ce59a8cfe401b6c --- /dev/null +++ b/checker/types/ets/etsFunctionType.cpp @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "etsFunctionType.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { + +Signature *ETSFunctionType::FirstAbstractSignature() +{ + for (auto *it : callSignatures_) { + if (it->HasSignatureFlag(SignatureFlags::ABSTRACT)) { + return it; + } + } + + return nullptr; +} + +void ETSFunctionType::ToString(std::stringstream &ss) const +{ + callSignatures_[0]->ToString(ss, nullptr); +} + +void ETSFunctionType::Identical(TypeRelation *relation, Type *other) +{ + if (!other->IsETSFunctionType()) { + return; + } + + callSignatures_[0]->Identical(relation, other->AsETSFunctionType()->CallSignatures()[0]); +} + +void ETSFunctionType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + callSignatures_[0]->AssignmentTarget(relation, source->AsETSFunctionType()->CallSignatures()[0]); +} + +Type *ETSFunctionType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + auto *copiedType = relation->GetChecker()->AsETSChecker()->CreateETSFunctionType(name_); + + for (auto *it : callSignatures_) { + copiedType->AddCallSignature(it->Copy(allocator, relation, globalTypes)); + } + + return copiedType; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsFunctionType.h b/checker/types/ets/etsFunctionType.h new file mode 100644 index 0000000000000000000000000000000000000000..6025317f2d0ba4c34bfb53873b2f915b93f6438e --- /dev/null +++ b/checker/types/ets/etsFunctionType.h @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_FUNCTION_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_FUNCTION_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +namespace panda::es2panda::checker { + +class ETSFunctionType : public Type { +public: + explicit ETSFunctionType(util::StringView name, Signature *signature, ArenaAllocator *allocator) + : Type(TypeFlag::FUNCTION), callSignatures_(allocator->Adapter()), name_(name) + { + callSignatures_.push_back(signature); + } + + ETSFunctionType(util::StringView name, ArenaAllocator *allocator) + : Type(TypeFlag::FUNCTION), callSignatures_(allocator->Adapter()), name_(name) + { + } + + ArenaVector &CallSignatures() + { + return callSignatures_; + } + + const ArenaVector &CallSignatures() const + { + return callSignatures_; + } + + const util::StringView Name() const + { + return name_; + } + + void AddCallSignature(Signature *signature) + { + callSignatures_.push_back(signature); + } + + Signature *FindSignature(const ir::ScriptFunction *func) const + { + for (auto *it : callSignatures_) { + if (it->Function() == func) { + return it; + } + } + + return nullptr; + } + + Signature *FirstAbstractSignature(); + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + +private: + ArenaVector callSignatures_; + util::StringView name_; +}; +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_FUNCTION_TYPE_H */ diff --git a/checker/types/ets/etsObjectType.cpp b/checker/types/ets/etsObjectType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..080e1abd69cd7e64cb50e550e65811d08d1d33a4 --- /dev/null +++ b/checker/types/ets/etsObjectType.cpp @@ -0,0 +1,249 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "etsObjectType.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/binder/declaration.h" + +namespace panda::es2panda::checker { + +void ETSObjectType::Iterate(const PropertyTraverser &cb) const +{ + for (const auto &[_, prop] : properties_) { + cb(prop); + } + + if (superType_) { + superType_->Iterate(cb); + } + + for (const auto *interface : interfaces_) { + interface->Iterate(cb); + } +} + +binder::LocalVariable *ETSObjectType::GetProperty(const util::StringView &name, PropertySearchFlags flags) const +{ + const auto it = properties_.find(name); + if (it != properties_.end()) { + if (!(flags & (PropertySearchFlags::IGNORE_STATIC | PropertySearchFlags::IGNORE_INSTANCE_FIELD))) { + return it->second; + } + + if ((flags & PropertySearchFlags::IGNORE_STATIC) && !it->second->HasFlag(binder::VariableFlags::STATIC)) { + return it->second; + } + + if ((flags & PropertySearchFlags::IGNORE_INSTANCE_FIELD) && + it->second->HasFlag(binder::VariableFlags::STATIC)) { + return it->second; + } + } + + if (superType_ && (flags & PropertySearchFlags::SEARCH_IN_BASE)) { + auto *prop = superType_->GetProperty(name, flags); + + if (prop) { + return prop; + } + } + + if (flags & PropertySearchFlags::SEARCH_IN_INTERFACES) { + for (auto *interface : interfaces_) { + auto *prop = interface->GetProperty(name, flags); + + if (prop) { + return prop; + } + } + } + + return nullptr; +} + +std::vector ETSObjectType::ForeignProperties() const +{ + std::vector foreignProps; + std::unordered_set ownProps; + ownProps.reserve(properties_.size()); + + for (const auto &[propName, _] : properties_) { + ownProps.insert(propName); + } + + auto allProps = CollectAllProperties(); + for (const auto &[name, var] : allProps) { + if (ownProps.find(name) == ownProps.end()) { + foreignProps.push_back(var); + } + } + + return foreignProps; +} + +std::unordered_map ETSObjectType::CollectAllProperties() const +{ + std::unordered_map propMap; + propMap.reserve(properties_.size()); + Iterate([&propMap](const binder::LocalVariable *var) { propMap.insert({var->Name(), var}); }); + + return propMap; +} + +void ETSObjectType::ToString(std::stringstream &ss) const +{ + ss << name_; +} + +void ETSObjectType::Identical(TypeRelation *relation, Type *other) +{ + if (!other->IsETSObjectType() || !other->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) { + return; + } + + if (variable_ != other->Variable()) { + return; + } + + ETSObjectType *otherObj = other->AsETSObjectType(); + if (typeArguments_.empty() != otherObj->TypeArguments().empty()) { + return; + } + + if (!typeArguments_.empty()) { + ASSERT(typeArguments_.size() == otherObj->TypeArguments().size()); + for (size_t idx = 0; idx < typeArguments_.size(); idx++) { + typeArguments_[idx]->Identical(relation, otherObj->TypeArguments()[idx]); + if (!relation->IsTrue()) { + return; + } + } + } + + relation->Result(true); +} + +bool ETSObjectType::AssignmentSource([[maybe_unused]] TypeRelation *relation, Type *target) +{ + return target->IsETSNullType(); +} + +void ETSObjectType::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (source->IsETSNullType()) { + relation->Result(true); + return; + } + IsSubtype(relation, source); +} + +void ETSObjectType::IsSubtype(TypeRelation *relation, Type *source) +{ + if (!source->IsETSObjectType() || !source->AsETSObjectType()->HasObjectFlag(ETSObjectFlags::CLASS)) { + return; + } + + ETSObjectType *sourceObj = source->AsETSObjectType(); + Type *sup = sourceObj->AsSuper(relation->GetChecker(), variable_); + if (!sup) { + return; + } + + relation->Result(true); +} + +Type *ETSObjectType::AsSuper(Checker *checker, binder::Variable *sourceVar) +{ + if (!sourceVar) { + return nullptr; + } + + if (variable_ == sourceVar) { + return this; + } + + if (!checker->TypeStack().insert(sourceVar).second) { + return nullptr; + } + + Type *superType = checker->AsETSChecker()->GetSuperType(this); + + if (!superType) { + return this; + } + + if (!superType->IsETSObjectType()) { + checker->TypeStack().erase(sourceVar); + return nullptr; + } + + ETSObjectType *superObj = superType->AsETSObjectType(); + + if (superObj->HasObjectFlag(ETSObjectFlags::CLASS)) { + Type *res = superObj->AsSuper(checker, sourceVar); + if (res) { + checker->TypeStack().erase(sourceVar); + return res; + } + } + + if (sourceVar->Declaration()->Node()->IsTSInterfaceDeclaration()) { + ArenaVector interfaces = checker->AsETSChecker()->GetInterfaces(this); + for (auto *it : interfaces) { + Type *res = it->AsSuper(checker, sourceVar); + if (res) { + checker->TypeStack().erase(sourceVar); + return res; + } + } + } + + checker->TypeStack().erase(sourceVar); + return nullptr; +} + +Type *ETSObjectType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + auto *checker = relation->GetChecker()->AsETSChecker(); + auto *copiedType = checker->CreateNewETSObjectType(name_, declNode_, flags_); + copiedType->RemoveObjectFlag(ETSObjectFlags::CHECKED_COMPATIBLE_ABSTRACTS | + ETSObjectFlags::UNCOMPLETE_INSTANTIATION); + + copiedType->SetVariable(variable_); + copiedType->SetSuperType(superType_); + + for (auto *it : interfaces_) { + copiedType->AddInterface(it); + } + + for (auto &[_, it] : properties_) { + auto *copiedProp = it->Copy(allocator, it->Declaration()); + auto *copiedPropType = ETSChecker::TryToInstantiate(relation->GetChecker()->AsETSChecker()->GetTypeOfVariable(it), + allocator, relation, globalTypes); + copiedPropType->SetVariable(copiedProp); + copiedProp->SetTsType(copiedPropType); + copiedType->AddProperty(copiedProp); + } + + for (auto *it : constructSignatures_) { + copiedType->AddConstructSignature(it->Copy(allocator, relation, globalTypes)); + } + + return copiedType; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsObjectType.h b/checker/types/ets/etsObjectType.h new file mode 100644 index 0000000000000000000000000000000000000000..9e47a9a0fa2dbdca9316664e3a55e68419f093dc --- /dev/null +++ b/checker/types/ets/etsObjectType.h @@ -0,0 +1,313 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_OBJECT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_OBJECT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +namespace panda::es2panda::checker { + +enum class ETSObjectFlags { + NO_OPTS = 0, + CLASS = 1 << 0, + INTERFACE = 1 << 1, + INSTANCE = 1 << 2, + ABSTRACT = 1 << 3, + GLOBAL = 1 << 4, + ENUM = 1 << 5, + RESOLVED_MEMBERS = 1 << 6, + RESOLVED_INTERFACES = 1 << 7, + RESOLVED_SUPER = 1 << 8, + RESOLVED_TYPE_PARAMS = 1 << 9, + CHECKED_COMPATIBLE_ABSTRACTS = 1 << 10, + NULL_TYPE = 1 << 11, + STRING = 1 << 12, + UNCOMPLETE_INSTANTIATION = 1 << 13, + + BUILTIN_STRING = 1 << 23, + BUILTIN_BOOLEAN = 1 << 24, + BUILTIN_BYTE = 1 << 25, + BUILTIN_CHAR = 1 << 26, + BUILTIN_SHORT = 1 << 27, + BUILTIN_INT = 1 << 28, + BUILTIN_LONG = 1 << 29, + BUILTIN_FLOAT = 1 << 30, + BUILTIN_DOUBLE = 1 << 31, + + BUILTIN_TYPE = BUILTIN_STRING | BUILTIN_BOOLEAN | BUILTIN_BYTE | BUILTIN_CHAR | BUILTIN_SHORT | BUILTIN_INT | + BUILTIN_LONG | BUILTIN_FLOAT | BUILTIN_DOUBLE, + GLOBAL_CLASS = CLASS | GLOBAL, +}; + +DEFINE_BITOPS(ETSObjectFlags) + +enum class PropertySearchFlags { + NO_OPTS = 0, + SEARCH_IN_BASE = 1 << 0, + SEARCH_IN_INTERFACES = 1 << 1, + IGNORE_STATIC = 1 << 2, + IGNORE_INSTANCE_FIELD = 1 << 3, + + SEARCH_ALL = SEARCH_IN_BASE | SEARCH_IN_INTERFACES, +}; + +DEFINE_BITOPS(PropertySearchFlags) + +class ETSObjectType : public Type { +public: + using PropertyMap = ArenaUnorderedMap; + using InstantiationMap = ArenaUnorderedMap; + using PropertyTraverser = std::function; + + explicit ETSObjectType(ArenaAllocator *allocator) : ETSObjectType(allocator, ETSObjectFlags::NO_OPTS) {} + + explicit ETSObjectType(ArenaAllocator *allocator, ETSObjectFlags flags) + : ETSObjectType(allocator, "", "", nullptr, flags) + { + } + + explicit ETSObjectType(ArenaAllocator *allocator, util::StringView name, util::StringView assemblerName, + ir::AstNode *declNode, ETSObjectFlags flags) + : Type(TypeFlag::ETS_OBJECT), + name_(name), + assemblerName_(assemblerName), + declNode_(declNode), + properties_(allocator->Adapter()), + constructSignatures_(allocator->Adapter()), + interfaces_(allocator->Adapter()), + flags_(flags), + instantiationMap_(allocator->Adapter()), + typeArguments_(allocator->Adapter()) + { + } + + void AddProperty(binder::LocalVariable *prop) + { + properties_.insert({prop->Name(), prop}); + } + + void AddConstructSignature(Signature *signature) + { + constructSignatures_.push_back(signature); + } + + void AddConstructSignature(const ArenaVector &signatures) + { + constructSignatures_.insert(constructSignatures_.end(), signatures.cbegin(), signatures.cend()); + } + + void AddInterface(ETSObjectType *interface) + { + interfaces_.push_back(interface); + } + + void SetSuperType(ETSObjectType *super) + { + superType_ = super; + } + + void SetTypeArguments(ArenaVector &&typeArgs) + { + typeArguments_ = std::move(typeArgs); + } + + void SetEnclosingType(ETSObjectType *enclosingType) + { + enclosingType_ = enclosingType; + } + + binder::LocalVariable *GetProperty(const util::StringView &name, PropertySearchFlags flags) const; + + const ArenaUnorderedMap &Properties() const + { + return properties_; + } + + ArenaUnorderedMap &Properties() + { + return properties_; + } + + const ArenaVector &TypeArguments() const + { + return typeArguments_; + } + + ArenaVector &TypeArguments() + { + return typeArguments_; + } + + const ArenaVector &ConstructSignatures() const + { + return constructSignatures_; + } + + ArenaVector &ConstructSignatures() + { + return constructSignatures_; + } + + const ArenaVector &Interfaces() const + { + return interfaces_; + } + + ArenaVector &Interfaces() + { + return interfaces_; + } + + ir::AstNode *GetDeclNode() const + { + return declNode_; + } + + const ETSObjectType *SuperType() const + { + return superType_; + } + + ETSObjectType *SuperType() + { + return superType_; + } + + const ETSObjectType *EnclosingType() const + { + return enclosingType_; + } + + ETSObjectType *EnclosingType() + { + return enclosingType_; + } + + ETSObjectType *OutermostClass() + { + auto *iter = enclosingType_; + + while (iter && iter->EnclosingType()) { + iter = iter->EnclosingType(); + } + + return iter; + } + + bool IsPropertyInherited(binder::Variable *var) + { + if (var->HasFlag(binder::VariableFlags::PRIVATE)) { + return GetProperty(var->Name(), PropertySearchFlags::NO_OPTS) == var; + } + + return true; + } + + bool IsSignatureInherited(Signature *signature) + { + if (signature->HasSignatureFlag(SignatureFlags::PRIVATE)) { + return signature->Owner() == this; + } + + return true; + } + + const util::StringView &Name() const + { + return name_; + } + + const util::StringView &AssemblerName() const + { + return assemblerName_; + } + + ETSObjectFlags ObjectFlags() const + { + return flags_; + } + + void AddObjectFlag(ETSObjectFlags flag) + { + flags_ |= flag; + } + + void RemoveObjectFlag(ETSObjectFlags flag) + { + flags_ &= ~flag; + } + + bool HasObjectFlag(ETSObjectFlags flag) const + { + return (flags_ & flag) != 0; + } + + ETSObjectFlags BuiltInKind() + { + return static_cast(flags_ & ETSObjectFlags::BUILTIN_TYPE); + } + + ETSObjectType *GetInstantiatedType(util::StringView hash) + { + auto found = instantiationMap_.find(hash); + + if (found != instantiationMap_.end()) { + return found->second; + } + + return nullptr; + } + + InstantiationMap &GetInstantiationMap() + { + return instantiationMap_; + } + + std::vector ForeignProperties() const; + + void Iterate(const PropertyTraverser &cb) const; + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + bool AssignmentSource(TypeRelation *relation, Type *target) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + void IsSubtype(TypeRelation *relation, Type *source) override; + Type *AsSuper(Checker *checker, binder::Variable *sourceVar) override; + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << assemblerName_; + } + +private: + std::unordered_map CollectAllProperties() const; + + util::StringView name_; + util::StringView assemblerName_; + ir::AstNode *declNode_; + PropertyMap properties_; + ArenaVector constructSignatures_; + ArenaVector interfaces_; + ETSObjectFlags flags_; + InstantiationMap instantiationMap_; + ArenaVector typeArguments_; + ETSObjectType *superType_ {}; + ETSObjectType *enclosingType_ {}; +}; +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_FUNCTION_TYPE_H */ diff --git a/checker/types/ets/etsStringType.cpp b/checker/types/ets/etsStringType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1043ebf984cf15487e377a38d5bd04f0e47908d5 --- /dev/null +++ b/checker/types/ets/etsStringType.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "etsStringType.h" + +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" + +namespace panda::es2panda::checker { +void ETSStringType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsETSStringType()) { + relation->Result(true); + } +} + +void ETSStringType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) +{ + if (source->IsETSStringType()) { + relation->Result(true); + } +} + +Type *ETSStringType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsStringType.h b/checker/types/ets/etsStringType.h new file mode 100644 index 0000000000000000000000000000000000000000..9c791744560d2a987a4c634513dded5b9c6f4e6a --- /dev/null +++ b/checker/types/ets/etsStringType.h @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_STRING_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_STRING_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" + +namespace panda::es2panda::checker { +class ETSStringType : public ETSObjectType { +public: + explicit ETSStringType(ArenaAllocator *allocator, [[maybe_unused]] ETSObjectType *super) + : ETSObjectType(allocator, ETSObjectFlags::CLASS | ETSObjectFlags::STRING | ETSObjectFlags::RESOLVED_SUPER) + { + SetSuperType(super); + } + + explicit ETSStringType(ArenaAllocator *allocator, ETSObjectType *super, util::StringView value) + : ETSObjectType(allocator, ETSObjectFlags::CLASS | ETSObjectFlags::STRING | ETSObjectFlags::RESOLVED_SUPER), + value_(value) + { + SetSuperType(super); + AddTypeFlag(TypeFlag::CONSTANT); + variable_ = super->Variable(); + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "string"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::BUILTIN_STRING; + } + + util::StringView GetValue() const + { + return value_; + } + +private: + util::StringView value_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/etsTypeParameter.cpp b/checker/types/ets/etsTypeParameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a98ab157c2bb1e85ab5c5f7ef8fda84a4fcb060 --- /dev/null +++ b/checker/types/ets/etsTypeParameter.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "etsTypeParameter.h" + +namespace panda::es2panda::checker { +void ETSTypeParameter::ToString([[maybe_unused]] std::stringstream &ss) const +{ + UNREACHABLE(); +} + +void ETSTypeParameter::Identical([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *other) +{ + UNREACHABLE(); +} + +void ETSTypeParameter::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) +{ + UNREACHABLE(); +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsTypeParameter.h b/checker/types/ets/etsTypeParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..a085f1be09bb634ae39ea8f7a10b1476bc0e9c4a --- /dev/null +++ b/checker/types/ets/etsTypeParameter.h @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_TYPE_PARAMETER_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_TYPE_PARAMETER_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ETSTypeParameter : public Type { +public: + explicit ETSTypeParameter() : Type(TypeFlag::ETS_TYPE_PARAMETER) {} + explicit ETSTypeParameter(Type *assemblerType) : Type(TypeFlag::ETS_TYPE_PARAMETER), assemblerType_(assemblerType) + { + } + + void SetType(Type *type) + { + type_ = type; + } + + Type *GetType() + { + return type_; + } + + Type *GetAssemblerType() + { + return assemblerType_; + } + + Type **GetTypeRef() + { + return &type_; + } + + Type **GetAssemblerTypeRef() + { + return &assemblerType_; + } + + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + +private: + Type *type_ {}; + Type *assemblerType_ {}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/etsTypeReference.cpp b/checker/types/ets/etsTypeReference.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bdc842e10a2908f144f8d62566cd8d71f8db513f --- /dev/null +++ b/checker/types/ets/etsTypeReference.cpp @@ -0,0 +1,85 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "etsTypeReference.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { + +util::StringView ETSTypeReference::ReferencedName() const +{ + return varRef_->Name(); +} + +void ETSTypeReference::ToString(std::stringstream &ss) const +{ + ss << ReferencedName(); +} + +void ETSTypeReference::ToAssemblerType(std::stringstream &ss) const +{ + ASSERT(*assemblerRef_); + (*assemblerRef_)->ToAssemblerType(ss); +} + +void ETSTypeReference::Identical(TypeRelation *relation, Type *other) +{ + if (*ref_) { + (*ref_)->Identical(relation, other); + return; + } + + if (!other->IsETSTypeReference()) { + return; + } + + relation->Result(varRef_ == other->AsETSTypeReference()->VarRef()); +} + +void ETSTypeReference::AssignmentTarget(TypeRelation *relation, Type *source) +{ + if (*ref_) { + (*ref_)->AssignmentTarget(relation, source); + } +} + +bool ETSTypeReference::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) +{ + if (!(*ref_)) { + return false; + } + + if (!target->IsETSTypeReference()) { + return true; + } + + if (!relation->IsAssignableTo(this, target)) { + return true; + } + + relation->Result(true); + return false; +} + +Type *ETSTypeReference::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) +{ + if (*ref_) { + return (*ref_)->Instantiate(allocator, relation, globalTypes); + } + + return relation->GetChecker()->AsETSChecker()->CreateTypeReference(ref_, assemblerRef_, varRef_); +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/etsTypeReference.h b/checker/types/ets/etsTypeReference.h new file mode 100644 index 0000000000000000000000000000000000000000..90c0764d47cd529f0d91baaf365ffb07baedc0d4 --- /dev/null +++ b/checker/types/ets/etsTypeReference.h @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_TYPE_REFERENCE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_TYPE_REFERENCE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::binder { +class LocalVariable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::checker { +class ETSTypeReference : public Type { +public: + explicit ETSTypeReference(Type **ref, Type **assemblerRef, binder::LocalVariable *varRef) + : Type(TypeFlag::ETS_TYPE_REFERENCE), ref_(ref), assemblerRef_(assemblerRef), varRef_(varRef) + { + } + + Type *Ref() + { + return *ref_; + } + + const Type *Ref() const + { + return *ref_; + } + + binder::LocalVariable *VarRef() + { + return varRef_; + } + + const binder::LocalVariable *VarRef() const + { + return varRef_; + } + + util::StringView ReferencedName() const; + + void ToString(std::stringstream &ss) const override; + void ToAssemblerType(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + bool AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *target) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + +private: + Type **ref_; + Type **assemblerRef_; + binder::LocalVariable *varRef_ {}; +}; +} // namespace panda::es2panda::checker + +#endif /* ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H */ diff --git a/checker/types/ets/etsVoidType.cpp b/checker/types/ets/etsVoidType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a7dd3bb11cb4ad4ba0f817dcd883880fc5711fe --- /dev/null +++ b/checker/types/ets/etsVoidType.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "etsVoidType.h" + +namespace panda::es2panda::checker { +void ETSVoidType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsETSVoidType()) { + relation->Result(true); + } +} + +void ETSVoidType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *ETSVoidType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/lexer/templates/keywordsMap.h.erb b/checker/types/ets/etsVoidType.h similarity index 42% rename from lexer/templates/keywordsMap.h.erb rename to checker/types/ets/etsVoidType.h index 46d4cc8bb71168a2192318ccf6e2891e82176f48..7ebd9a25c61321f12d40fd8d4043b79c8c3bf557 100644 --- a/lexer/templates/keywordsMap.h.erb +++ b/checker/types/ets/etsVoidType.h @@ -13,37 +13,32 @@ * limitations under the License. */ -// Autogenerated file -- DO NOT EDIT! +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_VOID_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_VOID_TYPE_H -#include "plugins/ecmascript/es2panda/lexer/keywordString.h" -#include "utils/span.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" -namespace panda::es2panda::lexer { -class KeywordsMap { +namespace panda::es2panda::checker { +class ETSVoidType : public Type { public: - KeywordsMap() = delete; - - static Span Map(char32_t cp) { - switch(cp) { -% keywords.each do |group| - case LEX_CHAR_LOWERCASE_<%= group.keys[0][0].upcase %>: { - return Span(KEYWORDS_<%= group.keys[0][0].upcase %>); - } -% end - default: { - return Span(); - } - } + ETSVoidType() : Type(TypeFlag::ETS_VOID) {} + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "void"; } -% keywords.each do |group| + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_VOID; + } - static constexpr std::array> KEYWORDS_<%= group.keys[0][0].upcase %> = {{ -% group.each do |key, kw| - {"<%= key%>", <%= kw[0] %>, <%= kw[1] %>}, -% end - }}; -% end +private: }; +} // namespace panda::es2panda::checker -} // namespace panda::es2panda::lexer +#endif diff --git a/checker/types/ets/floatType.cpp b/checker/types/ets/floatType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eff5e7e093f2b05ea2c44745a5a3e168348706f9 --- /dev/null +++ b/checker/types/ets/floatType.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "floatType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingWideningConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +void FloatType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsFloatType()) { + relation->Result(true); + } +} + +void FloatType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +Type *FloatType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/floatType.h b/checker/types/ets/floatType.h new file mode 100644 index 0000000000000000000000000000000000000000..19b83a35679c3a1665d4db6346987ab68524cda2 --- /dev/null +++ b/checker/types/ets/floatType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_FLOAT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_FLOAT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class FloatType : public Type { +public: + using UType = float; + + FloatType() : Type(TypeFlag::FLOAT), size_(32) {} + FloatType(UType value) : Type(TypeFlag::FLOAT | TypeFlag::CONSTANT), size_(32), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "float"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_FLOAT; + } + +private: + size_t size_; + UType value_ {0.0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/intType.cpp b/checker/types/ets/intType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34486134318fa72ba6a8e76262f68277735d13bc --- /dev/null +++ b/checker/types/ets/intType.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "intType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingWideningConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +void IntType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsIntType()) { + relation->Result(true); + } +} + +void IntType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +Type *IntType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/intType.h b/checker/types/ets/intType.h new file mode 100644 index 0000000000000000000000000000000000000000..60c183b5e455e636d2ab661c4f855319ed26299f --- /dev/null +++ b/checker/types/ets/intType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_INT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_INT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class IntType : public Type { +public: + using UType = int32_t; + + IntType() : Type(TypeFlag::INT), size_(32) {} + IntType(UType value) : Type(TypeFlag::INT | TypeFlag::CONSTANT), size_(32), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "int"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_INT; + } + +private: + size_t size_; + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/longType.cpp b/checker/types/ets/longType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0aab6ca49137badc4ef110b248c4446e8380ac4 --- /dev/null +++ b/checker/types/ets/longType.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "longType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/typeConverter.h" +#include "plugins/ecmascript/es2panda/checker/ets/narrowingWideningConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +void LongType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsLongType()) { + relation->Result(true); + } +} + +void LongType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +Type *LongType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/longType.h b/checker/types/ets/longType.h new file mode 100644 index 0000000000000000000000000000000000000000..1e83cfa34b5dcae7889b92fc4d85180e4c793715 --- /dev/null +++ b/checker/types/ets/longType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_LONG_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_LONG_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class LongType : public Type { +public: + using UType = int64_t; + + LongType() : Type(TypeFlag::LONG), size_(64) {} + LongType(UType value) : Type(TypeFlag::LONG | TypeFlag::CONSTANT), size_(64), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "long"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_LONG; + } + +private: + size_t size_; + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/shortType.cpp b/checker/types/ets/shortType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf43132d1d495c0d3fa795bb173b23219d9e304e --- /dev/null +++ b/checker/types/ets/shortType.cpp @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "shortType.h" + +#include "plugins/ecmascript/es2panda/checker/ets/narrowingWideningConverter.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + +namespace panda::es2panda::checker { +void ShortType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsShortType()) { + relation->Result(true); + } +} + +void ShortType::AssignmentTarget(TypeRelation *relation, [[maybe_unused]] Type *source) +{ + NarrowingWideningConverter(relation->GetChecker()->AsETSChecker(), relation, this, source); +} + +Type *ShortType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/shortType.h b/checker/types/ets/shortType.h new file mode 100644 index 0000000000000000000000000000000000000000..89561137b4b23dd7b7d9bc2b2e808b328ae52464 --- /dev/null +++ b/checker/types/ets/shortType.h @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_SHORT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_SHORT_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class ShortType : public Type { +public: + using UType = int16_t; + + ShortType() : Type(TypeFlag::SHORT), size_(16) {} + ShortType(UType value) : Type(TypeFlag::SHORT | TypeFlag::CONSTANT), size_(16), value_(value) {} + + UType GetValue() const + { + return value_; + } + + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToString(std::stringstream &ss) const override + { + ss << "short"; + } + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << compiler::Signatures::PRIMITIVE_SHORT; + } + +private: + size_t size_; + UType value_ {0}; +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/checker/types/ets/types.h b/checker/types/ets/types.h new file mode 100644 index 0000000000000000000000000000000000000000..1065ba37679e3d9307be8205efadfe4e2e46d625 --- /dev/null +++ b/checker/types/ets/types.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_H + +#include "byteType.h" +#include "charType.h" +#include "doubleType.h" +#include "floatType.h" +#include "intType.h" +#include "longType.h" +#include "shortType.h" +#include "etsBooleanType.h" +#include "etsFunctionType.h" +#include "charType.h" +#include "etsVoidType.h" +#include "etsStringType.h" +#include "etsObjectType.h" +#include "etsArrayType.h" +#include "wildcardType.h" +#include "etsTypeReference.h" +#include "etsTypeParameter.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" + +#endif /* TYPES_H */ diff --git a/checker/types/ets/wildcardType.cpp b/checker/types/ets/wildcardType.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca8c974c8f3377960198601f2f93ab72895bb176 --- /dev/null +++ b/checker/types/ets/wildcardType.cpp @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "wildcardType.h" + +namespace panda::es2panda::checker { +void WildcardType::ToString(std::stringstream &ss) const +{ + ss << "wildcard"; +} + +void WildcardType::Identical(TypeRelation *relation, Type *other) +{ + if (other->IsWildcardType()) { + relation->Result(true); + } +} + +void WildcardType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *WildcardType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, + [[maybe_unused]] GlobalTypesHolder *globalTypes) +{ + return this; +} +} // namespace panda::es2panda::checker diff --git a/checker/types/ets/wildcardType.h b/checker/types/ets/wildcardType.h new file mode 100644 index 0000000000000000000000000000000000000000..a0b3df5a4e2adf33ba9af9558a63c676c6051737 --- /dev/null +++ b/checker/types/ets/wildcardType.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_ETS_WILDCARD_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_ETS_WILDCARD_TYPE_H + +#include "plugins/ecmascript/es2panda/checker/types/type.h" + +namespace panda::es2panda::checker { +class WildcardType : public Type { +public: + WildcardType() : Type(TypeFlag::WILDCARD) {} + + void ToString(std::stringstream &ss) const override; + void Identical(TypeRelation *relation, Type *other) override; + void AssignmentTarget(TypeRelation *relation, Type *source) override; + Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) override; + + void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const override + { + ss << "wildcard"; + } +}; +} // namespace panda::es2panda::checker + +#endif diff --git a/typescript/types/globalTypesHolder.cpp b/checker/types/globalTypesHolder.cpp similarity index 56% rename from typescript/types/globalTypesHolder.cpp rename to checker/types/globalTypesHolder.cpp index 0b0a4e0db0545ec103b24a78218e2b6e4c7eee06..eaafabedac32314f5504e247f8ea3ddf235b557d 100644 --- a/typescript/types/globalTypesHolder.cpp +++ b/checker/types/globalTypesHolder.cpp @@ -15,28 +15,41 @@ #include "globalTypesHolder.h" -#include "plugins/ecmascript/es2panda/typescript/types/numberType.h" -#include "plugins/ecmascript/es2panda/typescript/types/anyType.h" -#include "plugins/ecmascript/es2panda/typescript/types/stringType.h" -#include "plugins/ecmascript/es2panda/typescript/types/booleanType.h" -#include "plugins/ecmascript/es2panda/typescript/types/voidType.h" -#include "plugins/ecmascript/es2panda/typescript/types/nullType.h" -#include "plugins/ecmascript/es2panda/typescript/types/undefinedType.h" -#include "plugins/ecmascript/es2panda/typescript/types/unknownType.h" -#include "plugins/ecmascript/es2panda/typescript/types/neverType.h" -#include "plugins/ecmascript/es2panda/typescript/types/nonPrimitiveType.h" -#include "plugins/ecmascript/es2panda/typescript/types/bigintType.h" -#include "plugins/ecmascript/es2panda/typescript/types/booleanLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/bigintLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/numberLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/stringLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/tupleType.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectLiteralType.h" -#include "plugins/ecmascript/es2panda/typescript/types/unionType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/numberType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/anyType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/stringType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/booleanType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/voidType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/nullType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/undefinedType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/unknownType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/neverType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/nonPrimitiveType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/bigintType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/booleanLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/bigintLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/numberLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/stringLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/tupleType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectLiteralType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/unionType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/byteType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/charType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/doubleType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/floatType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/intType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/longType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/shortType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsBooleanType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsStringType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsVoidType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/wildcardType.h" namespace panda::es2panda::checker { GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) { + // TS specific types globalTypes_[static_cast(GlobalTypeId::NUMBER)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::ANY)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::STRING)] = allocator->New(); @@ -65,6 +78,24 @@ GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) globalTypes_[static_cast(GlobalTypeId::EMPTY_OBJECT)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::RESOLVING_RETURN_TYPE)] = allocator->New(); globalTypes_[static_cast(GlobalTypeId::ERROR_TYPE)] = allocator->New(); + + // ETS specific types + globalTypes_[static_cast(GlobalTypeId::BYTE)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::SHORT)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::INT)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::LONG)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::FLOAT)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::DOUBLE)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::CHAR)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::ETS_BOOLEAN)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::ETS_VOID)] = allocator->New(); + globalTypes_[static_cast(GlobalTypeId::ETS_OBJECT)] = allocator->New(allocator); + + auto *globalNullType = allocator->New(allocator); + globalNullType->AsETSObjectType()->AddObjectFlag(ETSObjectFlags::NULL_TYPE); + globalTypes_[static_cast(GlobalTypeId::ETS_NULL)] = globalNullType; + + globalTypes_[static_cast(GlobalTypeId::ETS_WILDCARD)] = allocator->New(); } Type *GlobalTypesHolder::GlobalNumberType() @@ -181,4 +212,69 @@ Type *GlobalTypesHolder::GlobalErrorType() { return globalTypes_.at(static_cast(GlobalTypeId::ERROR_TYPE)); } + +Type *GlobalTypesHolder::GlobalByteType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::BYTE)); +} + +Type *GlobalTypesHolder::GlobalShortType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::SHORT)); +} + +Type *GlobalTypesHolder::GlobalIntType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::INT)); +} + +Type *GlobalTypesHolder::GlobalLongType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::LONG)); +} + +Type *GlobalTypesHolder::GlobalFloatType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::FLOAT)); +} + +Type *GlobalTypesHolder::GlobalDoubleType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::DOUBLE)); +} + +Type *GlobalTypesHolder::GlobalCharType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::CHAR)); +} + +Type *GlobalTypesHolder::GlobalETSBooleanType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_BOOLEAN)); +} + +Type *GlobalTypesHolder::GlobalETSStringType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_STRING)); +} + +Type *GlobalTypesHolder::GlobalETSVoidType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_VOID)); +} + +Type *GlobalTypesHolder::GlobalETSObjectType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_OBJECT)); +} + +Type *GlobalTypesHolder::GlobalETSNullType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_NULL)); +} + +Type *GlobalTypesHolder::GLobalWildcardType() +{ + return globalTypes_.at(static_cast(GlobalTypeId::ETS_WILDCARD)); +} } // namespace panda::es2panda::checker diff --git a/typescript/types/globalTypesHolder.h b/checker/types/globalTypesHolder.h similarity index 64% rename from typescript/types/globalTypesHolder.h rename to checker/types/globalTypesHolder.h index 6981d5da7c6a01cc0314314770aba7a136b66517..396e41a9fd671242319d9fbd3c5f036c54c5ddbf 100644 --- a/typescript/types/globalTypesHolder.h +++ b/checker/types/globalTypesHolder.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_GLOBAL_TYPES_HOLDER_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_GLOBAL_TYPES_HOLDER_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_GLOBAL_TYPES_HOLDER_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_GLOBAL_TYPES_HOLDER_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { enum class GlobalTypeId { @@ -43,7 +43,20 @@ enum class GlobalTypeId { EMPTY_OBJECT, RESOLVING_RETURN_TYPE, ERROR_TYPE, - COUNT + BYTE, + SHORT, + INT, + LONG, + FLOAT, + DOUBLE, + CHAR, + ETS_BOOLEAN, + ETS_STRING, + ETS_VOID, + ETS_OBJECT, + ETS_NULL, + ETS_WILDCARD, + COUNT, }; class GlobalTypesHolder { @@ -53,6 +66,7 @@ public: NO_COPY_SEMANTIC(GlobalTypesHolder); NO_MOVE_SEMANTIC(GlobalTypesHolder); + // TS specific types Type *GlobalNumberType(); Type *GlobalAnyType(); Type *GlobalStringType(); @@ -77,9 +91,36 @@ public: Type *GlobalResolvingReturnType(); Type *GlobalErrorType(); + // ETS specific types + Type *GlobalByteType(); + Type *GlobalShortType(); + Type *GlobalIntType(); + Type *GlobalLongType(); + Type *GlobalFloatType(); + Type *GlobalDoubleType(); + Type *GlobalCharType(); + Type *GlobalETSBooleanType(); + Type *GlobalETSStringType(); + Type *GlobalETSVoidType(); + Type *GlobalETSObjectType(); + Type *GlobalETSNullType(); + Type *GLobalWildcardType(); + + using Holder = std::array(GlobalTypeId::COUNT)>; + + Holder &GlobalTypes() + { + return globalTypes_; + } + + const Holder &GlobalTypes() const + { + return globalTypes_; + } + private: - std::array(GlobalTypeId::COUNT)> globalTypes_ {}; + Holder globalTypes_ {}; }; } // namespace panda::es2panda::checker -#endif /* ES2PANDA_COMPILER_TYPESCRIPT_TYPES_GLOBAL_TYPES_HOLDER_H */ +#endif /* ES2PANDA_COMPILER_CHECKER_TYPES_TS_GLOBAL_TYPES_HOLDER_H */ diff --git a/typescript/types/signature.cpp b/checker/types/signature.cpp similarity index 81% rename from typescript/types/signature.cpp rename to checker/types/signature.cpp index 80140201dee63f0a928e8940b0480e69d1a15fba..a9aa5785d0b7e9e890bff24fbe5b7ef43149f8f3 100644 --- a/typescript/types/signature.cpp +++ b/checker/types/signature.cpp @@ -15,18 +15,29 @@ #include "signature.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" + namespace panda::es2panda::checker { + +util::StringView Signature::InternalName() const +{ + return internalName_.Empty() ? func_->Scope()->InternalName() : internalName_; +} + Signature *Signature::Copy(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) { - checker::SignatureInfo *copiedInfo = allocator->New(signatureInfo_, allocator); + SignatureInfo *copiedInfo = allocator->New(signatureInfo_, allocator); - for (auto *it : copiedInfo->params) { - it->SetTsType(it->TsType()->Instantiate(allocator, relation, globalTypes)); + for (size_t idx = 0; idx < signatureInfo_->params.size(); idx++) { + copiedInfo->params[idx]->SetTsType( + ETSChecker::TryToInstantiate(signatureInfo_->params[idx]->TsType(), allocator, relation, globalTypes)); } - Type *copiedReturnType = returnType_->Instantiate(allocator, relation, globalTypes); + Type *copiedReturnType = ETSChecker::TryToInstantiate(returnType_, allocator, relation, globalTypes); - return allocator->New(copiedInfo, copiedReturnType); + return allocator->New(copiedInfo, copiedReturnType, func_); } void Signature::ToString(std::stringstream &ss, const binder::Variable *variable, bool printAsMethod) const @@ -80,7 +91,11 @@ void Signature::Identical(TypeRelation *relation, Signature *other) return; } - relation->IsIdenticalTo(returnType_, other->ReturnType()); + if (relation->NoReturnTypeCheck()) { + relation->Result(true); + } else { + relation->IsIdenticalTo(returnType_, other->ReturnType()); + } if (relation->IsTrue()) { for (uint64_t i = 0; i < signatureInfo_->params.size(); i++) { diff --git a/typescript/types/signature.h b/checker/types/signature.h similarity index 59% rename from typescript/types/signature.h rename to checker/types/signature.h index ea843d456cd778d4791374596e8388de36fb63c1..396a92443614affa67341f84d7cec5eca7f92acc 100644 --- a/typescript/types/signature.h +++ b/checker/types/signature.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_SIGNATURE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_SIGNATURE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_SIGNATURE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_SIGNATURE_H #include "type.h" @@ -49,12 +49,37 @@ public: // NOLINTEND(misc-non-private-member-variables-in-classes) }; +enum class SignatureFlags { + NO_OPTS = 0, + VIRTUAL = 1 << 0, + ABSTRACT = 1 << 1, + CALL = 1 << 2, + CONSTRUCT = 1 << 3, + PUBLIC = 1 << 4, + PROTECTED = 1 << 5, + PRIVATE = 1 << 6, + STATIC = 1 << 7, + OPEN = 1 << 8, +}; + +DEFINE_BITOPS(SignatureFlags) + class Signature { public: Signature(SignatureInfo *signature_info, Type *returnType) : signatureInfo_(signature_info), returnType_(returnType) { } + Signature(SignatureInfo *signature_info, Type *returnType, util::StringView internalName) + : signatureInfo_(signature_info), returnType_(returnType), internalName_(internalName) + { + } + + Signature(SignatureInfo *signature_info, Type *returnType, ir::ScriptFunction *func) + : signatureInfo_(signature_info), returnType_(returnType), func_(func) + { + } + ~Signature() = default; NO_COPY_SEMANTIC(Signature); NO_MOVE_SEMANTIC(Signature); @@ -94,14 +119,24 @@ public: returnType_ = type; } - void SetNode(const ir::AstNode *node) + void SetOwner(ETSObjectType *owner) { - node_ = node; + ownerObj_ = owner; } - const ir::AstNode *Node() const + ir::ScriptFunction *Function() { - return node_; + return func_; + } + + ETSObjectType *Owner() + { + return ownerObj_; + } + + const ir::ScriptFunction *Function() const + { + return func_; } const binder::LocalVariable *RestVar() const @@ -109,6 +144,49 @@ public: return signatureInfo_->restVar; } + uint8_t ProtectionFlag() const + { + if (flags_ & SignatureFlags::PRIVATE) { + return 2; + } + + if (flags_ & SignatureFlags::PROTECTED) { + return 1; + } + + return 0; + } + + void AddSignatureFlag(SignatureFlags flag) + { + flags_ |= flag; + } + + void RemoveSignatureFlag(SignatureFlags flag) + { + flags_ &= ~flag; + } + + bool HasSignatureFlag(SignatureFlags flag) const + { + return (flags_ & flag) != 0; + } + + void ToAssemblerType(std::stringstream &ss) const + { + ss << compiler::Signatures::MANGLE_BEGIN; + + for (const auto *param : signatureInfo_->params) { + param->TsType()->ToAssemblerType(ss); + ss << compiler::Signatures::MANGLE_SEPARATOR; + } + + returnType_->ToAssemblerType(ss); + ss << compiler::Signatures::MANGLE_SEPARATOR; + } + + util::StringView InternalName() const; + Signature *Copy(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes); void ToString(std::stringstream &ss, const binder::Variable *variable, bool printAsMethod = false) const; @@ -118,7 +196,10 @@ public: private: checker::SignatureInfo *signatureInfo_; Type *returnType_; - const ir::AstNode *node_ {}; + ir::ScriptFunction *func_ {}; + SignatureFlags flags_ {SignatureFlags::NO_OPTS}; + util::StringView internalName_ {}; + ETSObjectType *ownerObj_ {}; }; } // namespace panda::es2panda::checker diff --git a/typescript/types/anyType.cpp b/checker/types/ts/anyType.cpp similarity index 100% rename from typescript/types/anyType.cpp rename to checker/types/ts/anyType.cpp diff --git a/typescript/types/anyType.h b/checker/types/ts/anyType.h similarity index 87% rename from typescript/types/anyType.h rename to checker/types/ts/anyType.h index 8105bebf3d2fac2c932a07697de33c69ee32ef4e..76c38e62e2c0dd7b8e71f5247a05362a4e321aaf 100644 --- a/typescript/types/anyType.h +++ b/checker/types/ts/anyType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ANY_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ANY_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ANY_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ANY_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class AnyType : public Type { @@ -32,4 +32,4 @@ public: }; } // namespace panda::es2panda::checker -#endif /* TYPESCRIPT_TYPES_ANY_TYPE_H */ +#endif diff --git a/typescript/types/arrayType.cpp b/checker/types/ts/arrayType.cpp similarity index 96% rename from typescript/types/arrayType.cpp rename to checker/types/ts/arrayType.cpp index 78d10551309e3615db6ecd83954032757cb976d7..90deba9dcec39cc2a4a06579d7a7b8397c9f52a8 100644 --- a/typescript/types/arrayType.cpp +++ b/checker/types/ts/arrayType.cpp @@ -16,7 +16,7 @@ #include "arrayType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectType.h" namespace panda::es2panda::checker { void ArrayType::ToString(std::stringstream &ss) const diff --git a/typescript/types/arrayType.h b/checker/types/ts/arrayType.h similarity index 89% rename from typescript/types/arrayType.h rename to checker/types/ts/arrayType.h index 4e28e70f87da6e2fc62562c4b1e3cf939495bae3..27e61711aed3b01c1441b98639ddc3fab0fefe76 100644 --- a/typescript/types/arrayType.h +++ b/checker/types/ts/arrayType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ARRAY_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ARRAY_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ARRAY_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ARRAY_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class ArrayType : public Type { diff --git a/typescript/types/bigintLiteralType.cpp b/checker/types/ts/bigintLiteralType.cpp similarity index 100% rename from typescript/types/bigintLiteralType.cpp rename to checker/types/ts/bigintLiteralType.cpp diff --git a/typescript/types/bigintLiteralType.h b/checker/types/ts/bigintLiteralType.h similarity index 89% rename from typescript/types/bigintLiteralType.h rename to checker/types/ts/bigintLiteralType.h index aef7b39c946270b9ce40b4d669237a09c9ccd35a..f0fd4b1f5aab1fc17ccd3acac17ec73138dd9b6e 100644 --- a/typescript/types/bigintLiteralType.h +++ b/checker/types/ts/bigintLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BigintLiteralType : public Type { diff --git a/typescript/types/bigintType.cpp b/checker/types/ts/bigintType.cpp similarity index 100% rename from typescript/types/bigintType.cpp rename to checker/types/ts/bigintType.cpp diff --git a/typescript/types/bigintType.h b/checker/types/ts/bigintType.h similarity index 87% rename from typescript/types/bigintType.h rename to checker/types/ts/bigintType.h index d3022f3cce285e5d89fe82d5c6a1e477aef09f8f..07636b22d9af4d8e4d798fd6c22bf820ec0daa87 100644 --- a/typescript/types/bigintType.h +++ b/checker/types/ts/bigintType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BIGINT_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BIGINT_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BigintType : public Type { diff --git a/typescript/types/booleanLiteralType.cpp b/checker/types/ts/booleanLiteralType.cpp similarity index 100% rename from typescript/types/booleanLiteralType.cpp rename to checker/types/ts/booleanLiteralType.cpp diff --git a/typescript/types/booleanLiteralType.h b/checker/types/ts/booleanLiteralType.h similarity index 88% rename from typescript/types/booleanLiteralType.h rename to checker/types/ts/booleanLiteralType.h index 8f7b46c3bd097e58706d986998b68a3b736bc168..f10bfc2dddb1d0578377987be639a4cb49ef3822 100644 --- a/typescript/types/booleanLiteralType.h +++ b/checker/types/ts/booleanLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BooleanLiteralType : public Type { diff --git a/typescript/types/booleanType.cpp b/checker/types/ts/booleanType.cpp similarity index 100% rename from typescript/types/booleanType.cpp rename to checker/types/ts/booleanType.cpp diff --git a/typescript/types/booleanType.h b/checker/types/ts/booleanType.h similarity index 87% rename from typescript/types/booleanType.h rename to checker/types/ts/booleanType.h index 463b5c596ebcde2a9ad0723dbc5505ae5d4e8295..e16b95c68df31635ed687e66a56e1839ac53e33b 100644 --- a/typescript/types/booleanType.h +++ b/checker/types/ts/booleanType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_BOOLEAN_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_BOOLEAN_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class BooleanType : public Type { diff --git a/typescript/types/constructorType.cpp b/checker/types/ts/constructorType.cpp similarity index 95% rename from typescript/types/constructorType.cpp rename to checker/types/ts/constructorType.cpp index 15edc26fdf47ac831356bee877f17f1770c3f553..3af66bc5a91bcdbcb86601254079cb4e9787e90e 100644 --- a/typescript/types/constructorType.cpp +++ b/checker/types/ts/constructorType.cpp @@ -15,7 +15,7 @@ #include "constructorType.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { void ConstructorType::ToString(std::stringstream &ss) const diff --git a/typescript/types/constructorType.h b/checker/types/ts/constructorType.h similarity index 90% rename from typescript/types/constructorType.h rename to checker/types/ts/constructorType.h index 0776b2f193004da160a744769e3c83c2a3b5342d..4c930cee425ce0e369eee677a3dd9dc3867c3c02 100644 --- a/typescript/types/constructorType.h +++ b/checker/types/ts/constructorType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_CONSTRUCTOR_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_CONSTRUCTOR_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_CONSTRUCTOR_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_CONSTRUCTOR_TYPE_H #include "objectType.h" diff --git a/typescript/types/elementFlags.h b/checker/types/ts/elementFlags.h similarity index 90% rename from typescript/types/elementFlags.h rename to checker/types/ts/elementFlags.h index dba25576772509a4917428825d2b2089505178f4..2ced2a12251dc4344d80ec0c2d0563a9253e372d 100644 --- a/typescript/types/elementFlags.h +++ b/checker/types/ts/elementFlags.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ELEMENT_FLAGS_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ELEMENT_FLAGS_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ELEMENT_FLAGS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ELEMENT_FLAGS_H #include "plugins/ecmascript/es2panda/util/enumbitops.h" diff --git a/typescript/types/enumLiteralType.cpp b/checker/types/ts/enumLiteralType.cpp similarity index 96% rename from typescript/types/enumLiteralType.cpp rename to checker/types/ts/enumLiteralType.cpp index 79984a9e32661057121f220fcf9734694ac7e4dd..f6b7bc3ce6ca41c2cef8bdd709c7f723c75c7aca 100644 --- a/typescript/types/enumLiteralType.cpp +++ b/checker/types/ts/enumLiteralType.cpp @@ -16,7 +16,7 @@ #include "enumLiteralType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/enumType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/enumType.h" namespace panda::es2panda::checker { void EnumLiteralType::ToString(std::stringstream &ss) const diff --git a/typescript/types/enumLiteralType.h b/checker/types/ts/enumLiteralType.h similarity index 90% rename from typescript/types/enumLiteralType.h rename to checker/types/ts/enumLiteralType.h index 1b601a2c4d15262755aa8003f01b4255ac1f2c39..a0ddeb725d36e97e3a8705c8a1ad1927fad01a01 100644 --- a/typescript/types/enumLiteralType.h +++ b/checker/types/ts/enumLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::binder { class Scope; diff --git a/typescript/types/enumType.cpp b/checker/types/ts/enumType.cpp similarity index 100% rename from typescript/types/enumType.cpp rename to checker/types/ts/enumType.cpp diff --git a/typescript/types/enumType.h b/checker/types/ts/enumType.h similarity index 90% rename from typescript/types/enumType.h rename to checker/types/ts/enumType.h index 2c8cf92f81c9f5a72466590bdbc7af79af9b06cf..1a06fb73103f080b108979faee20237c1943a678 100644 --- a/typescript/types/enumType.h +++ b/checker/types/ts/enumType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_ENUM_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_ENUM_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::binder { class EnumVariable; diff --git a/typescript/types/functionType.cpp b/checker/types/ts/functionType.cpp similarity index 96% rename from typescript/types/functionType.cpp rename to checker/types/ts/functionType.cpp index 274dceefc78a31f0a282d67e5160d40e607dcd29..d3748baf39a03d71cd0cfd04610a69862d87eee4 100644 --- a/typescript/types/functionType.cpp +++ b/checker/types/ts/functionType.cpp @@ -15,7 +15,7 @@ #include "functionType.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { void FunctionType::ToString(std::stringstream &ss) const diff --git a/typescript/types/functionType.h b/checker/types/ts/functionType.h similarity index 90% rename from typescript/types/functionType.h rename to checker/types/ts/functionType.h index 4527c6b99d990db49391de168eef8d164ddb8639..f1b465a54bf29dc70687363036581e95c8d9aac3 100644 --- a/typescript/types/functionType.h +++ b/checker/types/ts/functionType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_FUNCTION_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_FUNCTION_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_FUNCTION_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_FUNCTION_TYPE_H #include #include "objectType.h" diff --git a/typescript/types/indexInfo.cpp b/checker/types/ts/indexInfo.cpp similarity index 100% rename from typescript/types/indexInfo.cpp rename to checker/types/ts/indexInfo.cpp diff --git a/typescript/types/indexInfo.h b/checker/types/ts/indexInfo.h similarity index 92% rename from typescript/types/indexInfo.h rename to checker/types/ts/indexInfo.h index 111079a3b2b0088cc01a184758cbc2773908bd15..79e252ebcc013646fe3405e2ea82dc73c1f7daf6 100644 --- a/typescript/types/indexInfo.h +++ b/checker/types/ts/indexInfo.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INDEX_INFO_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INDEX_INFO_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_INDEX_INFO_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_INDEX_INFO_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class IndexInfo { diff --git a/typescript/types/interfaceType.cpp b/checker/types/ts/interfaceType.cpp similarity index 98% rename from typescript/types/interfaceType.cpp rename to checker/types/ts/interfaceType.cpp index f9f48b683e4cb305b8d18212d58e7afd972efa1d..2d093f1f7335737249c146ba0634280a51dc4789 100644 --- a/typescript/types/interfaceType.cpp +++ b/checker/types/ts/interfaceType.cpp @@ -16,8 +16,8 @@ #include "interfaceType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeParameter.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/typeParameter.h" #include #include diff --git a/typescript/types/interfaceType.h b/checker/types/ts/interfaceType.h similarity index 97% rename from typescript/types/interfaceType.h rename to checker/types/ts/interfaceType.h index 1788e719a66730147f4846cb82a8224618addbf7..d929906a047b34efac7b7755a61bb9be6a7b6115 100644 --- a/typescript/types/interfaceType.h +++ b/checker/types/ts/interfaceType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INTERFACE_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_INTERFACE_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_INTERFACE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_INTERFACE_TYPE_H #include "objectType.h" diff --git a/typescript/types/neverType.cpp b/checker/types/ts/neverType.cpp similarity index 100% rename from typescript/types/neverType.cpp rename to checker/types/ts/neverType.cpp diff --git a/typescript/types/neverType.h b/checker/types/ts/neverType.h similarity index 87% rename from typescript/types/neverType.h rename to checker/types/ts/neverType.h index d103dc77c7a56373bf927213e226cdb5078c209b..606e255f48a2cd6e507d4020e45eb1da4cee23ef 100644 --- a/typescript/types/neverType.h +++ b/checker/types/ts/neverType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NEVER_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NEVER_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NEVER_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NEVER_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NeverType : public Type { diff --git a/typescript/types/nonPrimitiveType.cpp b/checker/types/ts/nonPrimitiveType.cpp similarity index 100% rename from typescript/types/nonPrimitiveType.cpp rename to checker/types/ts/nonPrimitiveType.cpp diff --git a/typescript/types/nonPrimitiveType.h b/checker/types/ts/nonPrimitiveType.h similarity index 86% rename from typescript/types/nonPrimitiveType.h rename to checker/types/ts/nonPrimitiveType.h index ea646d161dbc88a12e2257c486b63b33d058c717..380aaa316788b4cc6cc6dbac0f75b40888bd9ab7 100644 --- a/typescript/types/nonPrimitiveType.h +++ b/checker/types/ts/nonPrimitiveType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NON_PRIMITIVE_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NON_PRIMITIVE_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NON_PRIMITIVE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NON_PRIMITIVE_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NonPrimitiveType : public Type { diff --git a/typescript/types/nullType.cpp b/checker/types/ts/nullType.cpp similarity index 100% rename from typescript/types/nullType.cpp rename to checker/types/ts/nullType.cpp diff --git a/typescript/types/nullType.h b/checker/types/ts/nullType.h similarity index 88% rename from typescript/types/nullType.h rename to checker/types/ts/nullType.h index 45f37fc480b5422cc9eb69b7c290fa46e71b4825..16b4a614cb7720d5f3ac9abd8f802aac14199956 100644 --- a/typescript/types/nullType.h +++ b/checker/types/ts/nullType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NULL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NULL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NULL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NULL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NullType : public Type { diff --git a/typescript/types/numberLiteralType.cpp b/checker/types/ts/numberLiteralType.cpp similarity index 96% rename from typescript/types/numberLiteralType.cpp rename to checker/types/ts/numberLiteralType.cpp index f72e6f6cd3d53d590db488ef941c79824bb47463..c94f81681957f84b2c831aedb939a730cb05c99c 100644 --- a/typescript/types/numberLiteralType.cpp +++ b/checker/types/ts/numberLiteralType.cpp @@ -17,7 +17,7 @@ #include "plugins/ecmascript/es2panda/util/helpers.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/enumType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/enumType.h" namespace panda::es2panda::checker { void NumberLiteralType::ToString(std::stringstream &ss) const diff --git a/typescript/types/numberLiteralType.h b/checker/types/ts/numberLiteralType.h similarity index 88% rename from typescript/types/numberLiteralType.h rename to checker/types/ts/numberLiteralType.h index e3c3a9a96e59395191c7094b2eaadef1847d6d60..b3c34d89830c857f12b1c91976f36a1d1c76af93 100644 --- a/typescript/types/numberLiteralType.h +++ b/checker/types/ts/numberLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NumberLiteralType : public Type { diff --git a/typescript/types/numberType.cpp b/checker/types/ts/numberType.cpp similarity index 96% rename from typescript/types/numberType.cpp rename to checker/types/ts/numberType.cpp index 0a89535ac400d56a021839a7b265bb3a93b8a05f..9381711f7c62d043395bac2a8074e5e1e447cfa8 100644 --- a/typescript/types/numberType.cpp +++ b/checker/types/ts/numberType.cpp @@ -16,7 +16,7 @@ #include "numberType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/enumType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/enumType.h" namespace panda::es2panda::checker { void NumberType::ToString(std::stringstream &ss) const diff --git a/typescript/types/numberType.h b/checker/types/ts/numberType.h similarity index 87% rename from typescript/types/numberType.h rename to checker/types/ts/numberType.h index 702417e7796f235ec3e8ab90d0a9e63429c8c9ce..f8505c863caf6500fea3a8081e3fbe6ea73b393a 100644 --- a/typescript/types/numberType.h +++ b/checker/types/ts/numberType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_NUMBER_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_NUMBER_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class NumberType : public Type { diff --git a/typescript/types/objectDescriptor.cpp b/checker/types/ts/objectDescriptor.cpp similarity index 93% rename from typescript/types/objectDescriptor.cpp rename to checker/types/ts/objectDescriptor.cpp index df7949ba5116a33edd1960d0969944ee32d19b31..6d9ec80ba95116d31e2ddd3b2e9e35264dc59740 100644 --- a/typescript/types/objectDescriptor.cpp +++ b/checker/types/ts/objectDescriptor.cpp @@ -16,8 +16,8 @@ #include "objectDescriptor.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { binder::LocalVariable *ObjectDescriptor::FindProperty(const util::StringView &name) const diff --git a/typescript/types/objectDescriptor.h b/checker/types/ts/objectDescriptor.h similarity index 93% rename from typescript/types/objectDescriptor.h rename to checker/types/ts/objectDescriptor.h index 1d1ba16e5aaab6b3ac9044069e6a8b63593e10d2..f852f50148240e0bcc7f13fa62a210a5ee2af9bf 100644 --- a/typescript/types/objectDescriptor.h +++ b/checker/types/ts/objectDescriptor.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_DESCRIPTOR_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_DESCRIPTOR_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_DESCRIPTOR_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_DESCRIPTOR_H #include "macros.h" #include "plugins/ecmascript/es2panda/util/ustring.h" diff --git a/typescript/types/objectLiteralType.cpp b/checker/types/ts/objectLiteralType.cpp similarity index 94% rename from typescript/types/objectLiteralType.cpp rename to checker/types/ts/objectLiteralType.cpp index 729940cd10cd974fc56eaf6ae0c63618b70a8410..7581f32896e955870a1c156bc5406894810defbb 100644 --- a/typescript/types/objectLiteralType.cpp +++ b/checker/types/ts/objectLiteralType.cpp @@ -16,11 +16,11 @@ #include "objectLiteralType.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { -class Checker; +class TSChecker; void ObjectLiteralType::ToString(std::stringstream &ss) const { diff --git a/typescript/types/objectLiteralType.h b/checker/types/ts/objectLiteralType.h similarity index 90% rename from typescript/types/objectLiteralType.h rename to checker/types/ts/objectLiteralType.h index a20328d7cc24b36b848d7d244ee3c4d39335fde9..e9b5695c1c07ce046180a7f0065239b2ee4f9b4f 100644 --- a/typescript/types/objectLiteralType.h +++ b/checker/types/ts/objectLiteralType.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_LITERAL_TYPE_H #include "objectType.h" diff --git a/typescript/types/objectType.cpp b/checker/types/ts/objectType.cpp similarity index 97% rename from typescript/types/objectType.cpp rename to checker/types/ts/objectType.cpp index 966a57af84fc0ac37001b6c38602e9764ae361dc..fd34d587312879684e5a1e0c0917bb37da26b7b8 100644 --- a/typescript/types/objectType.cpp +++ b/checker/types/ts/objectType.cpp @@ -15,10 +15,10 @@ #include "objectType.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/interfaceType.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/interfaceType.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" namespace panda::es2panda::checker { bool ObjectType::EachSignatureRelatedToSomeSignature(TypeRelation *relation, diff --git a/typescript/types/objectType.h b/checker/types/ts/objectType.h similarity index 93% rename from typescript/types/objectType.h rename to checker/types/ts/objectType.h index 0b07f5a262b090cd42471aa39296139ef70ad5c2..7160ff13ea3f8820282ab313adbdebcbe47653e8 100644 --- a/typescript/types/objectType.h +++ b/checker/types/ts/objectType.h @@ -13,12 +13,12 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_OBJECT_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_OBJECT_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectDescriptor.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectDescriptor.h" #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/util/ustring.h" #include "plugins/ecmascript/es2panda/util/enumbitops.h" @@ -62,7 +62,7 @@ public: #undef OBJECT_TYPE_IS_CHECKS // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define OBJECT_TYPE_AS_CASTS(objectKind, typeName) \ +#define OBJECT_TYPE_AS_CAETS(objectKind, typeName) \ typeName *As##typeName() \ { \ ASSERT(Is##typeName()); \ @@ -73,8 +73,8 @@ public: ASSERT(Is##typeName()); \ return reinterpret_cast(this); \ } - OBJECT_TYPE_MAPPING(OBJECT_TYPE_AS_CASTS) -#undef OBJECT_TYPE_AS_CASTS + OBJECT_TYPE_MAPPING(OBJECT_TYPE_AS_CAETS) +#undef OBJECT_TYPE_AS_CAETS explicit ObjectType(ObjectType::ObjectTypeKind kind) : Type(TypeFlag::OBJECT), kind_(kind) {} diff --git a/typescript/types/stringLiteralType.cpp b/checker/types/ts/stringLiteralType.cpp similarity index 100% rename from typescript/types/stringLiteralType.cpp rename to checker/types/ts/stringLiteralType.cpp diff --git a/typescript/types/stringLiteralType.h b/checker/types/ts/stringLiteralType.h similarity index 88% rename from typescript/types/stringLiteralType.h rename to checker/types/ts/stringLiteralType.h index 0c9c078260b85db4bf03e246dca11904c3e770a8..c4df8c8e409ab4e17506aae50bfbc86e4466c7d8 100644 --- a/typescript/types/stringLiteralType.h +++ b/checker/types/ts/stringLiteralType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_LITERAL_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_LITERAL_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_LITERAL_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_LITERAL_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class StringLiteralType : public Type { diff --git a/typescript/types/stringType.cpp b/checker/types/ts/stringType.cpp similarity index 100% rename from typescript/types/stringType.cpp rename to checker/types/ts/stringType.cpp diff --git a/typescript/types/stringType.h b/checker/types/ts/stringType.h similarity index 87% rename from typescript/types/stringType.h rename to checker/types/ts/stringType.h index 86e746e9666fd10964452cf69055f0bf4552e501..c21499b93d45715d421a35571c57ff563e67c03f 100644 --- a/typescript/types/stringType.h +++ b/checker/types/ts/stringType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_STRING_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_STRING_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class StringType : public Type { diff --git a/typescript/types/tupleType.cpp b/checker/types/ts/tupleType.cpp similarity index 97% rename from typescript/types/tupleType.cpp rename to checker/types/ts/tupleType.cpp index 4358db09c4fad1f86304340dfc38b7a0e8b7f1f8..e6830f28dcf07ab9ec48d89f90baadaf982ed411 100644 --- a/typescript/types/tupleType.cpp +++ b/checker/types/ts/tupleType.cpp @@ -15,10 +15,10 @@ #include "tupleType.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" namespace panda::es2panda::checker { -Type *TupleType::ConvertToArrayType(Checker *checker) +Type *TupleType::ConvertToArrayType(TSChecker *checker) { ArenaVector unionTypes(checker->Allocator()->Adapter()); diff --git a/typescript/types/tupleType.h b/checker/types/ts/tupleType.h similarity index 92% rename from typescript/types/tupleType.h rename to checker/types/ts/tupleType.h index b69978fcab37c1353ef4b5376a7ecf08a560ee66..3ee5d44a1d0e6fbdd076c1b36a32709b26b10737 100644 --- a/typescript/types/tupleType.h +++ b/checker/types/ts/tupleType.h @@ -13,14 +13,14 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TUPLE_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TUPLE_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_TUPLE_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_TUPLE_TYPE_H #include "macros.h" #include "plugins/ecmascript/es2panda/binder/variable.h" -#include "plugins/ecmascript/es2panda/typescript/types/elementFlags.h" -#include "plugins/ecmascript/es2panda/typescript/types/objectType.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/elementFlags.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/objectType.h" namespace panda::es2panda::checker { using NamedTupleMemberPool = std::unordered_map; @@ -101,7 +101,7 @@ public: return res->second; } - Type *ConvertToArrayType(Checker *checker); + Type *ConvertToArrayType(TSChecker *checker); void ToString(std::stringstream &ss) const override; void Identical(TypeRelation *relation, Type *other) override; diff --git a/typescript/types/typeParameter.cpp b/checker/types/ts/typeParameter.cpp similarity index 100% rename from typescript/types/typeParameter.cpp rename to checker/types/ts/typeParameter.cpp diff --git a/typescript/types/typeParameter.h b/checker/types/ts/typeParameter.h similarity index 90% rename from typescript/types/typeParameter.h rename to checker/types/ts/typeParameter.h index fe30e2cdc333e6d45986246aa5fcb9aec2237111..2b6a51dd20a6f28ff5fde96091f173c4fb00e87b 100644 --- a/typescript/types/typeParameter.h +++ b/checker/types/ts/typeParameter.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_PARAMETER_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_PARAMETER_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_PARAMETER_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_PARAMETER_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class TypeParameter : public Type { diff --git a/typescript/types/typeReference.cpp b/checker/types/ts/typeReference.cpp similarity index 100% rename from typescript/types/typeReference.cpp rename to checker/types/ts/typeReference.cpp diff --git a/typescript/types/typeReference.h b/checker/types/ts/typeReference.h similarity index 84% rename from typescript/types/typeReference.h rename to checker/types/ts/typeReference.h index aa90e1c700ff47acb8dc905d1a5cb2373be3d520..9b7c47f126cde25361368183afc9c7ffc902e981 100644 --- a/typescript/types/typeReference.h +++ b/checker/types/ts/typeReference.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_REFERENCE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_REFERENCE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class TypeReference : public Type { @@ -44,4 +44,4 @@ private: }; } // namespace panda::es2panda::checker -#endif /* ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_REFERENCE_H */ +#endif /* ES2PANDA_COMPILER_CHECKER_TYPES_TS_TYPE_REFERENCE_H */ diff --git a/typescript/types/types.h b/checker/types/ts/types.h similarity index 89% rename from typescript/types/types.h rename to checker/types/ts/types.h index 7b3d9810067b7606d298e2e23db021488b202cf8..404ed5af88d9253efcea8b90d187cfd1a7f6aba2 100644 --- a/typescript/types/types.h +++ b/checker/types/ts/types.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_H #include "anyType.h" #include "arrayType.h" @@ -42,8 +42,8 @@ #include "unknownType.h" #include "voidType.h" #include "indexInfo.h" -#include "signature.h" #include "typeParameter.h" #include "typeReference.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" #endif /* TYPES_H */ diff --git a/typescript/types/undefinedType.cpp b/checker/types/ts/undefinedType.cpp similarity index 100% rename from typescript/types/undefinedType.cpp rename to checker/types/ts/undefinedType.cpp diff --git a/typescript/types/undefinedType.h b/checker/types/ts/undefinedType.h similarity index 87% rename from typescript/types/undefinedType.h rename to checker/types/ts/undefinedType.h index 64cdef883017f9a6e22ad82444af5ef1a42085be..d58e4561f52d22da001ab8d71243b6f1ec2cf8ea 100644 --- a/typescript/types/undefinedType.h +++ b/checker/types/ts/undefinedType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNDEFINED_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNDEFINED_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNDEFINED_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNDEFINED_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class UndefinedType : public Type { diff --git a/typescript/types/unionType.cpp b/checker/types/ts/unionType.cpp similarity index 98% rename from typescript/types/unionType.cpp rename to checker/types/ts/unionType.cpp index 9bb413659e76d3d538991e696ec15e032fec5cb2..b408ae424aef0491bfb49ffb22e02d4837f8174a 100644 --- a/typescript/types/unionType.cpp +++ b/checker/types/ts/unionType.cpp @@ -16,7 +16,7 @@ #include "unionType.h" #include -#include "plugins/ecmascript/es2panda/typescript/types/globalTypesHolder.h" +#include "plugins/ecmascript/es2panda/checker/types/globalTypesHolder.h" namespace panda::es2panda::checker { void UnionType::ToString(std::stringstream &ss) const diff --git a/typescript/types/unionType.h b/checker/types/ts/unionType.h similarity index 96% rename from typescript/types/unionType.h rename to checker/types/ts/unionType.h index 70e1850176907212c3a48fe6eb4d1a4c39da1f2d..90222f83e57e3d1be8af4f226f85113284dbbcb9 100644 --- a/typescript/types/unionType.h +++ b/checker/types/ts/unionType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNION_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNION_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNION_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNION_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class GlobalTypesHolder; diff --git a/typescript/types/unknownType.cpp b/checker/types/ts/unknownType.cpp similarity index 100% rename from typescript/types/unknownType.cpp rename to checker/types/ts/unknownType.cpp diff --git a/typescript/types/unknownType.h b/checker/types/ts/unknownType.h similarity index 87% rename from typescript/types/unknownType.h rename to checker/types/ts/unknownType.h index 892b81655e8bb79e2a8313eacd9d050785189f74..205e1e501e29f49e8b3e65a81e1698fa511bdd68 100644 --- a/typescript/types/unknownType.h +++ b/checker/types/ts/unknownType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNKNOWN_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_UNKNOWN_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNKNOWN_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_UNKNOWN_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class UnknownType : public Type { diff --git a/typescript/types/voidType.cpp b/checker/types/ts/voidType.cpp similarity index 100% rename from typescript/types/voidType.cpp rename to checker/types/ts/voidType.cpp diff --git a/typescript/types/voidType.h b/checker/types/ts/voidType.h similarity index 87% rename from typescript/types/voidType.h rename to checker/types/ts/voidType.h index 9f8fcfd2cd23703e0ed6fe8e19479aa919078cbc..2776c0d5bd8558660fde4ab4003d2c42fb0b5100 100644 --- a/typescript/types/voidType.h +++ b/checker/types/ts/voidType.h @@ -13,10 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_VOID_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_VOID_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TS_VOID_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TS_VOID_TYPE_H -#include "type.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" namespace panda::es2panda::checker { class VoidType : public Type { diff --git a/typescript/types/type.cpp b/checker/types/type.cpp similarity index 63% rename from typescript/types/type.cpp rename to checker/types/type.cpp index 4d4ba4b5b725da84414899075f1e115203f38c65..c61cb48b4edff1a95e2aa31a4fba295e635a9b50 100644 --- a/typescript/types/type.cpp +++ b/checker/types/type.cpp @@ -15,11 +15,21 @@ #include "type.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeFlag.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeFacts.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/types/typeFlag.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/etsObjectType.h" namespace panda::es2panda::checker { +bool Type::IsETSNullType() const +{ + return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::NULL_TYPE); +} + +bool Type::IsETSStringType() const +{ + return IsETSObjectType() && AsETSObjectType()->HasObjectFlag(ETSObjectFlags::STRING); +} + void Type::ToStringAsSrc(std::stringstream &ss) const { ToString(ss); @@ -35,8 +45,20 @@ bool Type::AssignmentSource([[maybe_unused]] TypeRelation *relation, [[maybe_unu return false; } +TypeFacts Type::GetTypeFacts() const +{ + return TypeFacts::NONE; +} + void Type::Compare([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *other) {} +void Type::IsSubtype([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) {} + +Type *Type::AsSuper([[maybe_unused]] Checker *checker, [[maybe_unused]] binder::Variable *sourceVar) +{ + return nullptr; +} + Type *Type::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, [[maybe_unused]] GlobalTypesHolder *globalTypes) { diff --git a/typescript/types/type.h b/checker/types/type.h similarity index 67% rename from typescript/types/type.h rename to checker/types/type.h index c0411b81cbc3f694640f133d8cd118be166072ca..fe65c573a095d96dd053841afded94ac6670774d 100644 --- a/typescript/types/type.h +++ b/checker/types/type.h @@ -13,12 +13,13 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_H -#include "plugins/ecmascript/es2panda/typescript/types/typeFacts.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeMapping.h" -#include "plugins/ecmascript/es2panda/typescript/types/typeRelation.h" +#include "generated/signatures.h" +#include "plugins/ecmascript/es2panda/checker/types/typeMapping.h" +#include "plugins/ecmascript/es2panda/checker/types/typeRelation.h" +#include "plugins/ecmascript/es2panda/checker/types/typeFacts.h" #include "macros.h" #include @@ -36,6 +37,7 @@ class GlobalTypesHolder; #define DECLARE_TYPENAMES(typeFlag, typeName) class typeName; TYPE_MAPPING(DECLARE_TYPENAMES) #undef DECLARE_TYPENAMES +class ETSStringType; class Type { public: @@ -60,7 +62,7 @@ public: #undef DECLARE_IS_CHECKS // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define TYPE_AS_CASTS(typeFlag, typeName) \ +#define TYPE_AS_CAETS(typeFlag, typeName) \ typeName *As##typeName() \ { \ ASSERT(Is##typeName()); \ @@ -71,27 +73,42 @@ public: ASSERT(Is##typeName()); \ return reinterpret_cast(this); \ } - TYPE_MAPPING(TYPE_AS_CASTS) -#undef TYPE_AS_CASTS + TYPE_MAPPING(TYPE_AS_CAETS) +#undef TYPE_AS_CAETS + + bool IsETSStringType() const; + bool IsETSNullType() const; + + ETSStringType *AsETSStringType() + { + ASSERT(IsETSObjectType()); + return reinterpret_cast(this); + } + + const ETSStringType *AsETSStringType() const + { + ASSERT(IsETSObjectType()); + return reinterpret_cast(this); + } TypeFlag TypeFlags() const { return typeFlags_; } - bool HasTypeFlag(TypeFlag type_flag) const + bool HasTypeFlag(TypeFlag typeflag) const { - return (typeFlags_ & type_flag) != 0; + return (typeFlags_ & typeflag) != 0; } - void AddTypeFlag(TypeFlag type_flag) + void AddTypeFlag(TypeFlag typeflag) { - typeFlags_ |= type_flag; + typeFlags_ |= typeflag; } - void RemoveTypeFlag(TypeFlag type_flag) + void RemoveTypeFlag(TypeFlag typeflag) { - typeFlags_ &= ~type_flag; + typeFlags_ &= ~typeflag; } uint64_t Id() const @@ -114,16 +131,30 @@ public: return variable_; } + util::StringView ToAssemblerTypeView(ArenaAllocator *allocator) const + { + std::stringstream ss; + ToAssemblerType(ss); + return util::UString(ss.str(), allocator).View(); + } + virtual void ToString(std::stringstream &ss) const = 0; virtual void ToStringAsSrc(std::stringstream &ss) const; - virtual TypeFacts GetTypeFacts() const = 0; + virtual TypeFacts GetTypeFacts() const; + virtual void ToAssemblerType([[maybe_unused]] std::stringstream &ss) const {}; + virtual uint32_t Rank() const + { + return 0; + } virtual void Identical(TypeRelation *relation, Type *other); virtual void AssignmentTarget(TypeRelation *relation, Type *source) = 0; virtual bool AssignmentSource(TypeRelation *relation, Type *target); virtual void Compare(TypeRelation *relation, Type *other); + virtual void IsSubtype(TypeRelation *relation, Type *source); + virtual Type *AsSuper(Checker *checker, binder::Variable *sourceVar); - virtual Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes) = 0; + virtual Type *Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes); protected: // NOLINTBEGIN(misc-non-private-member-variables-in-classes) diff --git a/typescript/types/typeFacts.h b/checker/types/typeFacts.h similarity index 98% rename from typescript/types/typeFacts.h rename to checker/types/typeFacts.h index 3a92604a730ab78bb42cd54b33eae883eb7b595f..2c0ec662076237e018403d795c8a9526165119e4 100644 --- a/typescript/types/typeFacts.h +++ b/checker/types/typeFacts.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_FACTS_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_FACTS_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FACTS_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FACTS_H #include "plugins/ecmascript/es2panda/util/enumbitops.h" diff --git a/checker/types/typeFlag.h b/checker/types/typeFlag.h new file mode 100644 index 0000000000000000000000000000000000000000..3ae7b341c7ba591fd456ce48b35bfffcd6a30767 --- /dev/null +++ b/checker/types/typeFlag.h @@ -0,0 +1,123 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FLAG_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_FLAG_H + +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +#include + +namespace panda::es2panda::checker { +enum class TypeFlag : uint64_t { + NONE = 0, + NUMBER = 1ULL << 0, // x: number + STRING = 1ULL << 1, // x: string + BOOLEAN = 1ULL << 2, // x: boolean + VOID = 1ULL << 3, // x: void + NULL_TYPE = 1ULL << 4, // x: null + UNDEFINED = 1ULL << 5, // x: undefined + UNKNOWN = 1ULL << 6, // x: unknown + NEVER = 1ULL << 7, // x: never + UNION = 1ULL << 8, // x: a | b + OBJECT = 1ULL << 9, // x: object + BIGINT = 1ULL << 10, // x: bigint + BOOLEAN_LITERAL = 1ULL << 11, // x: true + NUMBER_LITERAL = 1ULL << 12, // x: 10 + STRING_LITERAL = 1ULL << 13, // x: "foo" + BIGINT_LITERAL = 1ULL << 14, // x: 10n + ENUM = 1ULL << 15, // enum x + ENUM_LITERAL = 1ULL << 16, // member of enum + SYMBOL = 1ULL << 17, // x: symbol + UNIQUE_SYMBOL = 1ULL << 18, // one of JS unique symbols + TYPE_PARAMETER = 1ULL << 19, // function + INTERSECTION = 1ULL << 20, // x: a & b + INDEX = 1ULL << 21, // keyof x + INDEX_ACCESS = 1ULL << 22, // x[a] + CONDITIONAL = 1ULL << 23, // x extends a ? b : c + SUBSTITUTION = 1ULL << 24, // type parameter substitution + TEMPLATE_LITERAL = 1ULL << 25, // x: `hello ${World}` + STRING_MAPPING = 1ULL << 27, // Uppercase/Lowercase type + ANY = 1ULL << 28, // x: any + ARRAY = 1ULL << 29, // x: number[] + FUNCTION = 1ULL << 30, // x: (a) => b + NON_PRIMITIVE = 1ULL << 31, // x: object + TYPE_REFERENCE = 1ULL << 32, // x: A + READONLY = 1ULL << 33, // type assigned to a readonly property + CONSTANT = 1ULL << 34, // type for constant expressions containing the associated constant value + BYTE = 1ULL << 35, // x: byte + SHORT = 1ULL << 36, // x: short + INT = 1ULL << 37, // x: int + LONG = 1ULL << 38, // x: long + FLOAT = 1ULL << 39, // x: float + DOUBLE = 1ULL << 40, // x: double + CHAR = 1ULL << 41, // x: char + ETS_BOOLEAN = 1ULL << 42, // ETS boolean type + ETS_VOID = 1ULL << 43, // ETS void type + ETS_OBJECT = 1ULL << 44, // ETS class or interface type + ETS_ARRAY = 1ULL << 45, // ETS array type + SYNTHETIC = 1ULL < 46, // ETS type parameter + WILDCARD = 1ULL << 47, // new A() + ETS_TYPE_PARAMETER = 1ULL < 48, // ETS type parameter + ETS_TYPE_REFERENCE = 1ULL < 49, // ETS type parameter + ETS_TYPE = BYTE | SHORT | INT | LONG | FLOAT | DOUBLE | CHAR | ETS_BOOLEAN | ETS_VOID | ETS_OBJECT | ETS_ARRAY | + WILDCARD | ETS_TYPE_PARAMETER, + ETS_PRIMITIVE = BYTE | SHORT | INT | LONG | FLOAT | DOUBLE | CHAR | ETS_BOOLEAN, + ETS_ARRAY_INDEX = BYTE | SHORT | INT, + ETS_INTEGRAL = BYTE | CHAR | SHORT | INT | LONG, + ETS_FLOATING_POINT = FLOAT | DOUBLE, + ETS_NUMERIC = ETS_INTEGRAL | FLOAT | DOUBLE, + ETS_ARRAY_OR_OBJECT = ETS_ARRAY | ETS_OBJECT, + ETS_WIDE_NUMERIC = LONG | DOUBLE, + NARROWABLE_TO_FLOAT = DOUBLE, + NARROWABLE_TO_LONG = FLOAT | NARROWABLE_TO_FLOAT, + NARROWABLE_TO_INT = LONG | NARROWABLE_TO_LONG, + NARROWABLE_TO_CHAR = SHORT | INT | NARROWABLE_TO_INT, + NARROWABLE_TO_SHORT = INT | NARROWABLE_TO_INT, + NARROWABLE_TO_BYTE = CHAR | NARROWABLE_TO_CHAR, + WIDENABLE_TO_SHORT = BYTE, + WIDENABLE_TO_INT = CHAR | SHORT | WIDENABLE_TO_SHORT, + WIDENABLE_TO_LONG = INT | WIDENABLE_TO_INT, + WIDENABLE_TO_FLOAT = LONG | WIDENABLE_TO_LONG, + WIDENABLE_TO_DOUBLE = WIDENABLE_TO_FLOAT, + COMPUTED_TYPE_LITERAL_NAME = STRING_LITERAL | NUMBER_LITERAL | ENUM, + COMPUTED_NAME = COMPUTED_TYPE_LITERAL_NAME | STRING | NUMBER | ANY | SYMBOL, + ANY_OR_UNKNOWN = ANY | UNKNOWN, + ANY_OR_VOID = ANY | VOID, + NULLABLE = UNDEFINED | NULL_TYPE, + ANY_OR_NULLABLE = ANY | NULLABLE, + LITERAL = NUMBER_LITERAL | BOOLEAN_LITERAL | STRING_LITERAL | BIGINT_LITERAL, + NUMBER_LIKE = NUMBER | NUMBER_LITERAL, + NUMBER_LIKE_ENUM = NUMBER_LIKE | ENUM, + STRING_LIKE = STRING | STRING_LITERAL, + BOOLEAN_LIKE = BOOLEAN | BOOLEAN_LITERAL, + BIGINT_LIKE = BIGINT | BIGINT_LITERAL, + VOID_LIKE = VOID | UNDEFINED, + NUMBER_OR_ANY = NUMBER | ANY, + PRIMITIVE = STRING | NUMBER | BIGINT | BOOLEAN | ENUM | ENUM_LITERAL | SYMBOL | VOID | UNDEFINED | NULL_TYPE | + LITERAL | UNIQUE_SYMBOL, + PRIMITIVE_OR_ANY = PRIMITIVE | ANY, + UNION_OR_INTERSECTION = UNION | INTERSECTION, + DEFINITELY_FALSY = + STRING_LITERAL | NUMBER_LITERAL | BOOLEAN_LITERAL | BIGINT_LITERAL | VOID | UNDEFINED | NULL_TYPE, + POSSIBLY_FALSY = DEFINITELY_FALSY | STRING | NUMBER | BOOLEAN | BIGINT, + VALID_ARITHMETIC_TYPE = ANY | NUMBER_LIKE | BIGINT_LIKE | ENUM, + UNIT = LITERAL | UNIQUE_SYMBOL | NULLABLE, +}; + +DEFINE_BITOPS(TypeFlag) +} // namespace panda::es2panda::checker + +#endif /* TYPESCRIPT_TYPES_TYPE_FLAG_H */ diff --git a/checker/types/typeMapping.h b/checker/types/typeMapping.h new file mode 100644 index 0000000000000000000000000000000000000000..5652bcce5e7d182a5ea9c6fe00fb41d66d27319a --- /dev/null +++ b/checker/types/typeMapping.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_MAPPING_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_MAPPING_H + +#include "typeFlag.h" + +#define TYPE_MAPPING(_) \ + _(TypeFlag::ARRAY, ArrayType) \ + _(TypeFlag::ANY, AnyType) \ + _(TypeFlag::BIGINT_LITERAL, BigintLiteralType) \ + _(TypeFlag::NUMBER, NumberType) \ + _(TypeFlag::STRING, StringType) \ + _(TypeFlag::BOOLEAN, BooleanType) \ + _(TypeFlag::VOID, VoidType) \ + _(TypeFlag::NULL_TYPE, NullType) \ + _(TypeFlag::UNDEFINED, UndefinedType) \ + _(TypeFlag::UNKNOWN, UnknownType) \ + _(TypeFlag::NEVER, NeverType) \ + _(TypeFlag::UNION, UnionType) \ + _(TypeFlag::OBJECT, ObjectType) \ + _(TypeFlag::BIGINT, BigintType) \ + _(TypeFlag::BOOLEAN_LITERAL, BooleanLiteralType) \ + _(TypeFlag::NUMBER_LITERAL, NumberLiteralType) \ + _(TypeFlag::STRING_LITERAL, StringLiteralType) \ + _(TypeFlag::ENUM, EnumType) \ + _(TypeFlag::ENUM_LITERAL, EnumLiteralType) \ + _(TypeFlag::TYPE_PARAMETER, TypeParameter) \ + _(TypeFlag::TYPE_REFERENCE, TypeReference) \ + _(TypeFlag::BYTE, ByteType) \ + _(TypeFlag::SHORT, ShortType) \ + _(TypeFlag::INT, IntType) \ + _(TypeFlag::LONG, LongType) \ + _(TypeFlag::FLOAT, FloatType) \ + _(TypeFlag::DOUBLE, DoubleType) \ + _(TypeFlag::CHAR, CharType) \ + _(TypeFlag::ETS_BOOLEAN, ETSBooleanType) \ + _(TypeFlag::ETS_VOID, ETSVoidType) \ + _(TypeFlag::FUNCTION, ETSFunctionType) \ + _(TypeFlag::ETS_OBJECT, ETSObjectType) \ + _(TypeFlag::ETS_ARRAY, ETSArrayType) \ + _(TypeFlag::NON_PRIMITIVE, NonPrimitiveType) \ + _(TypeFlag::WILDCARD, WildcardType) \ + _(TypeFlag::ETS_TYPE_PARAMETER, ETSTypeParameter) \ + _(TypeFlag::ETS_TYPE_REFERENCE, ETSTypeReference) + +#define OBJECT_TYPE_MAPPING(_) \ + _(ObjectType::ObjectTypeKind::FUNCTION, FunctionType) \ + _(ObjectType::ObjectTypeKind::TUPLE, TupleType) \ + _(ObjectType::ObjectTypeKind::LITERAL, ObjectLiteralType) \ + _(ObjectType::ObjectTypeKind::INTERFACE, InterfaceType) + +#endif /* TYPE_MAPPING_H */ diff --git a/typescript/types/typeRelation.cpp b/checker/types/typeRelation.cpp similarity index 84% rename from typescript/types/typeRelation.cpp rename to checker/types/typeRelation.cpp index da3491542ae9eabfd183a173d554d18b834c8ebe..73e1aefdb62573841b85960d06ff9f5a1f0170f0 100644 --- a/typescript/types/typeRelation.cpp +++ b/checker/types/typeRelation.cpp @@ -15,33 +15,11 @@ #include "typeRelation.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" -#include "plugins/ecmascript/es2panda/typescript/types/indexInfo.h" -#include "plugins/ecmascript/es2panda/typescript/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/ts/indexInfo.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" namespace panda::es2panda::checker { -const Type *AsSrc::GetType() const -{ - return type_; -} - -TypeRelation::TypeRelation(Checker *checker) : checker_(checker) {} - -bool TypeRelation::IsTrue() const -{ - return result_ == RelationResult::TRUE; -} - -const Checker *TypeRelation::GetChecker() const -{ - return checker_; -} - -Checker *TypeRelation::GetChecker() -{ - return checker_; -} - ArenaAllocator *TypeRelation::Allocator() { return checker_->Allocator(); @@ -116,6 +94,7 @@ bool TypeRelation::IsIdenticalTo(IndexInfo *source, IndexInfo *target) return result_ == RelationResult::TRUE; } +// TODO: applyNarrowing -> flag bool TypeRelation::IsAssignableTo(Type *source, Type *target) { result_ = CacheLookup(source, target, checker_->AssignableResults(), RelationType::ASSIGNABLE); @@ -130,8 +109,10 @@ bool TypeRelation::IsAssignableTo(Type *source, Type *target) target->AssignmentTarget(this, source); } - checker_->AssignableResults().cached.insert( - {{source->Id(), target->Id()}, {result_, RelationType::ASSIGNABLE}}); + if (flags_ == TypeRelationFlag::NONE) { + checker_->AssignableResults().cached.insert( + {{source->Id(), target->Id()}, {result_, RelationType::ASSIGNABLE}}); + } } return result_ == RelationResult::TRUE; @@ -165,9 +146,4 @@ void TypeRelation::RaiseError(std::initializer_list lis { checker_->ThrowTypeError(list, loc); } - -void TypeRelation::Result(bool res) -{ - result_ = res ? RelationResult::TRUE : RelationResult::FALSE; -} } // namespace panda::es2panda::checker diff --git a/typescript/types/typeRelation.h b/checker/types/typeRelation.h similarity index 50% rename from typescript/types/typeRelation.h rename to checker/types/typeRelation.h index c55b30ea16c94209bab5a2f83c0fb1d14885d225..2f0792989e946b3a30369478d8360a5ca9348781 100644 --- a/typescript/types/typeRelation.h +++ b/checker/types/typeRelation.h @@ -13,27 +13,53 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_RELATION_H -#define ES2PANDA_COMPILER_TYPESCRIPT_TYPES_TYPE_RELATION_H +#ifndef ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_RELATION_H +#define ES2PANDA_COMPILER_CHECKER_TYPES_TYPE_RELATION_H #include "plugins/ecmascript/es2panda/lexer/token/sourceLocation.h" #include "plugins/ecmascript/es2panda/lexer/token/tokenType.h" -#include "macros.h" #include "plugins/ecmascript/es2panda/util/ustring.h" +#include "plugins/ecmascript/es2panda/util/enumbitops.h" + +#include "macros.h" #include #include +namespace panda::es2panda::ir { +class Expression; +} + namespace panda::es2panda::checker { class Signature; class IndexInfo; class Type; class Checker; -enum class RelationResult { TRUE, FALSE, UNKNOWN, MAYBE, CACHE_MISS }; +enum class TypeRelationFlag { + NONE = 0, + NARROWING = 1 << 0, + WIDENING = 1 << 1, + BOXING = 1 << 2, + UNBOXING = 1 << 3, + CAPTURE = 1 << 4, + STRING = 1 << 5, + VALUE_SET = 1 << 6, + UNCHECKED = 1 << 7, + NO_THROW = 1 << 8, + SELF_REFERENCE = 1 << 9, + NO_RETURN_TYPE_CHECK = 1 << 10, + DIRECT_RETURN = 1 << 11, + + ASSIGNMENT_CONTEXT = WIDENING | BOXING | UNBOXING, +}; + +enum class RelationResult { TRUE, FALSE, UNKNOWN, MAYBE, CACHE_MISS, ERROR }; enum class RelationType { COMPARABLE, ASSIGNABLE, IDENTICAL }; +DEFINE_BITOPS(TypeRelationFlag) + class RelationKey { public: uint64_t sourceId; @@ -74,17 +100,66 @@ class AsSrc { public: explicit AsSrc(const Type *type) : type_(const_cast(type)) {} - const Type *GetType() const; + const Type *GetType() const + { + return type_; + } private: Type *type_; }; -using TypeErrorMessageElement = std::variant; +using TypeErrorMessageElement = + std::variant; class TypeRelation { public: - explicit TypeRelation(Checker *checker); + explicit TypeRelation(Checker *checker) : checker_(checker), result_(RelationResult::FALSE) {} + + bool IsTrue() const + { + return result_ == RelationResult::TRUE; + } + + bool IsError() const + { + return result_ == RelationResult::ERROR; + } + + bool ApplyNarrowing() const + { + return (flags_ & TypeRelationFlag::NARROWING) != 0; + } + + bool ApplyWidening() const + { + return (flags_ & TypeRelationFlag::WIDENING) != 0; + } + + bool NoReturnTypeCheck() const + { + return (flags_ & TypeRelationFlag::NO_RETURN_TYPE_CHECK) != 0; + } + + bool DirectReturn() const + { + return (flags_ & TypeRelationFlag::DIRECT_RETURN) != 0; + } + + const Checker *GetChecker() const + { + return checker_; + } + + ir::Expression *GetNode() const + { + return node_; + } + + Checker *GetChecker() + { + return checker_; + } bool IsIdenticalTo(Type *source, Type *target); bool IsIdenticalTo(Signature *source, Signature *target); @@ -94,18 +169,58 @@ public: void RaiseError(const std::string &errMsg, const lexer::SourcePosition &loc) const; void RaiseError(std::initializer_list list, const lexer::SourcePosition &loc) const; - void Result(bool res); - const Checker *GetChecker() const; - Checker *GetChecker(); + void Result(bool res) + { + result_ = res ? RelationResult::TRUE : RelationResult::FALSE; + } + + void Result(RelationResult res) + { + result_ = res; + } + + void SetNode(ir::Expression *node) + { + node_ = node; + } + + void SetFlags(TypeRelationFlag flags) + { + flags_ = flags; + } + ArenaAllocator *Allocator(); - bool IsTrue() const; + + friend class SavedTypeRelationFlagsContext; private: RelationResult CacheLookup(const Type *source, const Type *target, const RelationHolder &holder, RelationType type) const; Checker *checker_; - RelationResult result_ {RelationResult::FALSE}; + RelationResult result_ {}; + TypeRelationFlag flags_ {}; + ir::Expression *node_ {}; +}; +class SavedTypeRelationFlagsContext { +public: + explicit SavedTypeRelationFlagsContext(TypeRelation *relation, TypeRelationFlag newFlag) + : relation_(relation), prev_(relation->flags_) + { + relation_->flags_ = newFlag; + } + + NO_COPY_SEMANTIC(SavedTypeRelationFlagsContext); + DEFAULT_MOVE_SEMANTIC(SavedTypeRelationFlagsContext); + + ~SavedTypeRelationFlagsContext() + { + relation_->flags_ = prev_; + } + +private: + TypeRelation *relation_; + TypeRelationFlag prev_; }; } // namespace panda::es2panda::checker diff --git a/compiler/base/catchTable.cpp b/compiler/base/catchTable.cpp index b6992dd7491090fa47b5472f781df1207e43f0fd..eda1103bb51a13e93b4e91e4bfe53e7d791b8b09 100644 --- a/compiler/base/catchTable.cpp +++ b/compiler/base/catchTable.cpp @@ -18,8 +18,8 @@ #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" namespace panda::es2panda::compiler { -TryLabelSet::TryLabelSet(PandaGen *pg) - : try_(pg->AllocLabel(), pg->AllocLabel()), catch_(pg->AllocLabel(), pg->AllocLabel()) +TryLabelSet::TryLabelSet(CodeGen *cg) + : try_(cg->AllocLabel(), cg->AllocLabel()), catch_(cg->AllocLabel(), cg->AllocLabel()) { } } // namespace panda::es2panda::compiler diff --git a/compiler/base/catchTable.h b/compiler/base/catchTable.h index 5dfd29a23e1ad2e26668376e0bbcdc3e5a2cf296..50236a066d1a8cde3b82bc73adcdbe1aa0ff44a5 100644 --- a/compiler/base/catchTable.h +++ b/compiler/base/catchTable.h @@ -20,11 +20,11 @@ #include "plugins/ecmascript/es2panda/compiler/core/labelPair.h" namespace panda::es2panda::compiler { -class PandaGen; +class CodeGen; class TryLabelSet { public: - explicit TryLabelSet(PandaGen *pg); + explicit TryLabelSet(CodeGen *cg); ~TryLabelSet() = default; DEFAULT_COPY_SEMANTIC(TryLabelSet); @@ -67,7 +67,7 @@ private: class CatchTable { public: - CatchTable(PandaGen *pg, uint32_t depth) : labelSet_(pg), depth_(depth) {} + CatchTable(CodeGen *cg, uint32_t depth) : labelSet_(cg), depth_(depth) {} ~CatchTable() = default; NO_COPY_SEMANTIC(CatchTable); diff --git a/compiler/base/condition.cpp b/compiler/base/condition.cpp index 647f20923989019b1f56be6d94a072ac60e16621..2b7c5a53371f70410fa34ba3a897c569ef09431f 100644 --- a/compiler/base/condition.cpp +++ b/compiler/base/condition.cpp @@ -16,6 +16,7 @@ #include "condition.h" #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" #include "plugins/ecmascript/es2panda/ir/expressions/binaryExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/unaryExpression.h" @@ -89,4 +90,76 @@ void Condition::Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLa pg->ToBoolean(expr); pg->BranchIfFalse(expr, falseLabel); } + +Condition::Result Condition::CheckConstantExpr(const ir::Expression *expr) +{ + if (expr->TsType()->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + auto res = expr->TsType()->AsETSBooleanType()->GetValue(); + return res ? Result::CONST_TRUE : Result::CONST_FALSE; + } + + return Result::UNKNOWN; +} + +void Condition::Compile(ETSGen *etsg, const ir::Expression *expr, Label *falseLabel) +{ + if (expr->IsBinaryExpression()) { + const auto *binExpr = expr->AsBinaryExpression(); + + switch (binExpr->OperatorType()) { + case lexer::TokenType::PUNCTUATOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: + case lexer::TokenType::KEYW_INSTANCEOF: { + auto ttctx = TargetTypeContext(etsg, binExpr->OperationType()); + + RegScope rs(etsg); + VReg lhs = etsg->AllocReg(); + + binExpr->Left()->Compile(etsg); + etsg->ApplyWidenAndStoreAccumulator(binExpr, lhs, binExpr->OperationType()); + binExpr->Right()->Compile(etsg); + etsg->Condition(binExpr, binExpr->OperatorType(), lhs, falseLabel); + return; + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_AND: { + binExpr->Left()->Compile(etsg); + etsg->BranchIfFalse(binExpr, falseLabel); + + binExpr->Right()->Compile(etsg); + etsg->BranchIfFalse(binExpr, falseLabel); + return; + } + case lexer::TokenType::PUNCTUATOR_LOGICAL_OR: { + auto *endLabel = etsg->AllocLabel(); + + binExpr->Left()->Compile(etsg); + etsg->BranchIfTrue(binExpr, endLabel); + + binExpr->Right()->Compile(etsg); + etsg->BranchIfFalse(binExpr, falseLabel); + etsg->SetLabel(binExpr, endLabel); + return; + } + default: { + break; + } + } + } else if (expr->IsUnaryExpression() && + expr->AsUnaryExpression()->OperatorType() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) { + expr->AsUnaryExpression()->Argument()->Compile(etsg); + etsg->BranchIfTrue(expr, falseLabel); + return; + } + + // TODO: Handle implicit bool conversion: not zero int == true, not null obj ref == true, otherwise false + ASSERT(expr->TsType()->IsETSBooleanType()); // already checked by checker::CheckTruthinessOfType() + expr->Compile(etsg); + etsg->BranchIfFalse(expr, falseLabel); + + return; +} } // namespace panda::es2panda::compiler diff --git a/compiler/base/condition.h b/compiler/base/condition.h index c7d8e655d421b1ae238940e0a0f2a1a0706548c9..c969d104755cf40a1e6367eb08f8962633bc7b31 100644 --- a/compiler/base/condition.h +++ b/compiler/base/condition.h @@ -20,13 +20,22 @@ namespace panda::es2panda::compiler { class PandaGen; +class ETSGen; class Label; class Condition { public: Condition() = delete; + enum class Result { + CONST_TRUE, + CONST_FALSE, + UNKNOWN, + }; + static void Compile(PandaGen *pg, const ir::Expression *expr, Label *falseLabel); + static void Compile(ETSGen *etsg, const ir::Expression *expr, Label *falseLabel); + static Result CheckConstantExpr(const ir::Expression *expr); }; } // namespace panda::es2panda::compiler diff --git a/compiler/base/destructuring.cpp b/compiler/base/destructuring.cpp index ea61f4d3d05a8edbd93b5062997f80e6e40590d3..694faf5c2bba7b503d34dbdc0c9916ab62a2605b 100644 --- a/compiler/base/destructuring.cpp +++ b/compiler/base/destructuring.cpp @@ -40,7 +40,7 @@ static void GenRestElement(PandaGen *pg, const ir::SpreadElement *restElement, DestructuringRestIterator iterator(destIterator); // create left reference for rest element - LReference lref = LReference::CreateLRef(pg, restElement, isDeclaration); + auto lref = JSLReference::Create(pg, restElement, isDeclaration); // create an empty array first pg->CreateEmptyArray(restElement); @@ -104,7 +104,7 @@ static void GenArray(PandaGen *pg, const ir::ArrayExpression *array) init = element->AsAssignmentPattern()->Right(); } - LReference lref = LReference::CreateLRef(pg, target, array->IsDeclaration()); + auto lref = JSLReference::Create(pg, target, array->IsDeclaration()); iterator.Step(); if (init != nullptr) { @@ -192,7 +192,7 @@ static void GenObjectWithRest(PandaGen *pg, const ir::ObjectExpression *object, for (const auto *element : properties) { if (element->IsRestElement()) { RegScope restScope(pg); - LReference lref = LReference::CreateLRef(pg, element, object->IsDeclaration()); + auto lref = JSLReference::Create(pg, element, object->IsDeclaration()); pg->CreateObjectWithExcludedKeys(element, rhs, propStart, properties.size() - 1); lref.SetValue(); break; @@ -214,7 +214,7 @@ static void GenObjectWithRest(PandaGen *pg, const ir::ObjectExpression *object, pg->StoreAccumulator(key, propReg); - LReference lref = LReference::CreateLRef(pg, target, object->IsDeclaration()); + auto lref = JSLReference::Create(pg, target, object->IsDeclaration()); pg->LoadAccumulator(element, propReg); pg->LoadObjByValue(element, rhs); @@ -252,7 +252,7 @@ static void GenObject(PandaGen *pg, const ir::ObjectExpression *object, VReg rhs Operand propOperand = pg->ToOwnPropertyKey(key, propExpr->IsComputed()); - LReference lref = LReference::CreateLRef(pg, target, object->IsDeclaration()); + auto lref = JSLReference::Create(pg, target, object->IsDeclaration()); if (std::holds_alternative(propOperand)) { pg->LoadAccumulator(element, std::get(propOperand)); diff --git a/compiler/base/literals.h b/compiler/base/literals.h index 9534b830563b54593aa33567a3c5268fe063936e..bb2b73b01cf999aa6be771d5ad0dce900e60b1b4 100644 --- a/compiler/base/literals.h +++ b/compiler/base/literals.h @@ -27,7 +27,7 @@ class TaggedTemplateExpression; } // namespace panda::es2panda::ir namespace panda::es2panda::checker { -class Checker; +class TSChecker; class Type; } // namespace panda::es2panda::checker diff --git a/compiler/base/lreference.cpp b/compiler/base/lreference.cpp index 0f2e0b36f745781ef5328fc1be09259787731ece..0caeadb727cbdaea43bf1844df5ed0e2b926d710 100644 --- a/compiler/base/lreference.cpp +++ b/compiler/base/lreference.cpp @@ -19,7 +19,10 @@ #include "plugins/ecmascript/es2panda/compiler/base/destructuring.h" #include "plugins/ecmascript/es2panda/compiler/core/function.h" #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" #include "plugins/ecmascript/es2panda/ir/base/spreadElement.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" #include "plugins/ecmascript/es2panda/ir/expressions/assignmentExpression.h" #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/expressions/memberExpression.h" @@ -28,11 +31,45 @@ #include "plugins/ecmascript/es2panda/util/helpers.h" namespace panda::es2panda::compiler { -// LReference -LReference::LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration, ReferenceKind refKind, - binder::ScopeFindResult res) - : node_(node), pg_(pg), refKind_(refKind), res_(res), isDeclaration_(isDeclaration) +LReference::LReferenceBase LReference::CreateBase(CodeGen *cg, const ir::AstNode *node, bool isDeclaration) +{ + switch (node->Type()) { + case ir::AstNodeType::IDENTIFIER: { + const util::StringView &name = node->AsIdentifier()->Name(); + binder::ScopeFindResult res = cg->Scope()->Find(name); + + return {cg, node, ReferenceKind::VAR_OR_GLOBAL, res, isDeclaration}; + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + return {cg, node, ReferenceKind::MEMBER, {}, false}; + } + case ir::AstNodeType::VARIABLE_DECLARATION: { + ASSERT(node->AsVariableDeclaration()->Declarators().size() == 1); + return CreateBase(cg, node->AsVariableDeclaration()->Declarators()[0]->Id(), true); + } + case ir::AstNodeType::VARIABLE_DECLARATOR: { + return CreateBase(cg, node->AsVariableDeclarator()->Id(), true); + } + case ir::AstNodeType::ARRAY_PATTERN: + case ir::AstNodeType::OBJECT_PATTERN: { + return {cg, node, ReferenceKind::DESTRUCTURING, {}, isDeclaration}; + } + case ir::AstNodeType::ASSIGNMENT_PATTERN: { + return CreateBase(cg, node->AsAssignmentPattern()->Left(), true); + } + case ir::AstNodeType::REST_ELEMENT: { + return CreateBase(cg, node->AsRestElement()->Argument(), true); + } + default: { + UNREACHABLE(); + } + } +} + +JSLReference::JSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration) + : LReference(node, refKind, res, isDeclaration), pg_(static_cast(cg)) { if (refKind_ != ReferenceKind::MEMBER) { return; @@ -50,7 +87,7 @@ LReference::LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration obj_ = pg_->AllocReg(); memberExpr->Object()->Compile(pg_); - pg->StoreAccumulator(node_, obj_); + pg_->StoreAccumulator(node_, obj_); prop_ = pg_->ToNamedPropertyKey(memberExpr->Property(), memberExpr->IsComputed()); if (std::holds_alternative(prop_)) { @@ -68,7 +105,7 @@ LReference::LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration prop_ = propReg; } -void LReference::GetValue() +void JSLReference::GetValue() const { switch (refKind_) { case ReferenceKind::VAR_OR_GLOBAL: { @@ -96,7 +133,7 @@ void LReference::GetValue() } } -void LReference::SetValue() +void JSLReference::SetValue() const { switch (refKind_) { case ReferenceKind::VAR_OR_GLOBAL: { @@ -127,48 +164,102 @@ void LReference::SetValue() } } -ReferenceKind LReference::Kind() const +ETSLReference::ETSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration) + : LReference(node, refKind, res, isDeclaration), etsg_(static_cast(cg)) { - return refKind_; -} + if (refKind_ != ReferenceKind::MEMBER) { + refKind_ = ResolveReferenceKind(res.variable); + return; + } -binder::Variable *LReference::Variable() const -{ - return res_.variable; + const auto *memberExpr = node_->AsMemberExpression(); + staticObjRef_ = memberExpr->Object()->TsType(); + + if (!memberExpr->IsComputed() && memberExpr->PropVar()->HasFlag(binder::VariableFlags::STATIC)) { + return; + } + + TargetTypeContext ttctx(etsg_, memberExpr->Object()->TsType()); + memberExpr->Object()->Compile(etsg_); + baseReg_ = etsg_->AllocReg(); + etsg_->StoreAccumulator(node, baseReg_); + + if (memberExpr->IsComputed()) { + TargetTypeContext pttctx(etsg_, memberExpr->Property()->TsType()); + memberExpr->Property()->Compile(etsg_); + propReg_ = etsg_->AllocReg(); + etsg_->StoreAccumulator(node, propReg_); + } } -LReference LReference::CreateLRef(PandaGen *pg, const ir::AstNode *node, bool isDeclaration) +ReferenceKind ETSLReference::ResolveReferenceKind(const binder::Variable *variable) { - switch (node->Type()) { - case ir::AstNodeType::IDENTIFIER: { - const util::StringView &name = node->AsIdentifier()->Name(); - binder::ScopeFindResult res = pg->Scope()->Find(name); + auto *declNode = variable->Declaration()->Node(); - return {node, pg, isDeclaration, ReferenceKind::VAR_OR_GLOBAL, res}; + switch (declNode->Type()) { + case ir::AstNodeType::CLASS_PROPERTY: { + auto *classField = declNode->AsClassProperty(); + return classField->IsStatic() ? ReferenceKind::STATIC_FIELD : ReferenceKind::FIELD; } - case ir::AstNodeType::MEMBER_EXPRESSION: { - return {node, pg, false, ReferenceKind::MEMBER, {}}; + case ir::AstNodeType::CLASS_DEFINITION: { + auto *classDef = declNode->AsClassDefinition(); + return classDef->IsStatic() ? ReferenceKind::STATIC_CLASS : ReferenceKind::CLASS; } - case ir::AstNodeType::VARIABLE_DECLARATION: { - ASSERT(node->AsVariableDeclaration()->Declarators().size() == 1); - return LReference::CreateLRef(pg, node->AsVariableDeclaration()->Declarators()[0]->Id(), true); + case ir::AstNodeType::METHOD_DEFINITION: { + return ReferenceKind::METHOD; } - case ir::AstNodeType::VARIABLE_DECLARATOR: { - return LReference::CreateLRef(pg, node->AsVariableDeclarator()->Id(), true); + case ir::AstNodeType::TS_INTERFACE_DECLARATION: { } - case ir::AstNodeType::ARRAY_PATTERN: - case ir::AstNodeType::OBJECT_PATTERN: { - return {node, pg, isDeclaration, ReferenceKind::DESTRUCTURING, {}}; + default: { + break; } - case ir::AstNodeType::ASSIGNMENT_PATTERN: { - return LReference::CreateLRef(pg, node->AsAssignmentPattern()->Left(), true); + } + + return ReferenceKind::LOCAL; +} + +void ETSLReference::GetValue() const +{ + switch (refKind_) { + case ReferenceKind::MEMBER: { + node_->AsMemberExpression()->Compile(etsg_); + break; } - case ir::AstNodeType::REST_ELEMENT: { - return LReference::CreateLRef(pg, node->AsRestElement()->Argument(), true); + default: { + etsg_->LoadVar(node_->AsIdentifier(), res_); + break; + } + } +} + +void ETSLReference::SetValue() const +{ + switch (refKind_) { + case ReferenceKind::MEMBER: { + auto *memberExpr = node_->AsMemberExpression(); + etsg_->ApplyWidening(node_, memberExpr->TsType()); + + if (memberExpr->IsComputed()) { + etsg_->StoreArrayElement(node_, baseReg_, propReg_); + break; + } + + auto &propName = memberExpr->Property()->AsIdentifier()->Name(); + if (memberExpr->PropVar()->HasFlag(binder::VariableFlags::STATIC)) { + util::StringView fullName = etsg_->FormClassPropReference(staticObjRef_->AsETSObjectType(), propName); + etsg_->StoreStaticProperty(node_, memberExpr->TsType(), fullName); + break; + } + + etsg_->StoreProperty(node_, memberExpr->TsType(), baseReg_, propName); + break; } default: { - UNREACHABLE(); + etsg_->StoreVar(node_->AsIdentifier(), res_); + break; } } } + } // namespace panda::es2panda::compiler diff --git a/compiler/base/lreference.h b/compiler/base/lreference.h index 0df234059dafff85af7b193ffbfc76265b633e8b..5733c9d2ae5ba0b7c5364ce0c3a9ec8536e8e7b7 100644 --- a/compiler/base/lreference.h +++ b/compiler/base/lreference.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_BASE_LREFERENCE_H -#define ES2PANDA_COMPILER_BASE_LREFERENCE_H +#ifndef ES2PANDA_COMPILER_BASE_JSLREFERENCE_H +#define ES2PANDA_COMPILER_BASE_JSLREFERENCE_H #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/ir/irnode.h" @@ -23,6 +23,10 @@ namespace panda::es2panda::ir { class AstNode; } // namespace panda::es2panda::ir +namespace panda::es2panda::checker { +class ETSObjectType; +} // namespace panda::es2panda::checker + namespace panda::es2panda::compiler { enum class ReferenceKind { MEMBER, @@ -30,34 +34,96 @@ enum class ReferenceKind { SUPER, VAR_OR_GLOBAL, DESTRUCTURING, + LOCAL, + STATIC_FIELD, + FIELD, + CLASS, + STATIC_CLASS, + METHOD, + STATIC_METHOD, }; +class CodeGen; +class ETSGen; class PandaGen; class LReference { public: - LReference(const ir::AstNode *node, PandaGen *pg, bool isDeclaration, ReferenceKind refKind, - binder::ScopeFindResult res); ~LReference() = default; NO_COPY_SEMANTIC(LReference); - NO_MOVE_SEMANTIC(LReference); + DEFAULT_MOVE_SEMANTIC(LReference); - void GetValue(); - void SetValue(); - binder::Variable *Variable() const; - ReferenceKind Kind() const; + ReferenceKind Kind() const + { + return refKind_; + } - static LReference CreateLRef(PandaGen *pg, const ir::AstNode *node, bool isDeclaration); + binder::Variable *Variable() const + { + return res_.variable; + } + +protected: + using LReferenceBase = std::tuple; + static LReferenceBase CreateBase(CodeGen *cg, const ir::AstNode *node, bool isDeclaration); + + explicit LReference(const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, bool isDeclaration) + : node_(node), refKind_(refKind), res_(res), isDeclaration_(isDeclaration) + { + } -private: const ir::AstNode *node_; - PandaGen *pg_; ReferenceKind refKind_; binder::ScopeFindResult res_; + bool isDeclaration_; +}; + +class JSLReference : public LReference { +public: + JSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration); + ~JSLReference() = default; + NO_COPY_SEMANTIC(JSLReference); + NO_MOVE_SEMANTIC(JSLReference); + + void GetValue() const; + void SetValue() const; + + static JSLReference Create(CodeGen *cg, const ir::AstNode *node, bool isDeclaration) + { + return std::make_from_tuple(CreateBase(cg, node, isDeclaration)); + } + +private: + PandaGen *pg_; VReg obj_; VReg privateCtor_ {}; Operand prop_; - bool isDeclaration_; +}; + +class ETSLReference : public LReference { +public: + ETSLReference(CodeGen *cg, const ir::AstNode *node, ReferenceKind refKind, binder::ScopeFindResult res, + bool isDeclaration); + ~ETSLReference() = default; + NO_COPY_SEMANTIC(ETSLReference); + NO_MOVE_SEMANTIC(ETSLReference); + + void GetValue() const; + void SetValue() const; + + static ETSLReference Create(CodeGen *cg, const ir::AstNode *node, bool isDeclaration) + { + return std::make_from_tuple(CreateBase(cg, node, isDeclaration)); + } + + static ReferenceKind ResolveReferenceKind(const binder::Variable *variable); + +private: + ETSGen *etsg_; + const checker::Type *staticObjRef_ {}; + VReg baseReg_ {}; + VReg propReg_ {}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/base/optionalChain.cpp b/compiler/base/optionalChain.cpp index c9cec7519e2da41b3b661a4036f541a464fa11df..e115517ddf131e7374d838c458cb4caeaca9cf61 100644 --- a/compiler/base/optionalChain.cpp +++ b/compiler/base/optionalChain.cpp @@ -40,7 +40,7 @@ void OptionalChain::Check(compiler::VReg obj) RegScope rs(pg_); - if (obj == INVALID_VREG) { + if (obj.IsInvalid()) { obj = pg_->AllocReg(); pg_->StoreAccumulator(node_, obj); } diff --git a/compiler/core/ETSGen.cpp b/compiler/core/ETSGen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03f13d530957519514d3cb836c030dafd73e0eb1 --- /dev/null +++ b/compiler/core/ETSGen.cpp @@ -0,0 +1,1191 @@ +/* + * 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. + */ + +#include "ETSGen.h" + +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/statement.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/expressions/binaryExpression.h" +#include "plugins/ecmascript/es2panda/ir/statements/deferStatement.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/compiler/base/lreference.h" +#include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" +#include "plugins/ecmascript/es2panda/compiler/core/dynamicContext.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" + +namespace panda::es2panda::compiler { + +void ETSGen::InitializeContainingClass() +{ + auto *containingClass = util::Helpers::GetContainingClassDefinition(rootNode_); + + if (containingClass) { + containingClassType_ = containingClass->TsType()->AsETSObjectType(); + return; + } + + auto *containingInterface = util::Helpers::GetContainingInterfaceDeclaration(rootNode_); + containingClassType_ = containingInterface->TsType()->AsETSObjectType(); +} + +const checker::ETSChecker *ETSGen::Checker() const +{ + return context_->Checker()->AsETSChecker(); +} + +const checker::Type *ETSGen::ReturnType() const +{ + return rootNode_->AsScriptFunction()->Signature()->ReturnType(); +} + +void ETSGen::ApplyWidenAndStoreAccumulator(const ir::AstNode *node, VReg &vreg, const checker::Type *targetType) +{ + ApplyWidening(node, targetType); + StoreAccumulator(node, vreg); +} + +VReg ETSGen::StoreException(const ir::AstNode *node) +{ + VReg exception = AllocReg(); + ra_.Emit(node, exception); + + acc_.SetType(Checker()->GlobalBuiltinExceptionType()); + exception.SetType(acc_.GetType()); + return exception; +} + +void ETSGen::StoreAccumulator(const ir::AstNode *node, VReg &vreg) +{ + if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + ra_.Emit(node, vreg); + } else if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + ra_.Emit(node, vreg); + } else { + ra_.Emit(node, vreg); + } + + vreg.SetType(acc_.GetType()); +} + +void ETSGen::LoadAccumulator(const ir::AstNode *node, VReg vreg) +{ + if (vreg.GetType()->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + ra_.Emit(node, vreg); + } else if (vreg.GetType()->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + ra_.Emit(node, vreg); + } else { + ra_.Emit(node, vreg); + } + + acc_.SetType(vreg.GetType()); +} + +void ETSGen::MoveVreg(const ir::AstNode *node, VReg &vd, VReg vs) +{ + if (vs.GetType()->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + ra_.Emit(node, vd, vs); + } else if (vs.GetType()->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + ra_.Emit(node, vd, vs); + } else { + ra_.Emit(node, vd, vs); + } + + vd.SetType(vs.GetType()); +} + +void ETSGen::LoadVar(const ir::AstNode *node, const binder::ScopeFindResult &result) +{ + auto *local = result.variable->AsLocalVariable(); + + switch (ETSLReference::ResolveReferenceKind(result.variable)) { + case ReferenceKind::STATIC_FIELD: { + auto fullName = FormClassPropReference(result); + LoadStaticProperty(node, result.variable->TsType(), fullName); + break; + } + case ReferenceKind::FIELD: { + LoadProperty(node, result.variable->TsType(), GetThisReg(), result.name); + break; + } + case ReferenceKind::METHOD: + case ReferenceKind::STATIC_METHOD: + case ReferenceKind::CLASS: + case ReferenceKind::STATIC_CLASS: { + acc_.SetType(result.variable->TsType()); + break; + } + case ReferenceKind::LOCAL: { + LoadAccumulator(node, local->Vreg()); + break; + } + default: { + UNREACHABLE(); + } + } + + if (targetType_) { + ApplyWidening(node, targetType_); + } +} + +void ETSGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result) +{ + auto *local = result.variable->AsLocalVariable(); + ApplyWidening(node, local->TsType()); + + switch (ETSLReference::ResolveReferenceKind(result.variable)) { + case ReferenceKind::STATIC_FIELD: { + auto fullName = FormClassPropReference(result); + StoreStaticProperty(node, result.variable->TsType(), fullName); + break; + } + case ReferenceKind::FIELD: { + StoreProperty(node, result.variable->TsType(), GetThisReg(), result.name); + break; + } + case ReferenceKind::LOCAL: { + StoreAccumulator(node, local->Vreg()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +util::StringView ETSGen::FormClassPropReference(const checker::ETSObjectType *classType, const util::StringView &name) +{ + std::stringstream ss; + ss << classType->AssemblerName() << '.' << name; + auto res = programElement_->strings.insert(ss.str()); + + return util::StringView(*res.first); +} + +util::StringView ETSGen::FormClassPropReference(const binder::ScopeFindResult &result) +{ + auto containingClass = util::Helpers::GetContainingClassDefinition(result.variable->Declaration()->Node()); + auto containingClassType = containingClass->TsType()->AsETSObjectType(); + return FormClassPropReference(containingClassType, result.name); +} + +void ETSGen::StoreStaticOwnProperty(const ir::AstNode *node, const checker::Type *propType, + const util::StringView &name) +{ + util::StringView fullName = FormClassPropReference(containingClassType_, name); + StoreStaticProperty(node, propType, fullName); +} + +void ETSGen::StoreStaticProperty(const ir::AstNode *node, const checker::Type *propType, + const util::StringView &fullName) +{ + if (propType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + sa_.Emit(node, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + sa_.Emit(node, fullName); + } else { + sa_.Emit(node, fullName); + } +} + +void ETSGen::LoadStaticProperty(const ir::AstNode *node, const checker::Type *propType, + const util::StringView &fullName) +{ + if (propType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + sa_.Emit(node, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + sa_.Emit(node, fullName); + } else { + sa_.Emit(node, fullName); + } + + acc_.SetType(propType); +} + +void ETSGen::StoreProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name) +{ + util::StringView fullName = FormClassPropReference(objReg.GetType()->AsETSObjectType(), name); + + if (propType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + ra_.Emit(node, objReg, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + ra_.Emit(node, objReg, fullName); + } else { + ra_.Emit(node, objReg, fullName); + } +} + +void ETSGen::LoadProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name) +{ + util::StringView fullName = FormClassPropReference(objReg.GetType()->AsETSObjectType(), name); + + if (propType->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + ra_.Emit(node, objReg, fullName); + } else if (propType->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + ra_.Emit(node, objReg, fullName); + } else { + ra_.Emit(node, objReg, fullName); + } + + acc_.SetType(propType); +} + +void ETSGen::LoadThis(const ir::AstNode *node) +{ + binder::ScopeFindResult res = scope_->Find(binder::Binder::MANDATORY_PARAM_THIS); + LoadVar(node, res); +} + +VReg &ETSGen::GetThisReg() +{ + binder::ScopeFindResult res = scope_->Find(binder::Binder::MANDATORY_PARAM_THIS); + return res.variable->AsLocalVariable()->Vreg(); +} + +void ETSGen::LoadDefaultValue([[maybe_unused]] const ir::AstNode *node, [[maybe_unused]] const checker::Type *type) +{ + if (type->IsETSObjectType() || type->IsETSArrayType()) { + LoadAccumulatorNull(node, type); + } else { + auto ttctx = TargetTypeContext(this, type); + LoadAccumulatorInt(node, 0); + } +} + +void ETSGen::EmitReturnVoid(const ir::AstNode *node) +{ + sa_.Emit(node); +} + +void ETSGen::ReturnAcc(const ir::AstNode *node) +{ + if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + sa_.Emit(node); + } else if (acc_.GetType()->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { + sa_.Emit(node); + } else { + sa_.Emit(node); + } +} + +bool ETSGen::TryLoadConstantExpression(const ir::Expression *node) +{ + const auto *type = node->TsType(); + + if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return false; + } + + auto typeKind = checker::ETSChecker::TypeKind(type); + + switch (typeKind) { + case checker::TypeFlag::CHAR: { + LoadAccumulatorChar(node, type->AsCharType()->GetValue()); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: { + LoadAccumulatorBoolean(node, type->AsETSBooleanType()->GetValue()); + break; + } + case checker::TypeFlag::BYTE: { + LoadAccumulatorByte(node, type->AsByteType()->GetValue()); + break; + } + case checker::TypeFlag::SHORT: { + LoadAccumulatorShort(node, type->AsShortType()->GetValue()); + break; + } + case checker::TypeFlag::INT: { + LoadAccumulatorInt(node, type->AsIntType()->GetValue()); + break; + } + case checker::TypeFlag::LONG: { + LoadAccumulatorWideInt(node, type->AsLongType()->GetValue()); + break; + } + case checker::TypeFlag::FLOAT: { + LoadAccumulatorFloat(node, type->AsFloatType()->GetValue()); + break; + } + case checker::TypeFlag::DOUBLE: { + LoadAccumulatorDouble(node, type->AsDoubleType()->GetValue()); + break; + } + case checker::TypeFlag::ETS_OBJECT: { + LoadAccumulatorString(node, type->AsETSObjectType()->AsETSStringType()->GetValue()); + break; + } + default: { + UNREACHABLE(); + } + } + + return true; +} + +void ETSGen::ApplyWidening(const ir::AstNode *node, const checker::Type *targetType) +{ + auto ttctx = TargetTypeContext(this, targetType); + + auto typeKind = checker::ETSChecker::TypeKind(targetType); + + switch (typeKind) { + case checker::TypeFlag::DOUBLE: { + CastToDouble(node); + break; + } + case checker::TypeFlag::FLOAT: { + CastToFloat(node); + break; + } + case checker::TypeFlag::LONG: { + CastToLong(node); + break; + } + default: { + break; + } + } +} + +void ETSGen::SwapBinaryOpArgs(const ir::AstNode *node, VReg &lhs) +{ + RegScope rs(this); + auto tmp = AllocReg(); + + StoreAccumulator(node, tmp); + LoadAccumulator(node, lhs); + MoveVreg(node, lhs, tmp); +} + +void ETSGen::CastToBoolean([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalETSBooleanType()); +} + +void ETSGen::CastToByte([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: { + return; + } + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalByteType()); +} + +void ETSGen::CastToChar([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::INT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalCharType()); +} + +void ETSGen::CastToShort([[maybe_unused]] const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + return; + } + case checker::TypeFlag::INT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalShortType()); +} + +void ETSGen::CastToDouble(const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + return; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalDoubleType()); +} + +void ETSGen::CastToFloat(const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + return; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalFloatType()); +} + +void ETSGen::CastToLong(const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::LONG: { + return; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalLongType()); +} + +void ETSGen::CastToInt(const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalIntType()); +} + +void ETSGen::ToBinaryResult(const ir::AstNode *node, Label *ifFalse) +{ + Label *end = AllocLabel(); + sa_.Emit(node, 1); + sa_.Emit(node, end); + SetLabel(node, ifFalse); + sa_.Emit(node, 0); + SetLabel(node, end); +} + +void ETSGen::Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs) +{ + ApplyWidening(node, targetType_); + + switch (op) { + case lexer::TokenType::PUNCTUATOR_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryEquality(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryEquality(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + Label *ifFalse = AllocLabel(); + BinaryRelation(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_MOD: + case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { + SwapBinaryOpArgs(node, lhs); + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: + case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: + case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { + BinaryBitwiseArithmetic(node, lhs); + break; + } + case lexer::TokenType::KEYW_INSTANCEOF: { + SwapBinaryOpArgs(node, lhs); + IsInstance(node, lhs.GetType()->AsETSObjectType()->AssemblerName()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse) +{ + ApplyWidening(node, targetType_); + + switch (op) { + case lexer::TokenType::PUNCTUATOR_EQUAL: { + BinaryEqualityCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { + BinaryEqualityCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { + BinaryRelationCondition(node, lhs, ifFalse); + break; + } + case lexer::TokenType::KEYW_INSTANCEOF: { + SwapBinaryOpArgs(node, lhs); + sa_.Emit(node, lhs.GetType()->AsETSObjectType()->AssemblerName()); + BranchIfFalse(node, ifFalse); + acc_.SetType(Checker()->GlobalETSBooleanType()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::EmitNullPointerException(const ir::AstNode *node) +{ + VReg exception = StoreException(node); + NewObject(node, exception, Signatures::BUILTIN_NULLPOINTER_EXCEPTION); + CallThisStatic0(node, exception, Signatures::BUILTIN_NULLPOINTER_EXCEPTION_CTOR); + EmitThrow(node, exception); +} + +void ETSGen::CompileStatements(const ArenaVector &statements) +{ + for (const auto *stmt : statements) { + stmt->Compile(this); + } +} + +void ETSGen::CompileDeferStatements(const ArenaVector &statements) +{ + for (auto it = statements.crbegin(); it != statements.crend(); it++) { + auto *stmt = *it; + if (!stmt->IsDeferStatement()) { + continue; + } + stmt->AsDeferStatement()->Stmt()->Compile(this); + } +} + +void ETSGen::CompileStatementList(const ArenaVector &statements) +{ + if (!scope_->HasFlag(binder::ScopeFlags::DEFER_STMT)) { + CompileStatements(statements); + return; + } + + ASSERT(!statements.empty()); + auto *node = statements.front(); + + TrapContext trapCtx(this); + const auto &labelSet = trapCtx.LabelSet(); + + SetLabel(node, labelSet.TryBegin()); + CompileStatements(statements); + CompileDeferStatements(statements); + SetLabel(node, labelSet.TryEnd()); + Branch(node, labelSet.CatchEnd()); + + SetLabel(node, labelSet.CatchBegin()); + VReg exception = StoreException(node); + CompileDeferStatements(statements); + EmitThrow(node, exception); + SetLabel(node, labelSet.CatchEnd()); +} + +void ETSGen::Negate(const ir::AstNode *node) +{ + auto typeKind = checker::ETSChecker::TypeKind(acc_.GetType()); + + switch (typeKind) { + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::INT: { + sa_.Emit(node); + return; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::LogicalNot(const ir::AstNode *node) +{ + ASSERT(acc_.GetType()->IsETSBooleanType()); + sa_.Emit(node); + sa_.Emit(node, 1); +} + +void ETSGen::Unary(const ir::AstNode *node, lexer::TokenType op) +{ + switch (op) { + case lexer::TokenType::PUNCTUATOR_PLUS: { + break; // NOP -> Unary numeric promotion is performed + } + case lexer::TokenType::PUNCTUATOR_MINUS: { + UnaryMinus(node); + break; + } + case lexer::TokenType::PUNCTUATOR_TILDE: { + UnaryTilde(node); + break; + } + case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { + LogicalNot(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::UnaryMinus(const ir::AstNode *node) +{ + switch (checker::ETSChecker::ETSType(acc_.GetType())) { + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::INT: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::BYTE: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::UnaryTilde(const ir::AstNode *node) +{ + switch (checker::ETSChecker::ETSType(acc_.GetType())) { + case checker::TypeFlag::LONG: { + sa_.Emit(node); + break; + } + case checker::TypeFlag::INT: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::CHAR: + case checker::TypeFlag::BYTE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::Update(const ir::AstNode *node, lexer::TokenType op) +{ + switch (op) { + case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: { + UpdateOperator(node); + break; + } + case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: { + UpdateOperator(node); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSGen::StringBuilderAppend(const ir::AstNode *node, VReg builder) +{ + RegScope rs(this); + util::StringView signature {}; + + node->Compile(this); + + switch (checker::ETSChecker::ETSType(acc_.GetType())) { + case checker::TypeFlag::ETS_BOOLEAN: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_BOOLEAN; + break; + } + case checker::TypeFlag::CHAR: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_CHAR; + break; + } + case checker::TypeFlag::SHORT: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::INT: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_INT; + break; + } + case checker::TypeFlag::LONG: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_LONG; + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node); + [[fallthrough]]; + } + case checker::TypeFlag::DOUBLE: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_DOUBLE; + break; + } + default: { + signature = Signatures::BUILTIN_STRING_BUILDER_APPEND_BUILTIN_STRING; + break; + } + } + + if (acc_.GetType()->IsETSObjectType() && !acc_.GetType()->IsETSStringType()) { + ra_.Emit(node, Signatures::BUILTIN_OBJECT_TO_STRING, VReg::RegStart(), 0); + } + + VReg arg0 = AllocReg(); + StoreAccumulator(node, arg0); + + CallThisStatic1(node, builder, signature, arg0); +} + +void ETSGen::AppendString(const ir::BinaryExpression *binExpr, VReg &builder) +{ + ASSERT(binExpr->OperatorType() == lexer::TokenType::PUNCTUATOR_PLUS); + + auto *left = binExpr->Left(); + auto *right = binExpr->Right(); + + if (left->IsBinaryExpression()) { + AppendString(left->AsBinaryExpression(), builder); + } else { + StringBuilderAppend(left, builder); + } + + StringBuilderAppend(right, builder); +} + +void ETSGen::BuildString(const ir::AstNode *node) +{ + auto *binExpr = node->AsBinaryExpression(); + RegScope rs(this); + VReg builder = AllocReg(); + + sa_.Emit(node, Signatures::BUILTIN_STRING_BUILDER_CTOR, VReg::RegStart(), VReg::RegStart()); + StoreAccumulator(node, builder); + + AppendString(binExpr, builder); + CallThisStatic0(node, builder, Signatures::BUILTIN_STRING_BUILDER_TO_STRING); +} + +void ETSGen::NewObject(const ir::AstNode *node, VReg &ctor, util::StringView name) +{ + ra_.Emit(node, ctor, name); +} + +void ETSGen::NewArray(const ir::AstNode *node, VReg &arr, VReg dim, const checker::Type *arrType) +{ + std::stringstream ss; + arrType->ToAssemblerType(ss); + auto res = programElement_->strings.insert(ss.str()); + + ra_.Emit(node, arr, dim, util::StringView(*res.first)); +} + +void ETSGen::LoadArrayLength(const ir::AstNode *node, VReg arrayReg) +{ + ra_.Emit(node, arrayReg); + acc_.SetType(Checker()->GlobalIntType()); +} + +void ETSGen::LoadArrayElement(const ir::AstNode *node, VReg objectReg) +{ + auto *elementType = objectReg.GetType()->AsETSArrayType()->ElementType(); + + switch (checker::ETSChecker::ETSType(elementType)) { + case checker::TypeFlag::BYTE: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::INT: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::LONG: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::FLOAT: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::DOUBLE: { + ra_.Emit(node, objectReg); + break; + } + case checker::TypeFlag::ETS_ARRAY: + case checker::TypeFlag::ETS_OBJECT: { + ra_.Emit(node, objectReg); + break; + } + + default: { + UNREACHABLE(); + } + } + + acc_.SetType(elementType); +} + +void ETSGen::StoreArrayElement(const ir::AstNode *node, VReg objectReg, VReg index) +{ + auto *elementType = objectReg.GetType()->AsETSArrayType()->ElementType(); + + switch (checker::ETSChecker::ETSType(elementType)) { + case checker::TypeFlag::BYTE: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::CHAR: + case checker::TypeFlag::SHORT: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::INT: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::LONG: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::FLOAT: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::DOUBLE: { + ra_.Emit(node, objectReg, index); + break; + } + case checker::TypeFlag::ETS_ARRAY: + case checker::TypeFlag::ETS_OBJECT: { + ra_.Emit(node, objectReg, index); + break; + } + + default: { + UNREACHABLE(); + } + } + + acc_.SetType(elementType); +} + +void ETSGen::ThrowException(const ir::Expression *expr) +{ + RegScope rs(this); + + expr->Compile(this); + VReg arg = AllocReg(); + StoreAccumulator(expr, arg); + EmitThrow(expr, arg); +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/ETSGen.h b/compiler/core/ETSGen.h new file mode 100644 index 0000000000000000000000000000000000000000..8bd844f8ac675efe2ff775d2c2fd0210f84331ef --- /dev/null +++ b/compiler/core/ETSGen.h @@ -0,0 +1,637 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CORE_ETSGEN_H +#define ES2PANDA_COMPILER_CORE_ETSGEN_H + +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSfunction.h" +#include "plugins/ecmascript/es2panda/compiler/core/targetTypeContext.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" + +namespace panda::es2panda::compiler { + +class ETSGen : public CodeGen { +public: + explicit ETSGen(ArenaAllocator *allocator, RegSpiller *spiller, CompilerContext *context, + binder::FunctionScope *scope, ProgramElement *programElement) + : CodeGen(allocator, spiller, context, scope, programElement) + { + InitializeContainingClass(); + ETSFunction::Compile(this); + } + + const checker::ETSChecker *Checker() const; + const checker::Type *ReturnType() const; + + const checker::ETSObjectType *ContainingClassType() const + { + return containingClassType_; + } + + VReg &Acc() + { + return acc_; + } + + const VReg &Acc() const + { + return acc_; + } + + VReg StoreException(const ir::AstNode *node); + void ApplyWidenAndStoreAccumulator(const ir::AstNode *node, VReg &vreg, const checker::Type *targetType); + void StoreAccumulator(const ir::AstNode *node, VReg &vreg); + void LoadAccumulator(const ir::AstNode *node, VReg vreg); + void MoveVreg(const ir::AstNode *node, VReg &vd, VReg vs); + + void LoadVar(const ir::AstNode *node, const binder::ScopeFindResult &result); + void StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result); + + void LoadStaticProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &fullName); + void StoreStaticProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &fullName); + + void StoreStaticOwnProperty(const ir::AstNode *node, const checker::Type *propType, const util::StringView &name); + util::StringView FormClassPropReference(const checker::ETSObjectType *classType, const util::StringView &name); + + void StoreProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name); + void LoadProperty(const ir::AstNode *node, const checker::Type *propType, VReg objReg, + const util::StringView &name); + + void LoadThis(const ir::AstNode *node); + VReg &GetThisReg(); + + void LoadDefaultValue(const ir::AstNode *node, const checker::Type *type); + void EmitReturnVoid(const ir::AstNode *node); + void ReturnAcc(const ir::AstNode *node); + + void IsInstance(const ir::AstNode *node, util::StringView name) + { + sa_.Emit(node, name); + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + void Binary(const ir::AstNode *node, lexer::TokenType op, VReg lhs); + void Unary(const ir::AstNode *node, lexer::TokenType op); + void Update(const ir::AstNode *node, lexer::TokenType op); + + bool TryLoadConstantExpression(const ir::Expression *node); + void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse); + + void BranchIfFalse(const ir::AstNode *node, Label *ifFalse) + { + sa_.Emit(node, ifFalse); + } + + void BranchIfTrue(const ir::AstNode *node, Label *ifFalse) + { + sa_.Emit(node, ifFalse); + } + + void EmitThrow(const ir::AstNode *node, VReg err) + { + ra_.Emit(node, err); + } + + void EmitNullPointerException(const ir::AstNode *node); + + void ThrowException(const ir::Expression *expr); + + void Negate(const ir::AstNode *node); + void LogicalNot(const ir::AstNode *node); + + void LoadAccumulatorByte(const ir::AstNode *node, int8_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::BYTE); + } + + void LoadAccumulatorShort(const ir::AstNode *node, int16_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::SHORT); + } + + void LoadAccumulatorInt(const ir::AstNode *node, int32_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::INT); + } + + void LoadAccumulatorWideInt(const ir::AstNode *node, int64_t number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::LONG); + } + + void LoadAccumulatorFloat(const ir::AstNode *node, float number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::FLOAT); + } + + void LoadAccumulatorDouble(const ir::AstNode *node, double number) + { + LoadAccumulatorNumber(node, number, checker::TypeFlag::DOUBLE); + } + + void LoadAccumulatorBoolean(const ir::AstNode *node, bool value) + { + sa_.Emit(node, value ? 1 : 0); + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + void LoadAccumulatorString(const ir::AstNode *node, util::StringView str) + { + sa_.Emit(node, str); + acc_.SetType(Checker()->GlobalETSStringType()); + } + + void LoadAccumulatorNull(const ir::AstNode *node, const checker::Type *type) + { + sa_.Emit(node); + acc_.SetType(type); + } + + void LoadAccumulatorChar(const ir::AstNode *node, char16_t value) + { + sa_.Emit(node, value); + acc_.SetType(Checker()->GlobalCharType()); + } + + void ApplyWidening(const ir::AstNode *node) + { + if (targetType_) { + ApplyWidening(node, targetType_); + } + } + void ApplyWidening(const ir::AstNode *node, const checker::Type *targetType); + void SwapBinaryOpArgs(const ir::AstNode *node, VReg &lhs); + + void LoadArrayLength(const ir::AstNode *node, VReg arrayReg); + void LoadArrayElement(const ir::AstNode *node, VReg objReg); + void StoreArrayElement(const ir::AstNode *node, VReg objReg, VReg index); + + void CompileStatementList(const ArenaVector &statements); + + // Cast + void CastToBoolean(const ir::AstNode *node); + void CastToByte(const ir::AstNode *node); + void CastToChar(const ir::AstNode *node); + void CastToShort(const ir::AstNode *node); + void CastToDouble(const ir::AstNode *node); + void CastToFloat(const ir::AstNode *node); + void CastToLong(const ir::AstNode *node); + void CastToInt(const ir::AstNode *node); + + // Call, Construct + void NewArray(const ir::AstNode *node, VReg &arr, VReg dim, const checker::Type *arrType); + void NewObject(const ir::AstNode *node, VReg &ctor, util::StringView name); + void BuildString(const ir::AstNode *node); + void InitObject(const ir::AstNode *node, checker::Signature *signature, + const ArenaVector &arguments) + { + CallImpl(node, signature, arguments); + } + + void CallStatic(const ir::AstNode *node, checker::Signature *signature, + const ArenaVector &arguments) + { + CallImpl(node, signature, arguments); + } + + void CallThisStatic(const ir::AstNode *node, VReg &ctor, checker::Signature *signature, + const ArenaVector &arguments) + { + CallThisImpl(node, ctor, signature, arguments); + } + + void CallThisVirtual(const ir::AstNode *node, VReg &ctor, checker::Signature *signature, + const ArenaVector &arguments) + { + CallThisImpl(node, ctor, signature, arguments); + } + + void CallThisStatic0(const ir::AstNode *node, VReg &ctor, util::StringView name) + { + ra_.Emit(node, name, ctor, VReg::RegStart()); + } + + void CallThisStatic1(const ir::AstNode *node, VReg &ctor, util::StringView name, VReg &arg0) + { + ra_.Emit(node, name, ctor, arg0); + } + + void CallThisStatic2(const ir::AstNode *node, VReg &ctor, util::StringView name, VReg &arg0, VReg &arg1) + { + ra_.Emit(node, name, ctor, arg0, arg1, VReg::RegStart()); + } + + void GetType(const ir::AstNode *node) + { + auto classRef = acc_.GetType()->AsETSObjectType()->AssemblerName(); + sa_.Emit(node, classRef); + } + + ~ETSGen() = default; + NO_COPY_SEMANTIC(ETSGen); + NO_MOVE_SEMANTIC(ETSGen); + +private: + void StringBuilderAppend(const ir::AstNode *node, VReg builder); + void AppendString(const ir::BinaryExpression *binExpr, VReg &builder); + void CompileStatements(const ArenaVector &statements); + void CompileDeferStatements(const ArenaVector &statements); + util::StringView FormClassPropReference(const binder::ScopeFindResult &result); + void UnaryMinus(const ir::AstNode *node); + void UnaryTilde(const ir::AstNode *node); + + template + void StoreValueIntoArray(const ir::AstNode *node, VReg &arr, VReg &index) + { + ra_.Emit(node, arr, index); + } + + template + void UpdateOperator(const ir::AstNode *node) + { + switch (checker::ETSChecker::ETSType(acc_.GetType())) { + case checker::TypeFlag::LONG: { + RegScope scope(this); + VReg reg = AllocReg(); + ra_.Emit(node, reg, 1LL); + ra_.Emit(node, reg); + break; + } + case checker::TypeFlag::INT: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::BYTE: { + sa_.Emit(node, 1); + break; + } + case checker::TypeFlag::DOUBLE: { + RegScope scope(this); + VReg reg = AllocReg(); + ra_.Emit(node, reg, 1.0); + ra_.Emit(node, reg); + break; + } + case checker::TypeFlag::FLOAT: { + RegScope scope(this); + VReg reg = AllocReg(); + ra_.Emit(node, reg, 1.0F); + ra_.Emit(node, reg); + break; + } + default: { + UNREACHABLE(); + } + } + } + + template + void BinaryEqualityObj(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + ra_.Emit(node, lhs, ifFalse); + } + + template + void BinaryNumberComparison(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + ra_.Emit(node, lhs); + sa_.Emit(node, ifFalse); + } + + template + void BinaryEquality(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + BinaryEqualityCondition(node, lhs, ifFalse); + ToBinaryResult(node, ifFalse); + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + template + void BinaryEqualityCondition(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + auto typeKind = checker::ETSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::ETS_OBJECT: { + ASSERT(lhs.GetType()->IsETSObjectType()); + if (lhs.GetType()->IsETSStringType()) { + RegScope rs(this); + VReg arg0 = AllocReg(); + StoreAccumulator(node, arg0); + CallThisStatic1(node, lhs, Signatures::BUILTIN_STRING_EQUALS, arg0); + acc_.SetType(Checker()->GlobalETSBooleanType()); + if constexpr (std::is_same_v) { + LogicalNot(node); + } + BranchIfFalse(node, ifFalse); + return; + } + + BinaryEqualityObj(node, lhs, ifFalse); + + break; + } + case checker::TypeFlag::DOUBLE: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::FLOAT: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::LONG: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + ra_.Emit(node, lhs, ifFalse); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + template + void BinaryRelation(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + BinaryRelationCondition(node, lhs, ifFalse); + ToBinaryResult(node, ifFalse); + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + template + void BinaryRelationCondition(const ir::AstNode *node, VReg lhs, Label *ifFalse) + { + auto typeKind = checker::ETSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::DOUBLE: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::FLOAT: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::LONG: { + BinaryNumberComparison(node, lhs, ifFalse); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + ra_.Emit(node, lhs, ifFalse); + break; + } + default: { + UNREACHABLE(); + } + } + + acc_.SetType(Checker()->GlobalETSBooleanType()); + } + + template + void BinaryArithmetic(const ir::AstNode *node, VReg lhs) + { + auto typeKind = checker::ETSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::DOUBLE: { + ra_.Emit(node, lhs); + acc_.SetType(Checker()->GlobalDoubleType()); + break; + } + case checker::TypeFlag::FLOAT: { + ra_.Emit(node, lhs); + acc_.SetType(Checker()->GlobalFloatType()); + break; + } + default: { + BinaryBitwiseArithmetic(node, lhs); + } + } + } + + template + void BinaryBitwiseArithmetic(const ir::AstNode *node, VReg lhs) + { + auto typeKind = checker::ETSChecker::TypeKind(targetType_); + + switch (typeKind) { + case checker::TypeFlag::LONG: { + ra_.Emit(node, lhs); + acc_.SetType(Checker()->GlobalLongType()); + break; + } + case checker::TypeFlag::BYTE: + case checker::TypeFlag::SHORT: + case checker::TypeFlag::INT: { + ra_.Emit(node, lhs); + acc_.SetType(Checker()->GlobalIntType()); + break; + } + case checker::TypeFlag::ETS_BOOLEAN: { + ra_.Emit(node, lhs); + acc_.SetType(Checker()->GlobalETSBooleanType()); + break; + } + default: { + UNREACHABLE(); + } + } + } + +#define COMPILE_ARG(idx) \ + ASSERT(idx < arguments.size()); \ + auto *paramType##idx = signature->Params()[idx]->TsType(); \ + auto ttctx##idx = TargetTypeContext(this, paramType##idx); \ + arguments[idx]->Compile(this); \ + VReg arg##idx = AllocReg(); \ + ApplyWidenAndStoreAccumulator(node, arg##idx, paramType##idx) + + template + void CallThisImpl(const ir::AstNode *node, VReg &ctor, checker::Signature *signature, + const ArenaVector &arguments) + { + RegScope rs(this); + util::StringView name = signature->InternalName(); + + switch (arguments.size()) { + case 0: { + ra_.Emit(node, name, ctor, VReg::RegStart()); + break; + } + case 1: { + COMPILE_ARG(0); + ra_.Emit(node, name, ctor, arg0); + break; + } + case 2: { + COMPILE_ARG(0); + COMPILE_ARG(1); + ra_.Emit(node, name, ctor, arg0, arg1, VReg::RegStart()); + break; + } + case 3: { + COMPILE_ARG(0); + COMPILE_ARG(1); + COMPILE_ARG(2); + ra_.Emit(node, name, ctor, arg0, arg1, arg2); + break; + } + default: { + for (const auto *arg : arguments) { + auto ttctx = TargetTypeContext(this, arg->TsType()); + VReg argReg = AllocReg(); + arg->Compile(this); + StoreAccumulator(node, argReg); + } + + rra_.Emit(node, ctor, arguments.size() + 1, name, ctor); + break; + } + } + } + + template + void CallImpl(const ir::AstNode *node, checker::Signature *signature, + const ArenaVector &arguments) + { + RegScope rs(this); + util::StringView name = signature->InternalName(); + + switch (arguments.size()) { + case 0: { + ra_.Emit(node, name, VReg::RegStart(), VReg::RegStart()); + break; + } + case 1: { + COMPILE_ARG(0); + ra_.Emit(node, name, arg0, VReg::RegStart()); + break; + } + case 2: { + COMPILE_ARG(0); + COMPILE_ARG(1); + ra_.Emit(node, name, arg0, arg1); + break; + } + case 3: { + COMPILE_ARG(0); + COMPILE_ARG(1); + COMPILE_ARG(2); + ra_.Emit(node, name, arg0, arg1, arg2, VReg::RegStart()); + break; + } + case 4: { + COMPILE_ARG(0); + COMPILE_ARG(1); + COMPILE_ARG(2); + COMPILE_ARG(3); + ra_.Emit(node, name, arg0, arg1, arg2, arg3); + break; + } + default: { + VReg argStart = NextReg(); + + for (const auto *arg : arguments) { + auto ttctx = TargetTypeContext(this, arg->TsType()); + VReg argReg = AllocReg(); + arg->Compile(this); + StoreAccumulator(node, argReg); + } + + rra_.Emit(node, argStart, arguments.size(), name, argStart); + break; + } + } + } + +#undef COMPILE_ARG + + void ToBinaryResult(const ir::AstNode *node, Label *ifFalse); + + template + void LoadAccumulatorNumber(const ir::AstNode *node, T number, checker::TypeFlag targetType); + void InitializeContainingClass(); + + friend class TargetTypeContext; + + VReg acc_ {}; + const checker::Type *targetType_ {}; + const checker::ETSObjectType *containingClassType_ {}; +}; + +template +void ETSGen::LoadAccumulatorNumber(const ir::AstNode *node, T number, checker::TypeFlag targetType) +{ + auto typeKind = targetType_ ? checker::ETSChecker::TypeKind(targetType_) : targetType; + + switch (typeKind) { + case checker::TypeFlag::BYTE: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalByteType()); + break; + } + case checker::TypeFlag::CHAR: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalCharType()); + break; + } + case checker::TypeFlag::SHORT: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalShortType()); + break; + } + case checker::TypeFlag::INT: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalIntType()); + break; + } + case checker::TypeFlag::LONG: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalLongType()); + break; + } + case checker::TypeFlag::FLOAT: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalFloatType()); + break; + } + case checker::TypeFlag::DOUBLE: { + sa_.Emit(node, static_cast(number)); + acc_.SetType(Checker()->GlobalDoubleType()); + break; + } + default: { + UNREACHABLE(); + } + } +} + +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/ETSemitter.cpp b/compiler/core/ETSemitter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9317b1afc4de6c00a374ff5306e3e5e6ad592f45 --- /dev/null +++ b/compiler/core/ETSemitter.cpp @@ -0,0 +1,587 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "ETSemitter.h" + +#include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/base/methodDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsInterfaceBody.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameterDeclaration.h" +#include "plugins/ecmascript/es2panda/ir/ts/tsTypeParameter.h" +#include "plugins/ecmascript/es2panda/ir/ets/etsTypeReference.h" +#include "plugins/ecmascript/es2panda/ir/typeNode.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "plugins/ecmascript/es2panda/checker/checker.h" +#include "plugins/ecmascript/es2panda/checker/types/signature.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" +#include "assembly-program.h" + +namespace panda::es2panda::compiler { + +static constexpr auto EXTENSION = panda_file::SourceLang::ETS; + +static uint32_t TranslateModifierFlags(ir::ModifierFlags modifierFlags) +{ + uint32_t accessFlags = 0; + + if (modifierFlags & ir::ModifierFlags::PROTECTED) { + accessFlags = ACC_PROTECTED; + } else if (modifierFlags & ir::ModifierFlags::PRIVATE) { + accessFlags = ACC_PRIVATE; + } else { + accessFlags = ACC_PUBLIC; + } + + if (modifierFlags & ir::ModifierFlags::STATIC) { + accessFlags |= ACC_STATIC; + } + + if (modifierFlags & ir::ModifierFlags::CONST) { + accessFlags |= ACC_FINAL; + } + + return accessFlags; +} + +static pandasm::Function GenScriptFunction(const ir::ScriptFunction *scriptFunc) +{ + auto *funcScope = scriptFunc->Scope(); + auto *paramScope = funcScope->ParamScope(); + + auto func = pandasm::Function(funcScope->InternalName().Mutf8(), EXTENSION); + + func.params.reserve(paramScope->Params().size()); + + for (const auto *var : paramScope->Params()) { + std::stringstream ss; + var->TsType()->ToAssemblerType(ss); + func.params.emplace_back(pandasm::Type(ss.str(), var->TsType()->Rank()), EXTENSION); + } + + std::stringstream ss; + + if (scriptFunc->IsConstructor() || scriptFunc->IsStaticBlock()) { + func.return_type = pandasm::Type(Signatures::PRIMITIVE_VOID, 0); + } else { + auto *returnType = scriptFunc->Signature()->ReturnType(); + + returnType->ToAssemblerType(ss); + ASSERT(!ss.str().empty()); + func.return_type = pandasm::Type(ss.str(), returnType->Rank()); + } + + if (!scriptFunc->IsStaticBlock()) { + const auto *methodDef = util::Helpers::GetContainingClassMethodDefinition(scriptFunc); + func.metadata->SetAccessFlags(TranslateModifierFlags(methodDef->Modifiers())); + } + + return func; +} + +pandasm::Function *ETSFunctionEmitter::GenFunctionSignature() +{ + auto func = GenScriptFunction(cg_->RootNode()->AsScriptFunction()); + auto *funcElement = new pandasm::Function(func.name, func.language); + *funcElement = std::move(func); + programElement_->func = funcElement; + funcElement->regs_num = VReg::REG_START - cg_->TotalRegsNum(); + + return funcElement; +} + +void ETSFunctionEmitter::GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + [[maybe_unused]] binder::LocalVariable *variable) const +{ + variableDebug.signature = Signatures::ANY; + variableDebug.signature_type = Signatures::ANY; +} + +void ETSFunctionEmitter::GenFunctionAnnotations([[maybe_unused]] pandasm::Function *func) {} + +template +static pandasm::Function GenExternalFunction(T signature, bool isCtor) +{ + auto iter = signature.begin(); + std::string name(*iter++); + + auto func = pandasm::Function(name, EXTENSION); + + while (iter != signature.end()) { + auto paramName = *iter++; + func.params.emplace_back(pandasm::Type(paramName, 0), EXTENSION); + } + + func.return_type = pandasm::Type(Signatures::PRIMITIVE_VOID, 0); + if (isCtor) { + func.metadata->SetAttribute("ctor"); + } + func.metadata->SetAttribute("external"); + + return func; +} + +static pandasm::Function GenExternalFunction(checker::Signature *signature, bool isCtor) +{ + auto func = pandasm::Function(signature->InternalName().Mutf8(), EXTENSION); + + for (auto param : signature->Params()) { + auto *paramType = param->TsType(); + + std::stringstream ss; + paramType->ToAssemblerType(ss); + func.params.emplace_back(pandasm::Type(ss.str(), paramType->Rank()), EXTENSION); + } + + std::stringstream ss; + signature->ReturnType()->ToAssemblerType(ss); + func.return_type = pandasm::Type(ss.str(), signature->ReturnType()->Rank()); + + if (isCtor) { + func.metadata->SetAttribute("ctor"); + } + func.metadata->SetAttribute("external"); + + return func; +} + +void ETSEmitter::GenAnnotation() +{ + prog_->lang = EXTENSION; + const auto *binder = static_cast(context_->Binder()); + + auto *globalRecordTable = binder->GetGlobalRecordTable(); + + for (auto *classDecl : globalRecordTable->ClassDefinitions()) { + GenClassRecord(classDecl, false); + } + + for (auto *interfaceDecl : globalRecordTable->InterfaceDeclarations()) { + GenInterfaceRecord(interfaceDecl, false); + } + + for (auto *signature : globalRecordTable->Signatures()) { + auto func = GenScriptFunction(signature->Node()->AsScriptFunction()); + prog_->function_table.emplace(func.name, std::move(func)); + } + + for (auto [extProg, recordTable] : binder->GetExternalRecordTable()) { + (void)extProg; + GenExternalRecord(recordTable); + } + + const auto *checker = static_cast(context_->Checker()); + + for (auto [arrType, signature] : checker->GlobalArrayTypes()) { + GenGlobalArrayRecord(arrType, signature); + } +} + +void ETSEmitter::GenExternalRecord(binder::RecordTable *recordTable) +{ + for (auto *classDecl : recordTable->ClassDefinitions()) { + GenClassRecord(classDecl, !recordTable->Program()->Binder()->IsGenStdLib()); + } + + for (auto *interfaceDecl : recordTable->InterfaceDeclarations()) { + GenInterfaceRecord(interfaceDecl, !recordTable->Program()->Binder()->IsGenStdLib()); + } + + for (auto *signature : recordTable->Signatures()) { + auto func = GenScriptFunction(signature->Node()->AsScriptFunction()); + func.metadata->SetAttribute(Signatures::EXTERNAL); + prog_->function_table.emplace(func.name, std::move(func)); + } +} + +void ETSEmitter::EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init) +{ + if (!init) { + return; + } + + const auto *type = init->TsType(); + + if (!type->HasTypeFlag(checker::TypeFlag::CONSTANT)) { + return; + } + + auto typeKind = checker::ETSChecker::TypeKind(type); + + classField.metadata->SetFieldType(classField.type); + switch (typeKind) { + case checker::TypeFlag::ETS_BOOLEAN: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsETSBooleanType()->GetValue())); + break; + } + case checker::TypeFlag::BYTE: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsByteType()->GetValue())); + break; + } + case checker::TypeFlag::SHORT: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsShortType()->GetValue())); + break; + } + case checker::TypeFlag::INT: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsIntType()->GetValue())); + break; + } + case checker::TypeFlag::LONG: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsLongType()->GetValue())); + break; + } + case checker::TypeFlag::FLOAT: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsFloatType()->GetValue())); + break; + } + case checker::TypeFlag::DOUBLE: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsDoubleType()->GetValue())); + break; + } + case checker::TypeFlag::CHAR: { + classField.metadata->SetValue( + pandasm::ScalarValue::Create(type->AsCharType()->GetValue())); + break; + } + case checker::TypeFlag::ETS_OBJECT: { + classField.metadata->SetValue(pandasm::ScalarValue::Create( + type->AsETSObjectType()->AsETSStringType()->GetValue().Mutf8())); + break; + } + default: { + UNREACHABLE(); + } + } +} + +void ETSEmitter::GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external) +{ + auto *scriptFunc = methodDef->Function(); + + if (scriptFunc->Body()) { + return; + } + + auto func = GenScriptFunction(scriptFunc); + func.metadata->SetAccessFlags(func.metadata->GetAccessFlags() | ACC_ABSTRACT); + if (external) { + func.metadata->SetAttribute(Signatures::EXTERNAL); + } + prog_->function_table.emplace(func.name, std::move(func)); +} + +void ETSEmitter::GenClassField(const ir::ClassProperty *field, pandasm::Record &classRecord, bool external) +{ + auto classField = pandasm::Field(prog_->lang); + const auto *ident = field->Id(); + std::stringstream ss; + field->TsType()->ToAssemblerType(ss); + + classField.name = ident->Name().Mutf8(); + classField.type = pandasm::Type(ss.str(), field->TsType()->Rank()); + + classField.metadata->SetAccessFlags(TranslateModifierFlags(field->Modifiers())); + + if (external) { + classField.metadata->SetAttribute(Signatures::EXTERNAL); + } else { + EmitDefaultFieldValue(classField, field->Value()); + } + classRecord.field_list.emplace_back(std::move(classField)); +} + +void ETSEmitter::GenClassInheritedFields(const checker::ETSObjectType *baseType, pandasm::Record &classRecord) +{ + std::vector foreignProps = baseType->ForeignProperties(); + + for (const auto *foreignProp : foreignProps) { + auto *declNode = foreignProp->Declaration()->Node(); + if (!declNode->IsClassProperty()) { + continue; + } + + GenClassField(declNode->AsClassProperty(), classRecord, true); + } +} + +void ETSEmitter::GenGlobalArrayRecord(checker::ETSArrayType *arrayType, checker::Signature *signature) +{ + std::stringstream ss; + arrayType->ToAssemblerType(ss); + + auto arrayRecord = pandasm::Record(ss.str(), prog_->lang); + + auto func = GenExternalFunction(signature, true); + func.params.emplace(func.params.begin(), pandasm::Type(ss.str(), 0), EXTENSION); + + prog_->function_table.emplace(func.name, std::move(func)); + + arrayRecord.metadata->SetAttribute(Signatures::EXTERNAL); + prog_->record_table.emplace(arrayRecord.name, std::move(arrayRecord)); +} + +void ETSEmitter::GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external) +{ + auto *baseType = interfaceDecl->TsType()->AsETSObjectType(); + + auto interfaceRecord = pandasm::Record(baseType->Name().Mutf8(), prog_->lang); + + if (external) { + interfaceRecord.metadata->SetAttribute(Signatures::EXTERNAL); + } + + uint32_t accessFlags = ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE; + + if (interfaceDecl->IsStatic()) { + accessFlags |= ACC_STATIC; + } + + interfaceRecord.metadata->SetAccessFlags(accessFlags); + interfaceRecord.source_file = context_->Binder()->Program()->SourceFile().Mutf8(); + interfaceRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT); + + for (auto *it : baseType->Interfaces()) { + interfaceRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, it->Name().Mutf8()); + } + + GenClassInheritedFields(baseType, interfaceRecord); + + for (const auto *prop : interfaceDecl->Body()->Body()) { + if (prop->IsClassProperty()) { + GenClassField(prop->AsClassProperty(), interfaceRecord, false); + } else if (prop->IsMethodDefinition()) { + GenInterfaceMethodDefinition(prop->AsMethodDefinition(), external); + } + } + + prog_->record_table.emplace(interfaceRecord.name, std::move(interfaceRecord)); +} + +void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool external) +{ + auto classRecord = pandasm::Record(classDef->InternalName().Mutf8(), prog_->lang); + + if (external) { + classRecord.metadata->SetAttribute(Signatures::EXTERNAL); + } + + uint32_t accessFlags = ACC_PUBLIC; + + if (classDef->IsAbstract()) { + accessFlags |= ACC_ABSTRACT; + } + + if (!classDef->IsOpen()) { + accessFlags |= ACC_FINAL; + } + + if (classDef->IsStatic()) { + accessFlags |= ACC_STATIC; + } + + classRecord.metadata->SetAccessFlags(accessFlags); + classRecord.source_file = context_->Binder()->Program()->SourceFile().Mutf8(); + + auto *baseType = classDef->TsType()->AsETSObjectType(); + + if (baseType->SuperType()) { + classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, + baseType->SuperType()->AssemblerName().Mutf8()); + } else { + classRecord.metadata->SetAttributeValue(Signatures::EXTENDS_ATTRIBUTE, Signatures::BUILTIN_OBJECT); + } + + for (auto *it : baseType->Interfaces()) { + classRecord.metadata->SetAttributeValue(Signatures::IMPLEMENTS_ATTRIBUTE, it->Name().Mutf8()); + } + + if (!classDef->IsAbstract()) { + GenClassInheritedFields(baseType, classRecord); + } + + for (const auto *prop : classDef->Body()) { + if (!prop->IsClassProperty()) { + continue; + } + + GenClassField(prop->AsClassProperty(), classRecord, external); + } + + std::vector annotations; + if (classDef->TypeParams()) { + annotations.emplace_back(GenAnnotationSignature(classDef)); + } + + const ir::AstNode *parent = classDef->Parent(); + while (parent != nullptr) { + if (parent->IsMethodDefinition()) { + annotations.emplace_back(GenAnnotationEnclosingMethod(parent->AsMethodDefinition())); + annotations.emplace_back(GenAnnotationInnerClass(classDef, parent)); + break; + } + if (parent->IsClassDefinition()) { + annotations.emplace_back(GenAnnotationEnclosingClass( + parent->AsClassDefinition()->TsType()->AsETSObjectType()->AssemblerName().Utf8())); + annotations.emplace_back(GenAnnotationInnerClass(classDef, parent)); + break; + } + parent = parent->Parent(); + } + + if (!annotations.empty()) { + classRecord.metadata->SetAnnotations(std::move(annotations)); + } + + prog_->record_table.emplace(classRecord.name, std::move(classRecord)); +} + +pandasm::AnnotationData ETSEmitter::GenAnnotationSignature(const ir::ClassDefinition *classDef) +{ + static constexpr std::string_view object = "Lets/lang/Object;"; + std::vector parts {}; + std::stringstream ss {}; + const auto ¶ms = classDef->TypeParams()->Params(); + + bool firstIteration = true; + for (const auto *param : params) { + if (firstIteration) { + ss << Signatures::GENERIC_BEGIN; + firstIteration = false; + } + ss << param->Name()->Name() << Signatures::MANGLE_BEGIN; + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + + std::stringstream {}.swap(ss); + if (!param->Constraint()) { + ss << object; + } else { + param->Constraint()->AsETSTypeReference()->TsType()->ToAssemblerType(ss); + auto str = ss.str(); + std::replace(str.begin(), str.end(), *Signatures::METHOD_SEPARATOR.begin(), + *Signatures::NAMESPACE_SEPARATOR.begin()); + std::stringstream {}.swap(ss); + ss << Signatures::CLASS_REF_BEGIN << str << Signatures::MANGLE_SEPARATOR; + } + + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + std::stringstream {}.swap(ss); // cleanup + } + + ss << Signatures::GENERIC_END; + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + + std::stringstream {}.swap(ss); + if (!classDef->TsType()->AsETSObjectType()->SuperType()) { + ss << object; + } else { + ss << Signatures::CLASS_REF_BEGIN; + auto superType = classDef->TsType()->AsETSObjectType()->SuperType()->AssemblerName().Mutf8(); + std::replace(superType.begin(), superType.end(), *Signatures::MANGLE_SEPARATOR.begin(), + *Signatures::NAMESPACE_SEPARATOR.begin()); + ss << superType << Signatures::MANGLE_SEPARATOR; + } + parts.emplace_back(pandasm::ScalarValue::Create(ss.str())); + + GenAnnotation(Signatures::DALVIK_ANNOTATION_SIGNATURE); + pandasm::AnnotationData signature(Signatures::DALVIK_ANNOTATION_SIGNATURE); + pandasm::AnnotationElement value( + Signatures::ANNOTATION_KEY_VALUE, + std::make_unique(pandasm::Value::Type::STRING, std::move(parts))); + signature.AddElement(std::move(value)); + return signature; +} + +pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef) +{ + GenAnnotation(Signatures::DALVIK_ANNOTATION_ENCLOSING_METHOD); + pandasm::AnnotationData enclosing_method(Signatures::DALVIK_ANNOTATION_ENCLOSING_METHOD); + pandasm::AnnotationElement value( + Signatures::ANNOTATION_KEY_VALUE, + std::make_unique(pandasm::ScalarValue::Create( + methodDef->Function()->Scope()->InternalName().Mutf8()))); + enclosing_method.AddElement(std::move(value)); + return enclosing_method; +} + +pandasm::AnnotationData ETSEmitter::GenAnnotationEnclosingClass(std::string_view className) +{ + GenAnnotation(Signatures::DALVIK_ANNOTATION_ENCLOSING_CLASS); + pandasm::AnnotationData enclosingClass(Signatures::DALVIK_ANNOTATION_ENCLOSING_CLASS); + pandasm::AnnotationElement value( + Signatures::ANNOTATION_KEY_VALUE, + std::make_unique( + pandasm::ScalarValue::Create(pandasm::Type::FromName(className, true)))); + enclosingClass.AddElement(std::move(value)); + return enclosingClass; +} + +pandasm::AnnotationData ETSEmitter::GenAnnotationInnerClass(const ir::ClassDefinition *classDef, + const ir::AstNode *parent) +{ + GenAnnotation(Signatures::DALVIK_ANNOTATION_INNER_CLASS); + pandasm::AnnotationData innerClass(Signatures::DALVIK_ANNOTATION_INNER_CLASS); + const bool isAnonymous = classDef->Modifiers() & ir::ClassDefinitionModifiers::ANONYMOUS; + pandasm::AnnotationElement name(Signatures::ANNOTATION_KEY_NAME, + std::make_unique( + isAnonymous + ? pandasm::ScalarValue::Create(0) + : pandasm::ScalarValue::Create( + classDef->TsType()->AsETSObjectType()->AssemblerName().Mutf8()))); + innerClass.AddElement(std::move(name)); + + pandasm::AnnotationElement accessFlags( + Signatures::ANNOTATION_KEY_ACCESS_FLAGS, + std::make_unique( + pandasm::ScalarValue::Create(TranslateModifierFlags(parent->Modifiers())))); + innerClass.AddElement(std::move(accessFlags)); + return innerClass; +} + +void ETSEmitter::GenAnnotation(std::string_view recordNameView, bool isRuntime, bool isType) +{ + const std::string recordName(recordNameView); + const auto recordIt = prog_->record_table.find(recordName); + if (recordIt == prog_->record_table.end()) { + pandasm::Record record(recordName, EXTENSION); + record.metadata->SetAttribute(Signatures::EXTERNAL); + record.metadata->SetAttribute(Signatures::ANNOTATION_ATTRIBUTE); + if (isRuntime && isType) { + record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, + Signatures::RUNTIME_TYPE_ANNOTATION); + } else if (isRuntime && !isType) { + record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::RUNTIME_ANNOTATION); + } else if (!isRuntime && isType) { + record.metadata->SetAttributeValue(Signatures::ANNOTATION_ATTRIBUTE_TYPE, Signatures::TYPE_ANNOTATION); + } + prog_->record_table.emplace(record.name, std::move(record)); + } +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/ETSemitter.h b/compiler/core/ETSemitter.h new file mode 100644 index 0000000000000000000000000000000000000000..02a304c174f169f1740e1a13393690aeefb0d384 --- /dev/null +++ b/compiler/core/ETSemitter.h @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CORE_ETS_EMITTER_H +#define ES2PANDA_COMPILER_CORE_ETS_EMITTER_H + +#include "emitter.h" + +namespace panda::es2panda::binder { +class RecordTable; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::ir { +class ClassDefinition; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::checker { +class ETSObjectType; +class ETSArrayType; +class Signature; +} // namespace panda::es2panda::checker + +namespace panda::pandasm { +struct Field; +struct Record; +struct ItemMetadata; +struct AnnotationData; +} // namespace panda::pandasm + +namespace panda::es2panda::compiler { + +class ETSFunctionEmitter : public FunctionEmitter { +public: + ETSFunctionEmitter(const CodeGen *cg, ProgramElement *programElement) : FunctionEmitter(cg, programElement) {} + ~ETSFunctionEmitter() = default; + NO_COPY_SEMANTIC(ETSFunctionEmitter); + NO_MOVE_SEMANTIC(ETSFunctionEmitter); + +protected: + const ETSGen *Stsg() const + { + return reinterpret_cast(cg_); + } + + pandasm::Function *GenFunctionSignature() override; + + void GenFunctionAnnotations(pandasm::Function *func) override; + void GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + binder::LocalVariable *variable) const override; +}; + +class ETSEmitter : public Emitter { +public: + explicit ETSEmitter(const CompilerContext *context) : Emitter(context) {} + virtual ~ETSEmitter() = default; + NO_COPY_SEMANTIC(ETSEmitter); + NO_MOVE_SEMANTIC(ETSEmitter); + + void GenAnnotation() override; + +private: + void GenExternalRecord(binder::RecordTable *recordTable); + void GenGlobalArrayRecord(checker::ETSArrayType *arrType, checker::Signature *signature); + void GenClassRecord(const ir::ClassDefinition *classDef, bool external); + void GenAnnotation(std::string_view record_name, bool isRuntime = false, bool isType = false); + void GenInterfaceRecord(const ir::TSInterfaceDeclaration *interfaceDecl, bool external); + void EmitDefaultFieldValue(pandasm::Field &classField, const ir::Expression *init); + void GenClassField(const ir::ClassProperty *field, pandasm::Record &classRecord, bool external); + void GenInterfaceMethodDefinition(const ir::MethodDefinition *methodDef, bool external); + void GenClassInheritedFields(const checker::ETSObjectType *baseType, pandasm::Record &classRecord); + pandasm::AnnotationData GenAnnotationSignature(const ir::ClassDefinition *classDef); + pandasm::AnnotationData GenAnnotationEnclosingClass(std::string_view className); + pandasm::AnnotationData GenAnnotationEnclosingMethod(const ir::MethodDefinition *methodDef); + pandasm::AnnotationData GenAnnotationInnerClass(const ir::ClassDefinition *classDef, const ir::AstNode *parent); +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/ETSfunction.cpp b/compiler/core/ETSfunction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b900541742c515c237ce3797989a0362684d4967 --- /dev/null +++ b/compiler/core/ETSfunction.cpp @@ -0,0 +1,159 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "ETSfunction.h" + +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/es2panda/binder/scope.h" +#include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/compiler/base/lreference.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/envScope.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" +#include "plugins/ecmascript/es2panda/ir/base/classProperty.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" +#include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" +#include "plugins/ecmascript/es2panda/checker/types/ets/types.h" + +namespace panda::es2panda::compiler { +void ETSFunction::CallImplicitCtor(ETSGen *etsg) +{ + RegScope rs(etsg); + auto *superType = etsg->ContainingClassType()->SuperType(); + + if (!superType) { + etsg->CallThisStatic0(etsg->RootNode(), etsg->GetThisReg(), Signatures::BUILTIN_OBJECT_CTOR); + + return; + } + + auto res = std::find_if(superType->ConstructSignatures().cbegin(), superType->ConstructSignatures().cend(), + [](const checker::Signature *sig) { return sig->Params().empty(); }); + + if (res == superType->ConstructSignatures().cend()) { + return; + } + + etsg->CallThisStatic0(etsg->RootNode(), etsg->GetThisReg(), (*res)->InternalName()); +} + +void ETSFunction::CompileSourceBlock(ETSGen *etsg, const ir::BlockStatement *block) +{ + auto *scriptFunc = etsg->RootNode()->AsScriptFunction(); + + if (scriptFunc->IsStaticBlock()) { + const auto *classDef = etsg->ContainingClassType()->GetDeclNode()->AsClassDefinition(); + + for (const auto *prop : classDef->Body()) { + if (!prop->IsClassProperty() || !prop->IsStatic()) { + continue; + } + + prop->AsClassProperty()->Compile(etsg); + } + } else if (scriptFunc->IsConstructor()) { + if (scriptFunc->IsImplicitConstructor()) { + CallImplicitCtor(etsg); + } + + const auto *classDef = etsg->ContainingClassType()->GetDeclNode()->AsClassDefinition(); + + for (const auto *prop : classDef->Body()) { + if (!prop->IsClassProperty() || prop->IsStatic()) { + continue; + } + + prop->AsClassProperty()->Compile(etsg); + } + } + + const auto &statements = block->Statements(); + + if (statements.empty()) { + etsg->SetFirstStmt(block); + etsg->EmitReturnVoid(block); + return; + } + + etsg->SetFirstStmt(statements.front()); + + etsg->CompileStatementList(statements); + + if (!statements.back()->IsReturnStatement()) { + if (etsg->ReturnType()->IsETSVoidType()) { + etsg->EmitReturnVoid(statements.back()); + } else { + etsg->LoadDefaultValue(statements.back(), scriptFunc->Signature()->ReturnType()); + etsg->ReturnAcc(statements.back()); + } + } +} + +void ETSFunction::CompileFunctionParameterDeclaration(ETSGen *etsg, const ir::ScriptFunction *func) +{ + ScopeContext scopeCtx(etsg, func->Scope()->ParamScope()); + + uint32_t index = 0; + + for (const auto *param : func->Params()) { + if (!param->IsRestElement()) { + index++; + continue; + } + + auto ref = JSLReference::Create(etsg, param, true); + [[maybe_unused]] binder::Variable *paramVar = ref.Variable(); + ASSERT(paramVar && paramVar->IsLocalVariable()); + + VReg paramReg = VReg(binder::Binder::MANDATORY_PARAMS_NUMBER + VReg::PARAM_START + index++); + ASSERT(paramVar->AsLocalVariable()->Vreg() == paramReg); + + ref.SetValue(); + index++; + } +} + +void ETSFunction::CompileFunction(ETSGen *etsg) +{ + const auto *decl = etsg->RootNode()->AsScriptFunction(); + CompileFunctionParameterDeclaration(etsg, decl); + + const ir::AstNode *body = decl->Body(); + + if (body->IsExpression()) { + // TODO + } else { + CompileSourceBlock(etsg, body->AsBlockStatement()); + } +} +void ETSFunction::Compile(ETSGen *etsg) +{ + FunctionRegScope lrs(etsg); + auto *topScope = etsg->TopScope(); + + if (topScope->IsFunctionScope()) { + CompileFunction(etsg); + } else { + ASSERT(topScope->IsGlobalScope()); + CompileSourceBlock(etsg, etsg->RootNode()->AsBlockStatement()); + } + + etsg->SortCatchTables(); +} + +} // namespace panda::es2panda::compiler diff --git a/compiler/core/ETSfunction.h b/compiler/core/ETSfunction.h new file mode 100644 index 0000000000000000000000000000000000000000..794bc4f556b6611a4b2e3a25d9c20af933b02293 --- /dev/null +++ b/compiler/core/ETSfunction.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CORE_ETSFUNCTION_H +#define ES2PANDA_COMPILER_CORE_ETSFUNCTION_H + +#include "plugins/ecmascript/es2panda/ir/irnode.h" + +namespace panda::es2panda::ir { +class ScriptFunction; +class BlockStatement; +} // namespace panda::es2panda::ir + +namespace panda::es2panda::compiler { +class ETSGen; + +class ETSFunction { +public: + ETSFunction() = delete; + + static void Compile(ETSGen *etsg); + +private: + static void CompileSourceBlock(ETSGen *etsg, const ir::BlockStatement *block); + static void CompileFunctionParameterDeclaration(ETSGen *etsg, const ir::ScriptFunction *func); + static void CompileFunction(ETSGen *etsg); + static void CallImplicitCtor(ETSGen *etsg); +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/JSemitter.cpp b/compiler/core/JSemitter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a0010fe3130b1d089a1b936957e1af4cad6bfea --- /dev/null +++ b/compiler/core/JSemitter.cpp @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2021 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. + */ + +#include "JSemitter.h" + +#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/binder/binder.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "assembly-program.h" + +namespace panda::es2panda::compiler { +pandasm::Function *JSFunctionEmitter::GenFunctionSignature() +{ + auto *func = new pandasm::Function(cg_->InternalName().Mutf8(), panda_file::SourceLang::ECMASCRIPT); + programElement_->func = func; + + size_t paramCount = cg_->InternalParamCount(); + func->params.reserve(paramCount); + + for (uint32_t i = 0; i < paramCount; ++i) { + func->params.emplace_back(pandasm::Type("any", 0), panda_file::SourceLang::ECMASCRIPT); + } + + func->regs_num = VReg::REG_START - cg_->TotalRegsNum(); + func->return_type = pandasm::Type("any", 0); + + return func; +} + +void JSFunctionEmitter::GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + [[maybe_unused]] binder::LocalVariable *variable) const +{ + variableDebug.signature = "any"; + variableDebug.signature_type = "any"; +} + +void JSFunctionEmitter::GenFunctionAnnotations(pandasm::Function *func) +{ + pandasm::AnnotationData funcAnnotationData("_ESAnnotation"); + pandasm::AnnotationElement icSizeAnnotationElement( + "icSize", std::make_unique( + pandasm::ScalarValue::Create(Pg()->IcSize()))); + funcAnnotationData.AddElement(std::move(icSizeAnnotationElement)); + + pandasm::AnnotationElement parameterLengthAnnotationElement( + "parameterLength", std::make_unique( + pandasm::ScalarValue::Create(Pg()->FormalParametersCount()))); + funcAnnotationData.AddElement(std::move(parameterLengthAnnotationElement)); + + pandasm::AnnotationElement funcNameAnnotationElement( + "funcName", std::make_unique( + pandasm::ScalarValue::Create(Pg()->FunctionName().Mutf8()))); + funcAnnotationData.AddElement(std::move(funcNameAnnotationElement)); + + func->metadata->AddAnnotations({funcAnnotationData}); +} + +void JSEmitter::GenAnnotation() +{ + prog_->lang = panda_file::SourceLang::ECMASCRIPT; + GenESAnnoatationRecord(); + GenESModuleModeRecord(context_->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); +} + +void JSEmitter::GenESAnnoatationRecord() +{ + auto annotationRecord = pandasm::Record("_ESAnnotation", prog_->lang); + annotationRecord.metadata->SetAttribute("external"); + annotationRecord.metadata->SetAccessFlags(ACC_ANNOTATION); + prog_->record_table.emplace(annotationRecord.name, std::move(annotationRecord)); +} + +void JSEmitter::GenESModuleModeRecord(bool isModule) +{ + auto modeRecord = pandasm::Record("_ESModuleMode", prog_->lang); + modeRecord.metadata->SetAccessFlags(ACC_PUBLIC); + + auto modeField = pandasm::Field(prog_->lang); + modeField.name = "isModule"; + modeField.type = pandasm::Type("u8", 0); + modeField.metadata->SetValue( + pandasm::ScalarValue::Create(static_cast(isModule))); + + modeRecord.field_list.emplace_back(std::move(modeField)); + + prog_->record_table.emplace(modeRecord.name, std::move(modeRecord)); +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/JSemitter.h b/compiler/core/JSemitter.h new file mode 100644 index 0000000000000000000000000000000000000000..9db4085616c0315a1256a63b213010cb6b02557d --- /dev/null +++ b/compiler/core/JSemitter.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CORE_JS_EMITTER_H +#define ES2PANDA_COMPILER_CORE_JS_EMITTER_H + +#include "emitter.h" + +namespace panda::es2panda::compiler { + +class JSFunctionEmitter : public FunctionEmitter { +public: + JSFunctionEmitter(const CodeGen *cg, ProgramElement *programElement) : FunctionEmitter(cg, programElement) {} + ~JSFunctionEmitter() = default; + NO_COPY_SEMANTIC(JSFunctionEmitter); + NO_MOVE_SEMANTIC(JSFunctionEmitter); + +protected: + const PandaGen *Pg() const + { + return reinterpret_cast(cg_); + } + + pandasm::Function *GenFunctionSignature() override; + + void GenFunctionAnnotations(pandasm::Function *func) override; + void GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + binder::LocalVariable *variable) const override; +}; + +class JSEmitter : public Emitter { +public: + explicit JSEmitter(const CompilerContext *context) : Emitter(context) {} + virtual ~JSEmitter() = default; + NO_COPY_SEMANTIC(JSEmitter); + NO_MOVE_SEMANTIC(JSEmitter); + + void GenAnnotation() override; + +private: + void GenESAnnoatationRecord(); + void GenESModuleModeRecord(bool isModule); +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/codeGen.cpp b/compiler/core/codeGen.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af9e56e67a6556db286acf909b08ea4aaaf5972a --- /dev/null +++ b/compiler/core/codeGen.cpp @@ -0,0 +1,196 @@ +/** + * Copyright (c) 2021-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. + */ + +#include "codeGen.h" + +#include "plugins/ecmascript/es2panda/compiler/core/emitter.h" +#include "plugins/ecmascript/es2panda/compiler/core/regAllocator.h" +#include "plugins/ecmascript/es2panda/compiler/core/regScope.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" +#include "plugins/ecmascript/es2panda/compiler/core/dynamicContext.h" +#include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" +#include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" +#include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" + +namespace panda::es2panda::compiler { +Label *CodeGen::AllocLabel() +{ + std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++); + return sa_.AllocLabel(std::move(id)); +} + +bool CodeGen::IsDebug() const +{ + return context_->IsDebug(); +} + +uint32_t CodeGen::ParamCount() const +{ + if (rootNode_->IsProgram()) { + return 0; + } + + return rootNode_->AsScriptFunction()->Params().size(); +} + +uint32_t CodeGen::FormalParametersCount() const +{ + if (rootNode_->IsProgram()) { + return 0; + } + + ASSERT(rootNode_->IsScriptFunction()); + + return rootNode_->AsScriptFunction()->FormalParamsLength(); +} + +uint32_t CodeGen::InternalParamCount() const +{ + static const uint32_t HIDDEN_PARAMS = 3; + return ParamCount() + HIDDEN_PARAMS; +} + +const util::StringView &CodeGen::InternalName() const +{ + return topScope_->InternalName(); +} + +const util::StringView &CodeGen::FunctionName() const +{ + return topScope_->Name(); +} + +binder::Binder *CodeGen::Binder() const +{ + return context_->Binder(); +} + +int32_t CodeGen::AddLiteralBuffer(LiteralBuffer &&buf) +{ + programElement_->buffStorage.emplace_back(std::move(buf)); + return literalBufferIdx_++; +} + +void CodeGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str) +{ + sa_.Emit(node, str); +} + +void CodeGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label) +{ + sa_.AddLabel(label); +} + +void CodeGen::Branch(const ir::AstNode *node, Label *label) +{ + sa_.Emit(node, label); +} + +bool CodeGen::CheckControlFlowChange() +{ + const auto *iter = dynamicContext_; + + while (iter) { + if (iter->HasFinalizer()) { + return true; + } + + iter = iter->Prev(); + } + + return false; +} + +Label *CodeGen::ControlFlowChangeBreak(const ir::Identifier *label) +{ + auto *iter = dynamicContext_; + + util::StringView labelName = label ? label->Name() : LabelTarget::BREAK_LABEL; + Label *breakTarget = nullptr; + + while (iter) { + iter->AbortContext(ControlFlowChange::BREAK, labelName); + + const auto &labelTargetName = iter->Target().BreakLabel(); + + if (iter->Target().BreakTarget()) { + breakTarget = iter->Target().BreakTarget(); + } + + if (labelTargetName == labelName) { + break; + } + + iter = iter->Prev(); + } + + return breakTarget; +} + +Label *CodeGen::ControlFlowChangeContinue(const ir::Identifier *label) +{ + auto *iter = dynamicContext_; + util::StringView labelName = label ? label->Name() : LabelTarget::CONTINUE_LABEL; + Label *continueTarget = nullptr; + + while (iter) { + iter->AbortContext(ControlFlowChange::CONTINUE, labelName); + + const auto &labelTargetName = iter->Target().ContinueLabel(); + + if (iter->Target().ContinueTarget()) { + continueTarget = iter->Target().ContinueTarget(); + } + + if (labelTargetName == labelName) { + break; + } + + iter = iter->Prev(); + } + + return continueTarget; +} + +uint32_t CodeGen::TryDepth() const +{ + const auto *iter = dynamicContext_; + uint32_t depth = 0; + + while (iter) { + if (iter->HasTryCatch()) { + depth++; + } + + iter = iter->Prev(); + } + + return depth; +} + +CatchTable *CodeGen::CreateCatchTable() +{ + auto *catchTable = allocator_->New(this, TryDepth()); + catchList_.push_back(catchTable); + return catchTable; +} + +void CodeGen::SortCatchTables() +{ + std::sort(catchList_.begin(), catchList_.end(), + [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); }); +} + +} // namespace panda::es2panda::compiler diff --git a/compiler/core/codeGen.h b/compiler/core/codeGen.h new file mode 100644 index 0000000000000000000000000000000000000000..a0c42f6921cc3dd3d9de1fc907498c8626903d99 --- /dev/null +++ b/compiler/core/codeGen.h @@ -0,0 +1,208 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CORE_CODEGEN_H +#define ES2PANDA_COMPILER_CORE_CODEGEN_H + +#include "plugins/ecmascript/es2panda/compiler/base/literals.h" +#include "plugins/ecmascript/es2panda/compiler/core/regAllocator.h" +#include "plugins/ecmascript/es2panda/compiler/core/regScope.h" + +namespace panda::es2panda::compiler { +class CatchTable; +class DynamicContext; + +enum class Constant { + JS_NAN, + JS_HOLE, + JS_INFINITY, + JS_UNDEFINED, + JS_NULL, + JS_TRUE, + JS_FALSE, + JS_SYMBOL, + JS_GLOBAL, +}; + +class DebugInfo { +public: + explicit DebugInfo(ArenaAllocator *allocator) : variableDebugInfo(allocator->Adapter()) {}; + DEFAULT_COPY_SEMANTIC(DebugInfo); + DEFAULT_MOVE_SEMANTIC(DebugInfo); + ~DebugInfo() = default; + + ArenaVector variableDebugInfo; + const ir::Statement *firstStmt {}; +}; + +class CodeGen { +public: + explicit CodeGen(ArenaAllocator *allocator, RegSpiller *spiller, CompilerContext *context, + binder::FunctionScope *scope, ProgramElement *programElement) + : allocator_(allocator), + context_(context), + debugInfo_(allocator_), + topScope_(scope), + scope_(topScope_), + rootNode_(scope->Node()), + insns_(allocator_->Adapter()), + catchList_(allocator_->Adapter()), + programElement_(programElement), + sa_(this), + ra_(this, spiller), + rra_(this, spiller) + { + } + ~CodeGen() = default; + NO_COPY_SEMANTIC(CodeGen); + NO_MOVE_SEMANTIC(CodeGen); + + static constexpr auto MAX_RANGE_CALL_ARG = 128; + + inline ArenaAllocator *Allocator() const + { + return allocator_; + } + + const ArenaVector &CatchList() const + { + return catchList_; + } + + binder::FunctionScope *TopScope() const + { + return topScope_; + } + + binder::Scope *Scope() const + { + return scope_; + } + + const ir::AstNode *RootNode() const + { + return rootNode_; + } + + ArenaList &Insns() + { + return insns_; + } + + const ArenaList &Insns() const + { + return insns_; + } + + VReg AllocReg() + { + return VReg(usedRegs_--); + } + + VReg AllocReg(const checker::Type *type) + { + return VReg(usedRegs_--, type); + } + + VReg NextReg() const + { + return VReg(usedRegs_); + } + + uint32_t TotalRegsNum() const + { + return totalRegs_; + } + + size_t LabelCount() const + { + return labelId_; + } + + const DebugInfo &Debuginfo() const + { + return debugInfo_; + } + + uint32_t IcSize() const + { + return 0; + } + + bool IsDebug() const; + RegSpiller *GetRegSpiller() const; + uint32_t ParamCount() const; + uint32_t FormalParametersCount() const; + uint32_t InternalParamCount() const; + const util::StringView &InternalName() const; + const util::StringView &FunctionName() const; + binder::Binder *Binder() const; + + Label *AllocLabel(); + int32_t AddLiteralBuffer(LiteralBuffer &&buf); + + void LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str); + + void SetLabel(const ir::AstNode *node, Label *label); + void Branch(const ir::AstNode *node, class Label *label); + bool CheckControlFlowChange(); + Label *ControlFlowChangeBreak(const ir::Identifier *label = nullptr); + Label *ControlFlowChangeContinue(const ir::Identifier *label); + + uint32_t TryDepth() const; + CatchTable *CreateCatchTable(); + void SortCatchTables(); + + void SetFirstStmt(const ir::Statement *stmt) + { + debugInfo_.firstStmt = stmt; + } + + [[noreturn]] static void Unimplemented() + { + throw Error(ErrorType::GENERIC, "", "Unimplemented code path"); + } + +protected: + ArenaAllocator *allocator_; + CompilerContext *context_; + DebugInfo debugInfo_; + binder::FunctionScope *topScope_; + binder::Scope *scope_; + const ir::AstNode *rootNode_; + ArenaList insns_; + ArenaVector catchList_; + ProgramElement *programElement_; + DynamicContext *dynamicContext_ {}; + + SimpleAllocator sa_; + RegAllocator ra_; + RangeRegAllocator rra_; + size_t labelId_ {0}; + int32_t literalBufferIdx_ {0}; + + uint32_t usedRegs_ {VReg::REG_START}; + uint32_t totalRegs_ {VReg::REG_START}; + friend class ScopeContext; + friend class RegScope; + friend class LocalRegScope; + friend class LoopRegScope; + friend class ParamRegScope; + friend class FunctionRegScope; + friend class DynamicContext; +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/compileJob.cpp b/compiler/core/compileJob.cpp new file mode 100644 index 0000000000000000000000000000000000000000..419ca79d62791acccfd974f7225eda45c86c1df7 --- /dev/null +++ b/compiler/core/compileJob.cpp @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#include "compileQueue.h" + +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" + +namespace panda::es2panda::compiler { + +void CompileJob::Run() +{ + std::unique_lock lock(m_); + cond_.wait(lock, [this] { return dependencies_ == 0; }); + + context_->GetCodeGenCb()(context_, scope_, &programElement_); + + if (dependant_) { + dependant_->Signal(); + } +} + +void CompileJob::DependsOn(CompileJob *job) +{ + job->dependant_ = this; + dependencies_++; +} + +void CompileJob::Signal() +{ + { + std::lock_guard lock(m_); + dependencies_--; + } + + cond_.notify_one(); +} +} // namespace panda::es2panda::compiler diff --git a/compiler/core/compileJob.h b/compiler/core/compileJob.h new file mode 100644 index 0000000000000000000000000000000000000000..687217f77f6a802857d6a0f104d7b83bb8880ed8 --- /dev/null +++ b/compiler/core/compileJob.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CORE_COMPILEJOB_H +#define ES2PANDA_COMPILER_CORE_COMPILEJOB_H + +#include "macros.h" +#include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/compiler/core/programElement.h" + +#include +#include + +namespace panda::es2panda::binder { +class FunctionScope; +} // namespace panda::es2panda::binder + +namespace panda::es2panda::compiler { +class CompilerContext; +class ProgramElement; + +class CompileJob { +public: + CompileJob() = default; + NO_COPY_SEMANTIC(CompileJob); + NO_MOVE_SEMANTIC(CompileJob); + ~CompileJob() = default; + + const ProgramElement *GetProgramElement() const + { + return &programElement_; + } + + ProgramElement *GetProgramElement() + { + return &programElement_; + } + + void SetConext(CompilerContext *context, binder::FunctionScope *scope) + { + context_ = context; + scope_ = scope; + } + + void Run(); + void DependsOn(CompileJob *job); + void Signal(); + +private: + std::mutex m_; + std::condition_variable cond_; + CompilerContext *context_ {}; + binder::FunctionScope *scope_ {}; + ProgramElement programElement_; + CompileJob *dependant_ {}; + size_t dependencies_ {0}; +}; +} // namespace panda::es2panda::compiler + +#endif diff --git a/compiler/core/compileQueue.cpp b/compiler/core/compileQueue.cpp index f75127362c9f1d02fc248d49719a451da564720d..6af577190c876d2668411348d2d690199ef62b43 100644 --- a/compiler/core/compileQueue.cpp +++ b/compiler/core/compileQueue.cpp @@ -23,43 +23,6 @@ #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" namespace panda::es2panda::compiler { -CompileJob::CompileJob() : programElement_(std::make_unique()) {} -CompileJob::~CompileJob() = default; - -void CompileJob::Run() -{ - std::unique_lock lock(m_); - cond_.wait(lock, [this] { return dependencies_ == 0; }); - - ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); - PandaGen pg(&allocator, context_, scope_, programElement_.get()); - - Function::Compile(&pg); - - FunctionEmitter funcEmitter(&pg, programElement_.get()); - funcEmitter.Generate(); - - if (dependant_ != nullptr) { - dependant_->Signal(); - } -} - -void CompileJob::DependsOn(CompileJob *job) -{ - job->dependant_ = this; - dependencies_++; -} - -void CompileJob::Signal() -{ - { - std::lock_guard lock(m_); - dependencies_--; - } - - cond_.notify_one(); -} - CompileQueue::CompileQueue(size_t threadCount) { threads_.reserve(threadCount); @@ -147,15 +110,16 @@ void CompileQueue::Wait(const JobsFinishedCb &onFinishedCb) std::unique_lock lock(m_); jobsFinished_.wait(lock, [this]() { return activeWorkers_ == 0 && jobsCount_ == 0; }); + if (!errors_.empty()) { + delete[] jobs_; + // NOLINTNEXTLINE + throw errors_.front(); + } + for (uint32_t i = 0; i < totalJobsCount_; i++) { onFinishedCb(jobs_ + i); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } delete[] jobs_; - - if (!errors_.empty()) { - // NOLINTNEXTLINE - throw errors_.front(); - } } } // namespace panda::es2panda::compiler diff --git a/compiler/core/compileQueue.h b/compiler/core/compileQueue.h index 39d39f1bc05b1af427395add0964299981ed7071..bd31c32f550b03cb2bb715dbd5f163c095fceebf 100644 --- a/compiler/core/compileQueue.h +++ b/compiler/core/compileQueue.h @@ -19,6 +19,7 @@ #include "macros.h" #include "os/thread.h" #include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/compiler/core/compileJob.h" #include #include @@ -30,39 +31,6 @@ class FunctionScope; namespace panda::es2panda::compiler { class CompilerContext; -class ProgramElement; - -class CompileJob { -public: - CompileJob(); - NO_COPY_SEMANTIC(CompileJob); - NO_MOVE_SEMANTIC(CompileJob); - ~CompileJob(); - - ProgramElement *GetProgramElement() const - { - return programElement_.get(); - } - - void SetConext(CompilerContext *context, binder::FunctionScope *scope) - { - context_ = context; - scope_ = scope; - } - - void Run(); - void DependsOn(CompileJob *job); - void Signal(); - -private: - std::mutex m_; - std::condition_variable cond_; - CompilerContext *context_ {}; - binder::FunctionScope *scope_ {}; - std::unique_ptr programElement_; - CompileJob *dependant_ {}; - size_t dependencies_ {0}; -}; class CompileQueue { public: diff --git a/compiler/core/compilerContext.cpp b/compiler/core/compilerContext.cpp index 209d223a95a2c1545e395be5b360dcdb53820344..c071e9f44f8823437e6d4efa7287bf859f755a75 100644 --- a/compiler/core/compilerContext.cpp +++ b/compiler/core/compilerContext.cpp @@ -16,14 +16,5 @@ #include "compilerContext.h" #include -#include "plugins/ecmascript/es2panda/compiler/core/emitter.h" -#include "plugins/ecmascript/es2panda/compiler/base/literals.h" - namespace panda::es2panda::compiler { -CompilerContext::CompilerContext(binder::Binder *binder, CompilerOptions options) - : binder_(binder), emitter_(std::make_unique(this)), options_(options) -{ -} - -CompilerContext::~CompilerContext() = default; } // namespace panda::es2panda::compiler diff --git a/compiler/core/compilerContext.h b/compiler/core/compilerContext.h index 7936fc1abbe38f85d1f793b59c792362dc24a568..3e348d6e5c1aab843220f9cb376c01efd55a9f82 100644 --- a/compiler/core/compilerContext.h +++ b/compiler/core/compilerContext.h @@ -23,34 +23,60 @@ #include -namespace panda::es2panda::ir { -class Literal; -} // namespace panda::es2panda::ir - namespace panda::es2panda::binder { class Binder; +class FunctionScope; } // namespace panda::es2panda::binder +namespace panda::es2panda::checker { +class Checker; +} // namespace panda::es2panda::checker + namespace panda::es2panda::compiler { class Literal; class DebugInfo; class Emitter; +class CodeGen; +class ProgramElement; class CompilerContext { public: - CompilerContext(binder::Binder *binder, CompilerOptions options); + using CodeGenCb = + std::function; + + CompilerContext(binder::Binder *binder, checker::Checker *checker, CompilerOptions options, + const CodeGenCb &codeGenCb) + : binder_(binder), checker_(checker), options_(options), codeGenCb_(codeGenCb) + { + } + NO_COPY_SEMANTIC(CompilerContext); NO_MOVE_SEMANTIC(CompilerContext); - ~CompilerContext(); + ~CompilerContext() = default; binder::Binder *Binder() const { return binder_; } + checker::Checker *Checker() const + { + return checker_; + } + Emitter *GetEmitter() const { - return emitter_.get(); + return emitter_; + } + + void SetEmitter(Emitter *emitter) + { + emitter_ = emitter; + } + + const CodeGenCb &GetCodeGenCb() const + { + return codeGenCb_; } int32_t AddContextLiteral(LiteralBuffer &&literals) @@ -69,6 +95,11 @@ public: return options_.isDebug; } + bool DumpDebugInfo() const + { + return options_.dumpDebugInfo; + } + bool IsDirectEval() const { return options_.isDirectEval; @@ -86,9 +117,11 @@ public: private: binder::Binder *binder_; + checker::Checker *checker_; + Emitter *emitter_ {}; std::vector buffStorage_; - std::unique_ptr emitter_; CompilerOptions options_; + CodeGenCb codeGenCb_ {}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/compilerImpl.cpp b/compiler/core/compilerImpl.cpp index 1531ad8ec1150cc331b6fd4d0ca15569c585590a..e32a0724bb6ecc13a0681a67b5665175f55824f8 100644 --- a/compiler/core/compilerImpl.cpp +++ b/compiler/core/compilerImpl.cpp @@ -15,10 +15,27 @@ #include "compilerImpl.h" -#include "plugins/ecmascript/es2panda/compiler/core/compileQueue.h" #include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" -#include "plugins/ecmascript/es2panda/compiler/core/emitter.h" -#include "plugins/ecmascript/es2panda/typescript/checker.h" +#include "plugins/ecmascript/es2panda/compiler/core/compileQueue.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerImpl.h" +#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/JSemitter.h" +#include "plugins/ecmascript/es2panda/compiler/core/ETSemitter.h" +#include "plugins/ecmascript/es2panda/parser/parserImpl.h" +#include "plugins/ecmascript/es2panda/parser/JSparser.h" +#include "plugins/ecmascript/es2panda/parser/ASparser.h" +#include "plugins/ecmascript/es2panda/parser/TSparser.h" +#include "plugins/ecmascript/es2panda/parser/ETSparser.h" +#include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "plugins/ecmascript/es2panda/binder/JSBinder.h" +#include "plugins/ecmascript/es2panda/binder/ASBinder.h" +#include "plugins/ecmascript/es2panda/binder/TSBinder.h" +#include "plugins/ecmascript/es2panda/binder/ETSBinder.h" +#include "plugins/ecmascript/es2panda/checker/TSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ETSchecker.h" +#include "plugins/ecmascript/es2panda/checker/ASchecker.h" +#include "plugins/ecmascript/es2panda/checker/JSchecker.h" #include "plugins/ecmascript/es2panda/es2panda.h" #include "plugins/ecmascript/es2panda/parser/program/program.h" @@ -26,15 +43,8 @@ #include namespace panda::es2panda::compiler { -CompilerImpl::CompilerImpl(size_t threadCount) : queue_(new CompileQueue(threadCount)) {} - -CompilerImpl::~CompilerImpl() -{ - delete queue_; -} -panda::pandasm::Program *CompilerImpl::Compile(CompilerContext *context, parser::Program *program, - const es2panda::CompilerOptions &options) +void CompilerImpl::HandleContextLiterals(CompilerContext *context) { auto *emitter = context->GetEmitter(); @@ -44,27 +54,98 @@ panda::pandasm::Program *CompilerImpl::Compile(CompilerContext *context, parser: } emitter->LiteralBufferIndex() += context->ContextLiterals().size(); +} - if (program->Extension() == ScriptExtension::AS) { - /* TODO(): AS files are not yet compiled */ - return nullptr; - } +panda::pandasm::Program *CompilerImpl::Emit(CompilerContext *context) +{ + HandleContextLiterals(context); + + queue_.Schedule(context); + + /* Main thread can also be used instead of idling */ + queue_.Consume(); + auto *emitter = context->GetEmitter(); + queue_.Wait([emitter](CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); }); - if (program->Extension() == ScriptExtension::TS) { - ArenaAllocator localAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); - auto checker = std::make_unique(&localAllocator, context->Binder()); - checker->StartChecker(); + return emitter->Finalize(context->DumpDebugInfo(), Signatures::ETS_GLOBAL); +} +template +static CompilerContext::CodeGenCb MakeCompileJob() +{ + return + [](CompilerContext *context, binder::FunctionScope *scope, compiler::ProgramElement *programElement) -> void { + RegSpiller rspl; + ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + CodeGen cg(&allocator, &rspl, context, scope, programElement); + + FunctionEmitter funcEmitter(&cg, programElement); + funcEmitter.Generate(); + }; +} + +using EmitCb = std::function; + +template +static pandasm::Program *CreateCompiler(const CompilationUnit &unit, const EmitCb &emitCb) +{ + ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + auto program = parser::Program::NewProgram(&allocator); + auto parser = Parser(&program, unit.options.stdLib, static_cast(unit.rawParserStatus)); + auto checker = Checker(); + + auto *binder = program.Binder(); + binder->SetProgram(&program); + + CompilerContext context(binder, &checker, unit.options, + MakeCompileJob()); + binder->SetCompilerContext(&context); + + auto emitter = Emitter(&context); + context.SetEmitter(&emitter); + + parser.ParseScript(unit.input); + + if (!checker.StartChecker(binder, unit.options)) { return nullptr; } - queue_->Schedule(context); + emitter.GenAnnotation(); - /* Main thread can also be used instead of idling */ - queue_->Consume(); - queue_->Wait([emitter](CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); }); + return emitCb(&context); +} - return emitter->Finalize(options.dumpDebugInfo); +pandasm::Program *CompilerImpl::Compile(const CompilationUnit &unit) +{ + auto emitCb = [this](CompilerContext *context) -> pandasm::Program * { return Emit(context); }; + + switch (unit.ext) { + case ScriptExtension::TS: { + return CreateCompiler( + unit, emitCb); + } + case ScriptExtension::AS: { + return CreateCompiler( + unit, emitCb); + } + case ScriptExtension::ETS: { + return CreateCompiler( + unit, emitCb); + } + case ScriptExtension::JS: { + return CreateCompiler( + unit, emitCb); + } + default: { + UNREACHABLE(); + return nullptr; + } + } } void CompilerImpl::DumpAsm(const panda::pandasm::Program *prog) diff --git a/compiler/core/compilerImpl.h b/compiler/core/compilerImpl.h index c81d92061a1ed393c5cc7c8dcd90f270999ac117..35cdf0b3dc30ea14bcaea6f46ed4318017371aad 100644 --- a/compiler/core/compilerImpl.h +++ b/compiler/core/compilerImpl.h @@ -17,6 +17,7 @@ #define ES2PANDA_COMPILER_INCLUDE_COMPILER_IMPL_H #include "plugins/ecmascript/es2panda/es2panda.h" +#include "plugins/ecmascript/es2panda/compiler/core/compileQueue.h" #include "macros.h" #include "mem/arena_allocator.h" #include "os/thread.h" @@ -35,19 +36,34 @@ namespace panda::es2panda::compiler { class CompileQueue; class CompilerContext; +class CompilationUnit { +public: + explicit CompilationUnit(const SourceFile &i, const CompilerOptions &o, uint32_t s, ScriptExtension e) + : input(i), options(o), rawParserStatus(s), ext(e) + { + } + const SourceFile &input; + const CompilerOptions &options; + uint32_t rawParserStatus; + ScriptExtension ext; +}; + class CompilerImpl { public: - explicit CompilerImpl(size_t threadCount); - ~CompilerImpl(); + explicit CompilerImpl(size_t threadCount) : queue_(threadCount) {} NO_COPY_SEMANTIC(CompilerImpl); NO_MOVE_SEMANTIC(CompilerImpl); + ~CompilerImpl() = default; + + pandasm::Program *Compile(const CompilationUnit &unit); - panda::pandasm::Program *Compile(CompilerContext *context, parser::Program *program, - const es2panda::CompilerOptions &options); static void DumpAsm(const panda::pandasm::Program *prog); private: - CompileQueue *queue_; + panda::pandasm::Program *Emit(CompilerContext *context); + static void HandleContextLiterals(CompilerContext *context); + + CompileQueue queue_; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/dynamicContext.cpp b/compiler/core/dynamicContext.cpp index eb936f4b1ec06f0daf1661137b5b324587afa7a8..3e681ae815b9f8e9567e8e7eac8555d233418f9c 100644 --- a/compiler/core/dynamicContext.cpp +++ b/compiler/core/dynamicContext.cpp @@ -17,30 +17,31 @@ #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" #include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" +#include "plugins/ecmascript/es2panda/compiler/core/envScope.h" #include "plugins/ecmascript/es2panda/ir/expressions/identifier.h" #include "plugins/ecmascript/es2panda/ir/statements/tryStatement.h" #include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" #include "plugins/ecmascript/es2panda/ir/statements/labelledStatement.h" namespace panda::es2panda::compiler { -DynamicContext::DynamicContext(PandaGen *pg, LabelTarget target) : pg_(pg), target_(target), prev_(pg_->dynamicContext_) +DynamicContext::DynamicContext(CodeGen *cg, LabelTarget target) : cg_(cg), target_(target), prev_(cg_->dynamicContext_) { - pg_->dynamicContext_ = this; + cg_->dynamicContext_ = this; } DynamicContext::~DynamicContext() { - pg_->dynamicContext_ = prev_; + cg_->dynamicContext_ = prev_; } -LabelContext::LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt) - : DynamicContext(pg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt) +LabelContext::LabelContext(CodeGen *cg, const ir::LabelledStatement *labelledStmt) + : DynamicContext(cg, LabelTarget(labelledStmt->Ident()->Name())), labelledStmt_(labelledStmt) { if (!labelledStmt->Body()->IsBlockStatement()) { return; } - label_ = pg->AllocLabel(); + label_ = cg->AllocLabel(); target_.SetBreakTarget(label_); } @@ -50,7 +51,7 @@ LabelContext::~LabelContext() return; } - pg_->SetLabel(labelledStmt_, label_); + cg_->SetLabel(labelledStmt_, label_); } LexEnvContext::LexEnvContext(LoopEnvScope *envScope, PandaGen *pg, LabelTarget target) @@ -60,11 +61,11 @@ LexEnvContext::LexEnvContext(LoopEnvScope *envScope, PandaGen *pg, LabelTarget t return; } - catchTable_ = pg_->CreateCatchTable(); + catchTable_ = cg_->CreateCatchTable(); const auto &labelSet = catchTable_->LabelSet(); const auto *node = envScope_->Scope()->Node(); - pg_->SetLabel(node, labelSet.TryBegin()); + cg_->SetLabel(node, labelSet.TryBegin()); } LexEnvContext::~LexEnvContext() @@ -76,14 +77,19 @@ LexEnvContext::~LexEnvContext() const auto &labelSet = catchTable_->LabelSet(); const auto *node = envScope_->Scope()->Node(); - pg_->SetLabel(node, labelSet.TryEnd()); - pg_->Branch(node, labelSet.CatchEnd()); + cg_->SetLabel(node, labelSet.TryEnd()); + cg_->Branch(node, labelSet.CatchEnd()); - pg_->SetLabel(node, labelSet.CatchBegin()); - pg_->PopLexEnv(node); - pg_->EmitThrow(node); - pg_->SetLabel(node, labelSet.CatchEnd()); - pg_->PopLexEnv(node); + cg_->SetLabel(node, labelSet.CatchBegin()); + AsPandaGen()->PopLexEnv(node); + AsPandaGen()->EmitThrow(node); + cg_->SetLabel(node, labelSet.CatchEnd()); + AsPandaGen()->PopLexEnv(node); +} + +PandaGen *LexEnvContext::AsPandaGen() const +{ + return static_cast(cg_); } bool LexEnvContext::HasTryCatch() const @@ -99,14 +105,14 @@ void LexEnvContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, } const auto *node = envScope_->Scope()->Node(); - pg_->PopLexEnv(node); + AsPandaGen()->PopLexEnv(node); } IteratorContext::IteratorContext(PandaGen *pg, const Iterator &iterator, LabelTarget target) : DynamicContext(pg, target), iterator_(iterator), catchTable_(pg->CreateCatchTable()) { const auto &labelSet = catchTable_->LabelSet(); - pg_->SetLabel(iterator_.Node(), labelSet.TryBegin()); + pg->SetLabel(iterator_.Node(), labelSet.TryBegin()); } IteratorContext::~IteratorContext() @@ -114,12 +120,12 @@ IteratorContext::~IteratorContext() const auto &labelSet = catchTable_->LabelSet(); const auto *node = iterator_.Node(); - pg_->SetLabel(node, labelSet.TryEnd()); - pg_->Branch(node, labelSet.CatchEnd()); + cg_->SetLabel(node, labelSet.TryEnd()); + cg_->Branch(node, labelSet.CatchEnd()); - pg_->SetLabel(node, labelSet.CatchBegin()); + cg_->SetLabel(node, labelSet.CatchBegin()); iterator_.Close(true); - pg_->SetLabel(node, labelSet.CatchEnd()); + cg_->SetLabel(node, labelSet.CatchEnd()); } void IteratorContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, @@ -140,16 +146,19 @@ void TryContext::InitFinalizer() return; } - finalizerRun_ = pg_->AllocReg(); - pg_->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED); + auto *pg = static_cast(cg_); + + finalizerRun_ = pg->AllocReg(); + pg->StoreConst(tryStmt_, finalizerRun_, Constant::JS_UNDEFINED); } -void TryContext::InitCatchTable() +void CatchContext::InitCatchTable() { - catchTable_ = pg_->CreateCatchTable(); + auto *pg = static_cast(cg_); + catchTable_ = pg->CreateCatchTable(); } -const TryLabelSet &TryContext::LabelSet() const +const TryLabelSet &CatchContext::LabelSet() const { return catchTable_->LabelSet(); } @@ -165,14 +174,10 @@ void TryContext::EmitFinalizer() return; } + auto *pg = static_cast(cg_); inFinalizer_ = true; - tryStmt_->FinallyBlock()->Compile(pg_); + tryStmt_->FinallyBlock()->Compile(pg); inFinalizer_ = false; } -void TryContext::AbortContext([[maybe_unused]] ControlFlowChange cfc, - [[maybe_unused]] const util::StringView &targetLabel) -{ - EmitFinalizer(); -} } // namespace panda::es2panda::compiler diff --git a/compiler/core/dynamicContext.h b/compiler/core/dynamicContext.h index 44753babdf7af61b6425dab44d7fa56713580b7b..b3179ad6edec606fbba05b13646e7488a7b04e10 100644 --- a/compiler/core/dynamicContext.h +++ b/compiler/core/dynamicContext.h @@ -28,12 +28,12 @@ class LabelledStatement; } // namespace panda::es2panda::ir namespace panda::es2panda::compiler { -class PandaGen; +class CodeGen; class LoopEnvScope; class CatchTable; class TryLabelSet; -enum class DynamicContextType { NONE, LABEL, LEX_ENV, ITERATOR, TRY }; +enum class DynamicContextType { NONE, LABEL, LEX_ENV, ITERATOR, TRY, TRAP }; class DynamicContext { public: @@ -75,10 +75,10 @@ public: } protected: - explicit DynamicContext(PandaGen *pg, LabelTarget target); + explicit DynamicContext(CodeGen *cg, LabelTarget target); // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - PandaGen *pg_; + CodeGen *cg_; LabelTarget target_; DynamicContext *prev_ {}; // NOLINTEND(misc-non-private-member-variables-in-classes) @@ -86,8 +86,8 @@ protected: class LabelContext : public DynamicContext { public: - explicit LabelContext(PandaGen *pg, LabelTarget target) : DynamicContext(pg, target) {} - explicit LabelContext(PandaGen *pg, const ir::LabelledStatement *labelledStmt); + explicit LabelContext(CodeGen *cg, LabelTarget target) : DynamicContext(cg, target) {} + explicit LabelContext(CodeGen *cg, const ir::LabelledStatement *labelledStmt); NO_COPY_SEMANTIC(LabelContext); NO_MOVE_SEMANTIC(LabelContext); ~LabelContext(); @@ -118,6 +118,9 @@ public: void AbortContext([[maybe_unused]] ControlFlowChange cfc, [[maybe_unused]] const util::StringView &targetLabel) override; +protected: + PandaGen *AsPandaGen() const; + private: LoopEnvScope *envScope_; CatchTable *catchTable_ {}; @@ -153,20 +156,47 @@ private: CatchTable *catchTable_; }; -class TryContext : public DynamicContext { +class CatchContext : public DynamicContext { public: - explicit TryContext(PandaGen *pg, const ir::TryStatement *tryStmt, bool hasFinalizer = true) - : DynamicContext(pg, {}), tryStmt_(tryStmt), hasFinalizer_(hasFinalizer) + NO_COPY_SEMANTIC(CatchContext); + NO_MOVE_SEMANTIC(CatchContext); + ~CatchContext() = default; + + CatchTable *GetCatchTable() const { - InitCatchTable(); - InitFinalizer(); + return catchTable_; + } + + const TryLabelSet &LabelSet() const; + + bool HasTryCatch() const override + { + return true; } - explicit TryContext(PandaGen *pg) : DynamicContext(pg, {}) +protected: + explicit CatchContext(CodeGen *cg) : DynamicContext(cg, {}) { InitCatchTable(); } + CatchTable *catchTable_ {}; + +private: + void InitCatchTable(); +}; + +class TryContext : public CatchContext { +public: + explicit TryContext(CodeGen *cg, const ir::TryStatement *tryStmt, bool hasFinalizer = true) + : CatchContext(cg), tryStmt_(tryStmt), hasFinalizer_(hasFinalizer) + + { + InitFinalizer(); + } + + explicit TryContext(CodeGen *cg) : CatchContext(cg) {} + NO_COPY_SEMANTIC(TryContext); NO_MOVE_SEMANTIC(TryContext); ~TryContext() = default; @@ -176,38 +206,51 @@ public: return DynamicContextType::TRY; } - bool HasTryCatch() const override - { - return true; - } - VReg FinalizerRun() const { return finalizerRun_; } - CatchTable *GetCatchTable() const - { - return catchTable_; - } - - const TryLabelSet &LabelSet() const; bool HasFinalizer() const override; void InitFinalizer(); void EmitFinalizer(); void AbortContext([[maybe_unused]] ControlFlowChange cfc, - [[maybe_unused]] const util::StringView &targetLabel) override; + [[maybe_unused]] const util::StringView &targetLabel) override + { + EmitFinalizer(); + } private: - void InitCatchTable(); - const ir::TryStatement *tryStmt_ {}; - CatchTable *catchTable_ {}; VReg finalizerRun_ {}; bool hasFinalizer_ {}; bool inFinalizer_ {}; }; + +class TrapContext : public CatchContext { +public: + explicit TrapContext(CodeGen *cg) : CatchContext(cg) {} + + NO_COPY_SEMANTIC(TrapContext); + NO_MOVE_SEMANTIC(TrapContext); + ~TrapContext() = default; + + DynamicContextType Type() const override + { + return DynamicContextType::TRAP; + } + + bool HasTryCatch() const override + { + return true; + } + + bool HasFinalizer() const override + { + return false; + } +}; } // namespace panda::es2panda::compiler #endif diff --git a/compiler/core/emitter.cpp b/compiler/core/emitter.cpp index bb01bd1d3d41855f6909de606167e4decf0bc77d..48c3841d318ce38a7da04528da247232701f5f46 100644 --- a/compiler/core/emitter.cpp +++ b/compiler/core/emitter.cpp @@ -15,22 +15,20 @@ #include "emitter.h" -#include "plugins/ecmascript/es2panda/ir/irnode.h" -#include "plugins/ecmascript/es2panda/binder/binder.h" #include "plugins/ecmascript/es2panda/util/helpers.h" #include "plugins/ecmascript/es2panda/binder/scope.h" #include "plugins/ecmascript/es2panda/binder/variable.h" #include "plugins/ecmascript/es2panda/compiler/base/literals.h" #include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" -#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" +#include "plugins/ecmascript/es2panda/compiler/core/regSpiller.h" #include "plugins/ecmascript/es2panda/compiler/debugger/debuginfoDumper.h" #include "plugins/ecmascript/es2panda/compiler/base/catchTable.h" #include "plugins/ecmascript/es2panda/es2panda.h" -#include "generated/isa.h" -#include "plugins/ecmascript/es2panda/ir/expressions/literal.h" #include "plugins/ecmascript/es2panda/ir/statements/blockStatement.h" -#include "macros.h" #include "plugins/ecmascript/es2panda/parser/program/program.h" +#include "generated/isa.h" +#include "macros.h" #include #include @@ -108,33 +106,19 @@ static LiteralPair TransformLiteral(const compiler::Literal *literal) return {tagLit, valueLit}; } -constexpr const auto LANG_EXT = pandasm::extensions::Language::ECMASCRIPT; - void FunctionEmitter::Generate() { - auto *func = new panda::pandasm::Function(pg_->InternalName().Mutf8(), LANG_EXT); - programElement_->func = func; - - size_t paramCount = pg_->InternalParamCount(); - func->params.reserve(paramCount); - - for (uint32_t i = 0; i < paramCount; ++i) { - func->params.emplace_back(panda::pandasm::Type("any", 0), LANG_EXT); - } - - func->regs_num = IRNode::REG_START - pg_->TotalRegsNum(); - func->return_type = panda::pandasm::Type("any", 0); - + auto *func = GenFunctionSignature(); GenFunctionInstructions(func); GenVariablesDebugInfo(func); GenSourceFileDebugInfo(func); GenFunctionCatchTables(func); - GenFunctionICSize(func); + GenFunctionAnnotations(func); } util::StringView FunctionEmitter::SourceCode() const { - return pg_->Binder()->Program()->SourceCode(); + return cg_->Binder()->Program()->SourceCode(); } static Format MatchFormat(const IRNode *node, const Formats &formats) @@ -155,8 +139,7 @@ static Format MatchFormat(const IRNode *node, const Formats &formats) } } - if (std::all_of(registers.begin(), registers.end(), - [limit](const VReg *reg) { return *reg >= IRNode::REG_START - limit; })) { + if (std::all_of(registers.begin(), registers.end(), [limit](const VReg *reg) { return reg->IsValid(limit); })) { return format; } } @@ -194,7 +177,7 @@ void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, pandasm::Ins *p ASSERT(astNode != nullptr); if (astNode == FIRST_NODE_OF_FUNCTION) { - astNode = pg_->Debuginfo().firstStmt; + astNode = cg_->Debuginfo().firstStmt; if (astNode == nullptr) { return; } @@ -202,7 +185,7 @@ void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, pandasm::Ins *p pandaIns->ins_debug.line_number = astNode->Range().start.line + 1; - if (pg_->IsDebug()) { + if (cg_->IsDebug()) { size_t insLen = GetIRNodeWholeLength(ins); if (insLen != 0) { pandaIns->ins_debug.bound_left = offset_; @@ -214,13 +197,13 @@ void FunctionEmitter::GenInstructionDebugInfo(const IRNode *ins, pandasm::Ins *p } } -void FunctionEmitter::GenFunctionInstructions(panda::pandasm::Function *func) +void FunctionEmitter::GenFunctionInstructions(pandasm::Function *func) { - func->ins.reserve(pg_->Insns().size()); + func->ins.reserve(cg_->Insns().size()); - uint32_t totalRegs = pg_->TotalRegsNum(); + uint32_t totalRegs = cg_->TotalRegsNum(); - for (const auto *ins : pg_->Insns()) { + for (const auto *ins : cg_->Insns()) { auto &pandaIns = func->ins.emplace_back(); ins->Transform(&pandaIns, programElement_, totalRegs); @@ -228,32 +211,32 @@ void FunctionEmitter::GenFunctionInstructions(panda::pandasm::Function *func) } } -void FunctionEmitter::GenFunctionICSize(panda::pandasm::Function *func) +void FunctionEmitter::GenFunctionAnnotations(pandasm::Function *func) { pandasm::AnnotationData funcAnnotationData("_ESAnnotation"); pandasm::AnnotationElement icSizeAnnotationElement( "icSize", - std::make_unique(pandasm::ScalarValue::Create(pg_->IcSize()))); + std::make_unique(pandasm::ScalarValue::Create(cg_->IcSize()))); funcAnnotationData.AddElement(std::move(icSizeAnnotationElement)); pandasm::AnnotationElement parameterLengthAnnotationElement( "parameterLength", std::make_unique( - pandasm::ScalarValue::Create(pg_->FormalParametersCount()))); + pandasm::ScalarValue::Create(cg_->FormalParametersCount()))); funcAnnotationData.AddElement(std::move(parameterLengthAnnotationElement)); pandasm::AnnotationElement funcNameAnnotationElement( "funcName", std::make_unique( - pandasm::ScalarValue::Create(pg_->FunctionName().Mutf8()))); + pandasm::ScalarValue::Create(cg_->FunctionName().Mutf8()))); funcAnnotationData.AddElement(std::move(funcNameAnnotationElement)); func->metadata->AddAnnotations({funcAnnotationData}); } -void FunctionEmitter::GenFunctionCatchTables(panda::pandasm::Function *func) +void FunctionEmitter::GenFunctionCatchTables(pandasm::Function *func) { - func->catch_blocks.reserve(pg_->CatchList().size()); + func->catch_blocks.reserve(cg_->CatchList().size()); - for (const auto *catchBlock : pg_->CatchList()) { + for (const auto *catchBlock : cg_->CatchList()) { const auto &labelSet = catchBlock->LabelSet(); auto &pandaCatchBlock = func->catch_blocks.emplace_back(); @@ -264,31 +247,20 @@ void FunctionEmitter::GenFunctionCatchTables(panda::pandasm::Function *func) } } -void FunctionEmitter::GenSourceFileDebugInfo(panda::pandasm::Function *func) +void FunctionEmitter::GenSourceFileDebugInfo(pandasm::Function *func) { - func->source_file = std::string {pg_->Binder()->Program()->SourceFile()}; + func->source_file = std::string {cg_->Binder()->Program()->SourceFile()}; - if (!pg_->IsDebug()) { + if (!cg_->IsDebug()) { return; } - if (pg_->RootNode()->IsProgram()) { + if (cg_->RootNode()->IsProgram()) { func->source_code = SourceCode().EscapeSymbol(); } } -static void GenLocalVariableInfo(pandasm::debuginfo::LocalVariable &variableDebug, binder::Variable *var, - uint32_t start, uint32_t varsLength, uint32_t totalRegsNum) -{ - variableDebug.name = var->Name().Mutf8(); - variableDebug.signature = "any"; - variableDebug.signature_type = "any"; - variableDebug.reg = static_cast(IRNode::MapRegister(var->AsLocalVariable()->Vreg(), totalRegsNum)); - variableDebug.start = start; - variableDebug.length = static_cast(varsLength); -} - -void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const binder::Scope *scope) const +void FunctionEmitter::GenScopeVariableInfo(pandasm::Function *func, const binder::Scope *scope) const { const auto *startIns = scope->ScopeStart(); const auto *endIns = scope->ScopeEnd(); @@ -296,28 +268,25 @@ void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const uint32_t start = 0; uint32_t count = 0; - for (const auto *it : pg_->Insns()) { + for (const auto *it : cg_->Insns()) { if (startIns == it) { start = count; } else if (endIns == it) { auto varsLength = static_cast(count - start + 1); - if (scope->IsFunctionScope()) { - for (auto *param : scope->AsFunctionScope()->ParamScope()->Params()) { - auto &variableDebug = func->local_variable_debug.emplace_back(); - GenLocalVariableInfo(variableDebug, param, start, varsLength, pg_->TotalRegsNum()); - } - } - - for (const auto &[_, variable] : scope->Bindings()) { - (void)_; - if (!variable->IsLocalVariable() || variable->LexicalBound() || - variable->Declaration()->IsParameterDecl()) { + for (const auto &[name, variable] : scope->Bindings()) { + if (!variable->IsLocalVariable() || variable->LexicalBound()) { continue; } auto &variableDebug = func->local_variable_debug.emplace_back(); - GenLocalVariableInfo(variableDebug, variable, start, varsLength, pg_->TotalRegsNum()); + variableDebug.name = name.Mutf8(); + // variableDebug.signature = "any"; + // variableDebug.signature_type = "any"; + GenVariableSignature(variableDebug, variable->AsLocalVariable()); + variableDebug.reg = static_cast(variable->AsLocalVariable()->Vreg().GetIndex()); + variableDebug.start = start; + variableDebug.length = static_cast(varsLength); } break; @@ -327,27 +296,23 @@ void FunctionEmitter::GenScopeVariableInfo(panda::pandasm::Function *func, const } } -void FunctionEmitter::GenVariablesDebugInfo(panda::pandasm::Function *func) +void FunctionEmitter::GenVariablesDebugInfo(pandasm::Function *func) { - if (!pg_->IsDebug()) { + if (!cg_->IsDebug()) { return; } - for (const auto *scope : pg_->Debuginfo().variableDebugInfo) { + for (const auto *scope : cg_->Debuginfo().variableDebugInfo) { GenScopeVariableInfo(func, scope); } } // Emitter -Emitter::Emitter(const CompilerContext *context) +Emitter::Emitter(const CompilerContext *context) : context_(context) { prog_ = new pandasm::Program(); - prog_->lang = pandasm::extensions::Language::ECMASCRIPT; - prog_->function_table.reserve(context->Binder()->Functions().size()); - GenESAnnoatationRecord(); - GenESModuleModeRecord(context->Binder()->Program()->Kind() == parser::ScriptKind::MODULE); } Emitter::~Emitter() @@ -355,31 +320,7 @@ Emitter::~Emitter() delete prog_; } -void Emitter::GenESAnnoatationRecord() -{ - auto annotationRecord = pandasm::Record("_ESAnnotation", LANG_EXT); - annotationRecord.metadata->SetAttribute("external"); - annotationRecord.metadata->SetAccessFlags(ACC_ANNOTATION); - prog_->record_table.emplace(annotationRecord.name, std::move(annotationRecord)); -} - -void Emitter::GenESModuleModeRecord(bool isModule) -{ - auto modeRecord = pandasm::Record("_ESModuleMode", LANG_EXT); - modeRecord.metadata->SetAccessFlags(ACC_PUBLIC); - - auto modeField = pandasm::Field(LANG_EXT); - modeField.name = "isModule"; - modeField.type = pandasm::Type("u8", 0); - modeField.metadata->SetValue( - pandasm::ScalarValue::Create(static_cast(isModule))); - - modeRecord.field_list.emplace_back(std::move(modeField)); - - prog_->record_table.emplace(modeRecord.name, std::move(modeRecord)); -} - -static void UpdateLiteralBufferId(panda::pandasm::Ins *ins, uint32_t offset) +static void UpdateLiteralBufferId(pandasm::Ins *ins, uint32_t offset) { switch (ins->opcode) { case pandasm::Opcode::ECMA_DEFINECLASSWITHBUFFER: { @@ -470,13 +411,17 @@ void Emitter::AddLiteralBuffer(const LiteralBuffer &literals, uint32_t index) prog_->literalarray_table.emplace(std::to_string(index), std::move(literalArrayInstance)); } -pandasm::Program *Emitter::Finalize(bool dumpDebugInfo) +pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, std::string_view globalClass) { if (dumpDebugInfo) { debuginfo::DebugInfoDumper dumper(prog_); dumper.Dump(); } + if (context_->Binder()->IsGenStdLib()) { + auto it = prog_->record_table.find(std::string(globalClass)); + prog_->record_table.erase(it); + } auto *prog = prog_; prog_ = nullptr; return prog; diff --git a/compiler/core/emitter.h b/compiler/core/emitter.h index 64f61251b34175d7dbc1d40ea91f6eaecb2c322d..7356fc6c1f7c5d77d7bc7279502edaa8db3864e4 100644 --- a/compiler/core/emitter.h +++ b/compiler/core/emitter.h @@ -13,12 +13,10 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_IR_EMITTER_H -#define ES2PANDA_COMPILER_IR_EMITTER_H +#ifndef ES2PANDA_COMPILER_CORE_EMITTER_H +#define ES2PANDA_COMPILER_CORE_EMITTER_H #include "plugins/ecmascript/es2panda/compiler/base/literals.h" -#include "plugins/ecmascript/es2panda/lexer/token/sourceLocation.h" -#include "macros.h" #include "plugins/ecmascript/es2panda/util/ustring.h" #include @@ -32,29 +30,29 @@ namespace panda::pandasm { struct Program; struct Function; struct Ins; +namespace debuginfo { +struct LocalVariable; +} // namespace debuginfo } // namespace panda::pandasm -namespace panda::es2panda::ir { -class Statement; -class Literal; -} // namespace panda::es2panda::ir - namespace panda::es2panda::binder { class Scope; +class LocalVariable; } // namespace panda::es2panda::binder namespace panda::es2panda::compiler { -class PandaGen; +class CodeGen; class DebugInfo; class Label; class IRNode; class CompilerContext; class ProgramElement; +class RegSpiller; class FunctionEmitter { public: - explicit FunctionEmitter(const PandaGen *pg, ProgramElement *programElement) - : pg_(pg), programElement_(programElement) + explicit FunctionEmitter(const CodeGen *cg, ProgramElement *programElement) + : cg_(cg), programElement_(programElement) { } @@ -64,44 +62,48 @@ public: void Generate(); -private: +protected: + virtual pandasm::Function *GenFunctionSignature() = 0; + virtual void GenFunctionAnnotations(pandasm::Function *func) = 0; + virtual void GenVariableSignature(pandasm::debuginfo::LocalVariable &variableDebug, + binder::LocalVariable *variable) const = 0; + void GenInstructionDebugInfo(const IRNode *ins, panda::pandasm::Ins *pandaIns); - void GenFunctionInstructions(panda::pandasm::Function *func); + void GenFunctionInstructions(pandasm::Function *func); + void GenScopeVariableInfo(pandasm::Function *func, const binder::Scope *scope) const; + void GenSourceFileDebugInfo(pandasm::Function *func); void GenFunctionCatchTables(panda::pandasm::Function *func); - void GenFunctionICSize(panda::pandasm::Function *func); - void GenScopeVariableInfo(panda::pandasm::Function *func, const binder::Scope *scope) const; - void GenSourceFileDebugInfo(panda::pandasm::Function *func); - void GenVariablesDebugInfo(panda::pandasm::Function *func); + void GenVariablesDebugInfo(pandasm::Function *func); util::StringView SourceCode() const; - const PandaGen *pg_; + const CodeGen *cg_; ProgramElement *programElement_; size_t offset_ {0}; }; class Emitter { public: - explicit Emitter(const CompilerContext *context); - ~Emitter(); + virtual ~Emitter(); NO_COPY_SEMANTIC(Emitter); NO_MOVE_SEMANTIC(Emitter); - void AddFunction(FunctionEmitter *func); void AddLiteralBuffer(const LiteralBuffer &literals, uint32_t index); void AddProgramElement(ProgramElement *programElement); - static void DumpAsm(const panda::pandasm::Program *prog); - panda::pandasm::Program *Finalize(bool dumpDebugInfo); + static void DumpAsm(const pandasm::Program *prog); + pandasm::Program *Finalize(bool dumpDebugInfo, std::string_view globalClass = ""); uint32_t &LiteralBufferIndex() { return literalBufferIndex_; } -private: - void GenESAnnoatationRecord(); - void GenESModuleModeRecord(bool isModule); + virtual void GenAnnotation() = 0; + +protected: + explicit Emitter(const CompilerContext *context); - panda::pandasm::Program *prog_; + pandasm::Program *prog_; + const CompilerContext *context_; uint32_t literalBufferIndex_ {}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/envScope.cpp b/compiler/core/envScope.cpp index 6dd355c886da55910d4b074e346b0d3762ed2b95..2b9b849e89dbd3dce526e5ed068123e8569be0ee 100644 --- a/compiler/core/envScope.cpp +++ b/compiler/core/envScope.cpp @@ -15,18 +15,19 @@ #include "envScope.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" #include "plugins/ecmascript/es2panda/ir/statement.h" namespace panda::es2panda::compiler { -ScopeContext::ScopeContext(PandaGen *pg, binder::Scope *newScope) : pg_(pg), prevScope_(pg_->scope_) +ScopeContext::ScopeContext(CodeGen *cg, binder::Scope *newScope) : cg_(cg), prevScope_(cg_->scope_) { - pg_->scope_ = newScope; + cg->scope_ = newScope; } ScopeContext::~ScopeContext() { - pg_->scope_ = prevScope_; + cg_->scope_ = prevScope_; } void EnvScope::Initialize(PandaGen *pg, VReg lexEnv) diff --git a/compiler/core/envScope.h b/compiler/core/envScope.h index ce0548c03754e03f581f9d13072ed098fd3de38a..7de54780bc67e4ccf4091015d3c0b30c0620bdc6 100644 --- a/compiler/core/envScope.h +++ b/compiler/core/envScope.h @@ -32,14 +32,14 @@ class PandaGen; class ScopeContext { public: - explicit ScopeContext(PandaGen *pg, binder::Scope *newScope); + explicit ScopeContext(CodeGen *cg, binder::Scope *newScope); ~ScopeContext(); NO_COPY_SEMANTIC(ScopeContext); NO_MOVE_SEMANTIC(ScopeContext); private: - PandaGen *pg_; + CodeGen *cg_; binder::Scope *prevScope_; }; diff --git a/compiler/core/function.cpp b/compiler/core/function.cpp index 17d8c1d27dd33b44e6b33a6f46a2a37ea283c7a9..8a31670d3ed918624cb5fbd8bc1cc04d2be02360 100644 --- a/compiler/core/function.cpp +++ b/compiler/core/function.cpp @@ -71,7 +71,7 @@ static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFu uint32_t index = 0; for (const auto *param : func->Params()) { - LReference ref = LReference::CreateLRef(pg, param, true); + auto ref = JSLReference::Create(pg, param, true); [[maybe_unused]] binder::Variable *paramVar = ref.Variable(); @@ -82,7 +82,7 @@ static void CompileFunctionParameterDeclaration(PandaGen *pg, const ir::ScriptFu ASSERT(paramVar && paramVar->IsLocalVariable()); - VReg paramReg = binder::Binder::MANDATORY_PARAMS_NUMBER + IRNode::PARAM_START + index++; + VReg paramReg = VReg(binder::Binder::MANDATORY_PARAMS_NUMBER + VReg::PARAM_START + index++); ASSERT(paramVar->LexicalBound() || paramVar->AsLocalVariable()->Vreg() == paramReg); if (param->IsAssignmentPattern()) { @@ -175,11 +175,11 @@ void Function::CompileInstanceFields(PandaGen *pg, const ir::ScriptFunction *dec const auto *prop = element->AsClassProperty(); - if ((prop->Modifiers() & ir::ModifierFlags::STATIC) != 0) { + if ((prop->IsStatic())) { continue; } - if (prop->IsPrivate()) { + if (prop->IsPrivateElement()) { if (prop->Value() == nullptr) { pg->LoadConst(element, Constant::JS_UNDEFINED); } else { diff --git a/compiler/core/labelTarget.cpp b/compiler/core/labelTarget.cpp index f8b39bbc6845c46d19a16adcc08f9ad8cdf9f705..b5cb85866da6b6ad51afc02d32bc13a30dddf8c7 100644 --- a/compiler/core/labelTarget.cpp +++ b/compiler/core/labelTarget.cpp @@ -15,11 +15,11 @@ #include "labelTarget.h" -#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" namespace panda::es2panda::compiler { -LabelTarget::LabelTarget(PandaGen *pg) - : LabelPair(pg->AllocLabel(), pg->AllocLabel()), breakLabel_(BREAK_LABEL), continueLabel_(CONTINUE_LABEL) +LabelTarget::LabelTarget(CodeGen *cg) + : LabelPair(cg->AllocLabel(), cg->AllocLabel()), breakLabel_(BREAK_LABEL), continueLabel_(CONTINUE_LABEL) { } } // namespace panda::es2panda::compiler diff --git a/compiler/core/labelTarget.h b/compiler/core/labelTarget.h index e31db8f01ee812f64e2b4eb5817b7e976314fbe2..870d37b667a228ee910e4a8acc202a64ed1e9d9c 100644 --- a/compiler/core/labelTarget.h +++ b/compiler/core/labelTarget.h @@ -28,7 +28,7 @@ class Identifier; namespace panda::es2panda::compiler { class LabelTarget; -class PandaGen; +class CodeGen; enum class ControlFlowChange { CONTINUE, @@ -37,7 +37,7 @@ enum class ControlFlowChange { class LabelTarget : public LabelPair { public: - explicit LabelTarget(PandaGen *pg); + explicit LabelTarget(CodeGen *cg); explicit LabelTarget(const util::StringView &label) : LabelTarget(nullptr, label) {} explicit LabelTarget(Label *target, const util::StringView &label) : LabelPair(target, nullptr), breakLabel_(label), continueLabel_(label) diff --git a/compiler/core/pandagen.cpp b/compiler/core/pandagen.cpp index 6ff9b530db893013f684c7effc59f562a8f1452d..bb9297025dfc0674cfb8e7209e1b6903ca84bb60 100644 --- a/compiler/core/pandagen.cpp +++ b/compiler/core/pandagen.cpp @@ -39,59 +39,6 @@ #include "plugins/ecmascript/es2panda/ir/expressions/literals/stringLiteral.h" namespace panda::es2panda::compiler { -// PandaGen - -Label *PandaGen::AllocLabel() -{ - std::string id = std::string {Label::PREFIX} + std::to_string(labelId_++); - return sa_.AllocLabel(std::move(id)); -} - -bool PandaGen::IsDebug() const -{ - return context_->IsDebug(); -} - -uint32_t PandaGen::ParamCount() const -{ - if (rootNode_->IsProgram()) { - return IsDirectEval() ? 1 : 0; - } - - return rootNode_->AsScriptFunction()->Params().size(); -} - -uint32_t PandaGen::FormalParametersCount() const -{ - if (rootNode_->IsProgram()) { - return 0; - } - - ASSERT(rootNode_->IsScriptFunction()); - - return rootNode_->AsScriptFunction()->FormalParamsLength(); -} - -uint32_t PandaGen::InternalParamCount() const -{ - static const uint32_t HIDDEN_PARAMS = 3; - return ParamCount() + HIDDEN_PARAMS; -} - -const util::StringView &PandaGen::InternalName() const -{ - return topScope_->InternalName(); -} - -const util::StringView &PandaGen::FunctionName() const -{ - return topScope_->Name(); -} - -binder::Binder *PandaGen::Binder() const -{ - return context_->Binder(); -} void PandaGen::FunctionInit(CatchTable *catchTable) { @@ -102,7 +49,7 @@ void PandaGen::FunctionInit(CatchTable *catchTable) const ir::ScriptFunction *func = rootNode_->AsScriptFunction(); - if (func->IsAsync()) { + if (func->IsAsyncFunc()) { if (func->IsGenerator()) { builder_ = allocator_->New(this, catchTable); return; @@ -128,7 +75,7 @@ bool PandaGen::FunctionHasFinalizer() const const ir::ScriptFunction *func = rootNode_->AsScriptFunction(); - return func->IsAsync() || func->IsGenerator(); + return func->IsAsyncFunc() || func->IsGenerator(); } void PandaGen::FunctionEnter() @@ -141,10 +88,85 @@ void PandaGen::FunctionExit() builder_->CleanUp(rootNode_->AsScriptFunction()); } -int32_t PandaGen::AddLiteralBuffer(LiteralBuffer &&buf) +void PandaGen::StoreAccumulator(const ir::AstNode *node, VReg vreg) { - programElement_->buffStorage.emplace_back(std::move(buf)); - return literalBufferIdx_++; + ra_.Emit(node, vreg); +} + +void PandaGen::LoadAccumulator(const ir::AstNode *node, VReg reg) +{ + ra_.Emit(node, reg); +} + +void PandaGen::MoveVreg(const ir::AstNode *node, VReg vd, VReg vs) +{ + ra_.Emit(node, vd, vs); +} + +void PandaGen::LoadAccumulatorFloat(const ir::AstNode *node, double num) +{ + sa_.Emit(node, num); +} + +void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, int32_t num) +{ + sa_.Emit(node, num); +} + +void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num) +{ + sa_.Emit(node, static_cast(num)); +} + +void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id) +{ + LoadConst(node, id); + StoreAccumulator(node, reg); +} + +void PandaGen::LoadConst(const ir::AstNode *node, Constant id) +{ + switch (id) { + case Constant::JS_HOLE: { + sa_.Emit(node); + break; + } + case Constant::JS_NAN: { + sa_.Emit(node); + break; + } + case Constant::JS_INFINITY: { + sa_.Emit(node); + break; + } + case Constant::JS_GLOBAL: { + sa_.Emit(node); + break; + } + case Constant::JS_UNDEFINED: { + sa_.Emit(node); + break; + } + case Constant::JS_SYMBOL: { + sa_.Emit(node); + break; + } + case Constant::JS_NULL: { + sa_.Emit(node); + break; + } + case Constant::JS_TRUE: { + sa_.Emit(node); + break; + } + case Constant::JS_FALSE: { + sa_.Emit(node); + break; + } + default: { + UNREACHABLE(); + } + } } void PandaGen::GetFunctionObject(const ir::AstNode *node) @@ -217,16 +239,9 @@ void PandaGen::StoreVar(const ir::AstNode *node, const binder::ScopeFindResult & StoreAccToLexEnv(node, result, isDeclaration); } -void PandaGen::StoreAccumulator(const ir::AstNode *node, VReg vreg) -{ - ra_.Emit(node, vreg); -} - void PandaGen::LoadAccFromArgs(const ir::AstNode *node) { - const auto *varScope = scope_->AsVariableScope(); - - if (!varScope->HasFlag(binder::VariableScopeFlags::USE_ARGS)) { + if (!scope_->HasFlag(binder::ScopeFlags::USE_ARGS)) { return; } @@ -345,11 +360,6 @@ void PandaGen::DeleteObjProperty(const ir::AstNode *node, VReg obj, VReg prop) ra_.Emit(node, obj, prop); } -void PandaGen::LoadAccumulator(const ir::AstNode *node, VReg reg) -{ - ra_.Emit(node, reg); -} - void PandaGen::LoadGlobalVar(const ir::AstNode *node, const util::StringView &name) { sa_.Emit(node, name); @@ -375,163 +385,11 @@ void PandaGen::StoreAccToLexEnv(const ir::AstNode *node, const binder::ScopeFind VirtualStoreVar::Expand(this, node, result, isDeclaration); } -void PandaGen::LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str) -{ - sa_.Emit(node, str); -} - void PandaGen::LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &bigInt) { sa_.Emit(node, bigInt); } -void PandaGen::LoadAccumulatorFloat(const ir::AstNode *node, double num) -{ - sa_.Emit(node, num); -} - -void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, int32_t num) -{ - sa_.Emit(node, num); -} - -void PandaGen::LoadAccumulatorInt(const ir::AstNode *node, size_t num) -{ - sa_.Emit(node, static_cast(num)); -} - -void PandaGen::StoreConst(const ir::AstNode *node, VReg reg, Constant id) -{ - LoadConst(node, id); - StoreAccumulator(node, reg); -} - -void PandaGen::LoadConst(const ir::AstNode *node, Constant id) -{ - switch (id) { - case Constant::JS_HOLE: { - sa_.Emit(node); - break; - } - case Constant::JS_NAN: { - sa_.Emit(node); - break; - } - case Constant::JS_INFINITY: { - sa_.Emit(node); - break; - } - case Constant::JS_GLOBAL: { - sa_.Emit(node); - break; - } - case Constant::JS_UNDEFINED: { - sa_.Emit(node); - break; - } - case Constant::JS_SYMBOL: { - sa_.Emit(node); - break; - } - case Constant::JS_NULL: { - sa_.Emit(node); - break; - } - case Constant::JS_TRUE: { - sa_.Emit(node); - break; - } - case Constant::JS_FALSE: { - sa_.Emit(node); - break; - } - default: { - UNREACHABLE(); - } - } -} - -void PandaGen::MoveVreg(const ir::AstNode *node, VReg vd, VReg vs) -{ - ra_.Emit(node, vd, vs); -} - -void PandaGen::SetLabel([[maybe_unused]] const ir::AstNode *node, Label *label) -{ - sa_.AddLabel(label); -} - -void PandaGen::Branch(const ir::AstNode *node, Label *label) -{ - sa_.Emit(node, label); -} - -bool PandaGen::CheckControlFlowChange() -{ - const auto *iter = dynamicContext_; - - while (iter != nullptr) { - if (iter->HasFinalizer()) { - return true; - } - - iter = iter->Prev(); - } - - return false; -} - -Label *PandaGen::ControlFlowChangeBreak(const ir::Identifier *label) -{ - auto *iter = dynamicContext_; - - util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::BREAK_LABEL; - Label *breakTarget = nullptr; - - while (iter != nullptr) { - iter->AbortContext(ControlFlowChange::BREAK, labelName); - - const auto &labelTargetName = iter->Target().BreakLabel(); - - if (iter->Target().BreakTarget() != nullptr) { - breakTarget = iter->Target().BreakTarget(); - } - - if (labelTargetName == labelName) { - break; - } - - iter = iter->Prev(); - } - - return breakTarget; -} - -Label *PandaGen::ControlFlowChangeContinue(const ir::Identifier *label) -{ - auto *iter = dynamicContext_; - util::StringView labelName = label != nullptr ? label->Name() : LabelTarget::CONTINUE_LABEL; - Label *continueTarget = nullptr; - - while (iter != nullptr) { - iter->AbortContext(ControlFlowChange::CONTINUE, labelName); - - const auto &labelTargetName = iter->Target().ContinueLabel(); - - if (iter->Target().ContinueTarget() != nullptr) { - continueTarget = iter->Target().ContinueTarget(); - } - - if (labelTargetName == labelName) { - break; - } - - iter = iter->Prev(); - } - - return continueTarget; -} - void PandaGen::Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, Label *ifFalse) { switch (op) { @@ -836,7 +694,7 @@ void PandaGen::Call1This(const ir::AstNode *node, VReg callee, VReg thisReg, VRe void PandaGen::Call(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments) { - bool hasThis = thisReg != INVALID_VREG; + bool hasThis = !thisReg.IsInvalid(); switch (arguments.size()) { case 0: { // 0 args @@ -919,7 +777,7 @@ void PandaGen::Call(const ir::AstNode *node, VReg callee, VReg thisReg, const Ar void PandaGen::CallTagged(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments) { - bool hasThis = thisReg != INVALID_VREG; + bool hasThis = !thisReg.IsInvalid(); StoreAccumulator(node, callee); Literals::GetTemplateObject(this, node->AsTaggedTemplateExpression()); @@ -1012,7 +870,7 @@ void PandaGen::DefineMethod(const ir::AstNode *node, const util::StringView &nam void PandaGen::DefineFunction(const ir::AstNode *node, const ir::ScriptFunction *realNode, const util::StringView &name) { - if (realNode->IsAsync()) { + if (realNode->IsAsyncFunc()) { if (realNode->IsGenerator()) { ra_.Emit(node, name, LexEnv()); } else { @@ -1342,7 +1200,7 @@ void PandaGen::GetAsyncIterator(const ir::AstNode *node) void PandaGen::CreateObjectWithExcludedKeys(const ir::AstNode *node, VReg obj, VReg argStart, size_t argCount) { - ASSERT(argStart == obj - 1); + ASSERT(argStart.GetIndex() == obj.GetIndex() - 1); if (argCount == 0) { // Do not emit undefined register argStart = obj; } @@ -1529,38 +1387,9 @@ void PandaGen::LdLexEnv(const ir::AstNode *node) sa_.Emit(node); } -uint32_t PandaGen::TryDepth() const -{ - const auto *iter = dynamicContext_; - uint32_t depth = 0; - - while (iter != nullptr) { - if (iter->HasTryCatch()) { - depth++; - } - - iter = iter->Prev(); - } - - return depth; -} - -CatchTable *PandaGen::CreateCatchTable() -{ - auto *catchTable = allocator_->New(this, TryDepth()); - catchList_.push_back(catchTable); - return catchTable; -} - -void PandaGen::SortCatchTables() -{ - std::sort(catchList_.begin(), catchList_.end(), - [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); }); -} - Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed) { - VReg res {IRNode::REG_START}; + VReg res {VReg::REG_START}; if (!isComputed) { if (prop->IsIdentifier()) { @@ -1586,7 +1415,7 @@ Operand PandaGen::ToNamedPropertyKey(const ir::Expression *prop, bool isComputed } if (prop->IsNumberLiteral()) { - auto num = prop->AsNumberLiteral()->Number(); + auto num = prop->AsNumberLiteral()->Number().GetDouble(); if (util::Helpers::IsIndex(num)) { return static_cast(num); } diff --git a/compiler/core/pandagen.h b/compiler/core/pandagen.h index 03b65f9270499c7785175f9a96b150d80ba3d127..369943e6e2e1120b4846aff742625f12073e78cd 100644 --- a/compiler/core/pandagen.h +++ b/compiler/core/pandagen.h @@ -16,10 +16,11 @@ #ifndef ES2PANDA_COMPILER_CORE_PANDAGEN_H #define ES2PANDA_COMPILER_CORE_PANDAGEN_H -#include "plugins/ecmascript/es2panda/compiler/base/literals.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" #include "plugins/ecmascript/es2panda/compiler/base/optionalChain.h" #include "plugins/ecmascript/es2panda/compiler/core/envScope.h" -#include "plugins/ecmascript/es2panda/compiler/core/inlineCache.h" +#include "plugins/ecmascript/es2panda/compiler/core/function.h" + #include "plugins/ecmascript/es2panda/compiler/core/regAllocator.h" #include "plugins/ecmascript/es2panda/compiler/core/regScope.h" #include "plugins/ecmascript/es2panda/ir/irnode.h" @@ -46,115 +47,20 @@ namespace panda::es2panda::compiler { class FunctionBuilder; class CompilerContext; class DynamicContext; -class CatchTable; - -enum class Constant { - JS_NAN, - JS_HOLE, - JS_INFINITY, - JS_UNDEFINED, - JS_NULL, - JS_TRUE, - JS_FALSE, - JS_SYMBOL, - JS_GLOBAL, -}; - -class DebugInfo { -public: - explicit DebugInfo(ArenaAllocator *allocator) : variableDebugInfo(allocator->Adapter()) {}; - DEFAULT_COPY_SEMANTIC(DebugInfo); - DEFAULT_MOVE_SEMANTIC(DebugInfo); - ~DebugInfo() = default; - - // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - ArenaVector variableDebugInfo; - const ir::Statement *firstStmt {}; - // NOLINTEND(misc-non-private-member-variables-in-classes) -}; -class PandaGen { +class PandaGen : public CodeGen { public: - explicit PandaGen(ArenaAllocator *allocator, CompilerContext *context, binder::FunctionScope *scope, - ProgramElement *programElement) - : allocator_(allocator), - context_(context), - debugInfo_(allocator_), - topScope_(scope), - scope_(topScope_), - rootNode_(scope->Node()), - insns_(allocator_->Adapter()), - catchList_(allocator_->Adapter()), - programElement_(programElement), - sa_(this), - ra_(this), - rra_(this) + explicit PandaGen(ArenaAllocator *allocator, RegSpiller *spiller, CompilerContext *context, + binder::FunctionScope *scope, ProgramElement *programElement) + : CodeGen(allocator, spiller, context, scope, programElement) { + Function::Compile(this); } + ~PandaGen() = default; NO_COPY_SEMANTIC(PandaGen); NO_MOVE_SEMANTIC(PandaGen); - inline ArenaAllocator *Allocator() const - { - return allocator_; - } - - const ArenaVector &CatchList() const - { - return catchList_; - } - - binder::FunctionScope *TopScope() const - { - return topScope_; - } - - binder::Scope *Scope() const - { - return scope_; - } - - const ir::AstNode *RootNode() const - { - return rootNode_; - } - - ArenaList &Insns() - { - return insns_; - } - - const ArenaList &Insns() const - { - return insns_; - } - - VReg AllocReg() - { - return usedRegs_--; - } - - VReg NextReg() const - { - return usedRegs_; - } - - uint32_t TotalRegsNum() const - { - return totalRegs_; - } - - size_t LabelCount() const - { - return labelId_; - } - - const DebugInfo &Debuginfo() const - { - return debugInfo_; - } - FunctionBuilder *FuncBuilder() const { return builder_; @@ -172,21 +78,6 @@ public: } } - uint32_t IcSize() const - { - return ic_.Size(); - } - - bool IsDebug() const; - uint32_t ParamCount() const; - uint32_t FormalParametersCount() const; - uint32_t InternalParamCount() const; - const util::StringView &InternalName() const; - const util::StringView &FunctionName() const; - binder::Binder *Binder() const; - - Label *AllocLabel(); - VReg LexEnv() const; bool FunctionHasFinalizer() const; @@ -194,7 +85,16 @@ public: void FunctionEnter(); void FunctionExit(); - int32_t AddLiteralBuffer(LiteralBuffer &&buf); + void StoreAccumulator(const ir::AstNode *node, VReg vreg); + void LoadAccumulator(const ir::AstNode *node, VReg reg); + void MoveVreg(const ir::AstNode *node, VReg vd, VReg vs); + + void LoadAccumulatorFloat(const ir::AstNode *node, double num); + void LoadAccumulatorInt(const ir::AstNode *node, int32_t num); + void LoadAccumulatorInt(const ir::AstNode *node, size_t num); + + void LoadConst(const ir::AstNode *node, Constant id); + void StoreConst(const ir::AstNode *node, VReg reg, Constant id); void GetFunctionObject(const ir::AstNode *node); void GetNewTarget(const ir::AstNode *node); @@ -203,7 +103,6 @@ public: void LoadVar(const ir::Identifier *node, const binder::ScopeFindResult &result); void StoreVar(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration); - void StoreAccumulator(const ir::AstNode *node, VReg vreg); void LoadAccFromArgs(const ir::AstNode *node); void LoadObjProperty(const ir::AstNode *node, const Operand &prop); @@ -212,7 +111,6 @@ public: void StoreObjProperty(const ir::AstNode *node, VReg obj, const Operand &prop); void StoreOwnProperty(const ir::AstNode *node, VReg obj, const Operand &prop); void DeleteObjProperty(const ir::AstNode *node, VReg obj, VReg prop); - void LoadAccumulator(const ir::AstNode *node, VReg reg); void LoadGlobalVar(const ir::AstNode *node, const util::StringView &name); void StoreGlobalVar(const ir::AstNode *node, const util::StringView &name); void StoreGlobalLet(const ir::AstNode *node, const util::StringView &name); @@ -225,21 +123,7 @@ public: void LoadAccFromLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result); void StoreAccToLexEnv(const ir::AstNode *node, const binder::ScopeFindResult &result, bool isDeclaration); - void LoadAccumulatorString(const ir::AstNode *node, const util::StringView &str); void LoadAccumulatorBigInt(const ir::AstNode *node, const util::StringView &bigInt); - void LoadAccumulatorFloat(const ir::AstNode *node, double num); - void LoadAccumulatorInt(const ir::AstNode *node, int32_t num); - void LoadAccumulatorInt(const ir::AstNode *node, size_t num); - - void LoadConst(const ir::AstNode *node, Constant id); - void StoreConst(const ir::AstNode *node, VReg reg, Constant id); - void MoveVreg(const ir::AstNode *node, VReg vd, VReg vs); - - void SetLabel(const ir::AstNode *node, Label *label); - void Branch(const ir::AstNode *node, class Label *label); - bool CheckControlFlowChange(); - Label *ControlFlowChangeBreak(const ir::Identifier *label = nullptr); - Label *ControlFlowChangeContinue(const ir::Identifier *label); void Condition(const ir::AstNode *node, lexer::TokenType op, VReg lhs, class Label *ifFalse); void Unary(const ir::AstNode *node, lexer::TokenType op, VReg operand); @@ -248,6 +132,7 @@ public: void BranchIfUndefined(const ir::AstNode *node, class Label *target); void BranchIfNotUndefined(const ir::AstNode *node, class Label *target); void BranchIfHole(const ir::AstNode *node, class Label *target); + void BranchIfTrue(const ir::AstNode *node, class Label *target); void BranchIfNotTrue(const ir::AstNode *node, class Label *target); void BranchIfFalse(const ir::AstNode *node, class Label *target); @@ -262,7 +147,6 @@ public: void ImplicitReturn(const ir::AstNode *node); void EmitAwait(const ir::AstNode *node); - static constexpr auto MAX_RANGE_CALL_ARG = 128; void CallTagged(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments); void Call(const ir::AstNode *node, VReg callee, VReg thisReg, const ArenaVector &arguments); void Call0This(const ir::AstNode *node, VReg callee, VReg thisReg); @@ -369,10 +253,6 @@ public: void ThrowTdz(const ir::AstNode *node, const util::StringView &name); void ThrowConstAssignment(const ir::AstNode *node, const util::StringView &name); - uint32_t TryDepth() const; - CatchTable *CreateCatchTable(); - void SortCatchTables(); - void LoadObjByIndex(const ir::AstNode *node, int64_t index); void LoadObjByValue(const ir::AstNode *node, VReg obj); @@ -397,52 +277,17 @@ public: bool IsDirectEval() const; bool IsEval() const; - void SetFirstStmt(const ir::Statement *stmt) - { - debugInfo_.firstStmt = stmt; - } - - [[noreturn]] static void Unimplemented() - { - throw Error(ErrorType::GENERIC, "Unimplemented code path"); - } - private: void LoadEvalBindings(const ir::AstNode *node); - ArenaAllocator *allocator_; - CompilerContext *context_; FunctionBuilder *builder_ {}; - DebugInfo debugInfo_; - binder::FunctionScope *topScope_; - binder::Scope *scope_; - const ir::AstNode *rootNode_; - ArenaList insns_; - ArenaVector catchList_; - ProgramElement *programElement_; - EnvScope *envScope_ {}; - DynamicContext *dynamicContext_ {}; OptionalChain *optionalChain_ {}; - InlineCache ic_; - SimpleAllocator sa_; - RegAllocator ra_; - RangeRegAllocator rra_; - - uint32_t usedRegs_ {IRNode::REG_START}; - uint32_t totalRegs_ {IRNode::REG_START}; - int32_t literalBufferIdx_ {0}; - friend class ScopeContext; - friend class RegScope; - friend class LocalRegScope; - friend class LoopRegScope; - friend class ParamRegScope; - friend class FunctionRegScope; + friend class EnvScope; friend class LoopEnvScope; friend class DynamicContext; friend class OptionalChain; - size_t labelId_ {0}; }; } // namespace panda::es2panda::compiler diff --git a/compiler/core/inlineCache.h b/compiler/core/programElement.cpp similarity index 71% rename from compiler/core/inlineCache.h rename to compiler/core/programElement.cpp index fd6d602bca13a8b7960c32de52820ca3e249bcb4..ded115221ba2afa455f6a23e734f6920d215d0cd 100644 --- a/compiler/core/inlineCache.h +++ b/compiler/core/programElement.cpp @@ -13,22 +13,13 @@ * limitations under the License. */ -#ifndef ES2PANDA_COMPILER_IR_INLINE_CACHE_H -#define ES2PANDA_COMPILER_IR_INLINE_CACHE_H +#include "programElement.h" -#include "macros.h" +#include namespace panda::es2panda::compiler { -class InlineCache { -public: - explicit InlineCache() = default; - - size_t Size() const; - uint32_t Offset(uint32_t slotSize); - -private: - size_t size_ {}; -}; +ProgramElement::~ProgramElement() +{ + delete func; +} } // namespace panda::es2panda::compiler - -#endif diff --git a/compiler/core/programElement.h b/compiler/core/programElement.h new file mode 100644 index 0000000000000000000000000000000000000000..5101c369d996c441b30ec0bb0af10ef061c20e6b --- /dev/null +++ b/compiler/core/programElement.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2021-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. + */ + +#ifndef ES2PANDA_COMPILER_CORE_PROGRAM_ELEMENT_H +#define ES2PANDA_COMPILER_CORE_PROGRAM_ELEMENT_H + +#include "macros.h" +#include "plugins/ecmascript/es2panda/compiler/base/literals.h" + +namespace panda::pandasm { +struct Ins; +struct Function; +} // namespace panda::pandasm + +namespace panda::es2panda::compiler { +class ProgramElement { +public: + explicit ProgramElement() = default; + ~ProgramElement(); + NO_COPY_SEMANTIC(ProgramElement); + NO_MOVE_SEMANTIC(ProgramElement); + + std::unordered_set strings; + std::vector literalBufferIns; + std::vector buffStorage; + panda::pandasm::Function *func {}; +}; +} // namespace panda::es2panda::compiler +#endif diff --git a/compiler/core/regAllocator.cpp b/compiler/core/regAllocator.cpp index 13a40894731448ad05b709c788bb229c23d1658d..e95c6c7d48447dcd5cfc0fa0d236b3f10bc5987f 100644 --- a/compiler/core/regAllocator.cpp +++ b/compiler/core/regAllocator.cpp @@ -15,70 +15,76 @@ #include "regAllocator.h" -#include "plugins/ecmascript/es2panda/ir/irnode.h" -#include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" +#include "plugins/ecmascript/es2panda/compiler/core/codeGen.h" +#include "plugins/ecmascript/es2panda/checker/types/type.h" #include namespace panda::es2panda::compiler { -// RegAllocatorBase void AllocatorBase::PushBack(IRNode *ins) { - pg_->Insns().push_back(ins); + cg_->Insns().push_back(ins); } ArenaAllocator *AllocatorBase::Allocator() const { - return pg_->Allocator(); + return cg_->Allocator(); } // SimpleAllocator Label *SimpleAllocator::AllocLabel(std::string &&id) { - const auto *lastInsNode = pg_->Insns().empty() ? FIRST_NODE_OF_FUNCTION : pg_->Insns().back()->Node(); + const auto *lastInsNode = cg_->Insns().empty() ? FIRST_NODE_OF_FUNCTION : cg_->Insns().back()->Node(); return Alloc