From ca7cae6951722688ac1ef4ef836e8c241506dffd Mon Sep 17 00:00:00 2001 From: cm4ker Date: Sat, 21 Jan 2023 02:50:33 +0600 Subject: [PATCH 01/16] add anonymous function syntax and parse it --- src/Aquila.CodeAnalysis/Errors/ErrorCode.cs | 462 +++++++++--------- .../Syntax.xml.Internal.Generated.cs | 249 ++++++++++ .../Generated/Syntax.xml.Main.Generated.cs | 31 ++ .../Generated/Syntax.xml.Syntax.Generated.cs | 90 ++++ .../Parser/LanguageParser.cs | 7 +- .../Parser/LanguageParser_Expr.cs | 16 +- src/Aquila.CodeAnalysis/Syntax/Syntax.xml | 33 +- src/Aquila.CodeAnalysis/Syntax/SyntaxFacts.cs | 2 +- src/Aquila.CodeAnalysis/Syntax/SyntaxKind.cs | 3 +- src/Aquila.Syntax.Test/SourceParserTest.cs | 16 +- 10 files changed, 670 insertions(+), 239 deletions(-) diff --git a/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs b/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs index ddea11c9b..6e91782da 100644 --- a/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs +++ b/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs @@ -21,375 +21,387 @@ internal enum ErrorCode Void = InternalErrorCode.Void, Unknown = InternalErrorCode.Unknown, - // - // Fatal errors - // + #region 3xxx Fatal errors + FTL_InvalidInputFileName = 3000, FTL_BadCodepage = 3016, FTL_InternalCompilerError = 3017, - // - // Errors - // + #endregion - //Syntax - ERR_SyntaxError = 4000, - ERR_IdentifierExpectedKW, - ERR_IdentifierExpected, - ERR_SemicolonExpected, - ERR_CloseParenExpected, - ERR_LbraceExpected, - ERR_RbraceExpected, - ERR_IllegalEscape, - ERR_NewlineInConst, - ERR_BadDirectivePlacement, - - WRN_ErrorOverride, - WRN_BadXMLRefSyntax, - ERR_TypeParamMustBeIdentifier, - ERR_OvlOperatorExpected, - ERR_TripleDotNotAllowed, - ERR_ExpectedVerbatimLiteral, - ERR_EndifDirectiveExpected, - ERR_EndRegionDirectiveExpected, - ERR_UnexpectedCharacter, - ERR_InternalError, - - ERR_FeatureIsExperimental, - ERR_FeatureInPreview, - WRN_LowercaseEllSuffix, - ERR_LegacyObjectIdSyntax, - ERR_InvalidReal, - ERR_InvalidNumber, - ERR_IntOverflow, - ERR_FloatOverflow, - ERR_OpenEndedComment, - ERR_Merge_conflict_marker_encountered, - - ERR_InsufficientStack, - ERR_NamespaceNotAllowedInScript, - ERR_GlobalDefinitionOrStatementExpected, - ERR_EOFExpected, - ERR_InvalidExprTerm, - ERR_BadAwaitAsIdentifier, - ERR_UsingAfterElements, - ERR_TopLevelStatementAfterNamespaceOrType, - ERR_UnexpectedAliasedName, - ERR_TypeExpected, - ERR_BadModifierLocation, - ERR_UnexpectedToken, - ERR_UnexpectedSemicolon, - ERR_SemiOrLBraceOrArrowExpected, - ERR_SemiOrLBraceExpected, - ERR_InvalidMemberDecl, - ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString, - ERR_UnterminatedStringLit, - ERR_UnescapedCurly, - ERR_UnclosedExpressionHole, - ERR_EscapedCurly, - ERR_SingleLineCommentInExpressionHole, - ERR_TooManyCharsInConst, - ERR_EmptyCharConst, - WRN_NonECMAFeature, - ERR_PartialMisplaced, - ERR_BadArraySyntax, - ERR_NoVoidParameter, - ERR_NoVoidHere, - ERR_IllegalVarianceSyntax, - ERR_ValueExpected, - ERR_BadNewExpr, - WRN_PrecedenceInversion, - ERR_ConditionalInInterpolation, - ERR_MissingArgument, - ERR_ExpressionExpected, - ERR_AliasQualAsExpression, - ERR_NamespaceUnexpected, - ERR_BadMemberFlag, - ERR_ConstValueRequired, - ERR_FixedDimsRequired, - ERR_CStyleArray, - ERR_ArraySizeInDeclaration, - ERR_BadVarDecl, - ERR_MultiTypeInDeclaration, - ERR_ElseCannotStartStatement, - ERR_InExpected, - ERR_ExpectedEndTry, + #region 4xxx Errors - //Compilation - ERR_BadCompilationOptionValue, - ERR_BadWin32Resource, - ERR_BinaryFile, - ERR_CantOpenFileWrite, - ERR_CantOpenWin32Icon, - ERR_CantOpenWin32Manifest, - ERR_CantOpenWin32Resource, - ERR_CantReadResource, - ERR_CantReadRulesetFile, - ERR_CompileCancelled, - ERR_EncReferenceToAddedMember, - ERR_ErrorBuildingWin32Resource, - ERR_ErrorOpeningAssemblyFile, - ERR_ErrorOpeningModuleFile, - ERR_ExpectedSingleScript, - ERR_FailedToCreateTempFile, - ERR_FileNotFound, - ERR_InvalidAssemblyMetadata, - ERR_InvalidDebugInformationFormat, - ERR_MetadataFileNotAssembly, - ERR_InvalidFileAlignment, - ERR_InvalidModuleMetadata, - ERR_InvalidOutputName, - ERR_InvalidPathMap, - ERR_InvalidSubsystemVersion, - ERR_LinkedNetmoduleMetadataMustProvideFullPEImage, - ERR_MetadataFileNotFound, - ERR_MetadataFileNotModule, - ERR_MetadataNameTooLong, - ERR_MetadataReferencesNotSupported, - ERR_NoSourceFile, - ERR_StartupObjectNotFound, - ERR_OpenResponseFile, - ERR_OutputWriteFailed, - ERR_PdbWritingFailed, - ERR_PermissionSetAttributeFileReadError, - ERR_PublicKeyContainerFailure, - ERR_PublicKeyFileFailure, - ERR_ResourceFileNameNotUnique, - ERR_ResourceInModule, - ERR_ResourceNotUnique, - ERR_TooManyUserStrings, - ERR_NotYetImplemented, // Used for all valid Aquila constructs - ERR_CircularBase, - ERR_TypeNameCannotBeResolved, - ERR_PositionalArgAfterUnpacking, // Cannot use positional argument after argument unpacking - - ERR_InvalidMetadataConsistance, + #region Syntax + + ERR_SyntaxError = 4000, + ERR_IdentifierExpectedKW = 4001, + ERR_IdentifierExpected = 4002, + ERR_SemicolonExpected = 4003, + ERR_CloseParenExpected = 4004, + ERR_LbraceExpected = 4005, + ERR_RbraceExpected = 4006, + ERR_IllegalEscape = 4007, + ERR_NewlineInConst = 4008, + ERR_BadDirectivePlacement = 4009, + + WRN_ErrorOverride = 4010, + WRN_BadXMLRefSyntax = 4011, + ERR_TypeParamMustBeIdentifier = 4012, + ERR_OvlOperatorExpected = 4013, + ERR_TripleDotNotAllowed = 4014, + ERR_ExpectedVerbatimLiteral = 4015, + ERR_EndifDirectiveExpected = 4016, + ERR_EndRegionDirectiveExpected = 4017, + ERR_UnexpectedCharacter = 4018, + ERR_InternalError = 4019, + + ERR_FeatureIsExperimental = 4020, + ERR_FeatureInPreview = 4021, + WRN_LowercaseEllSuffix = 4022, + ERR_LegacyObjectIdSyntax = 4023, + ERR_InvalidReal = 4024, + ERR_InvalidNumber = 4025, + ERR_IntOverflow = 4026, + ERR_FloatOverflow = 4027, + ERR_OpenEndedComment = 4028, + ERR_Merge_conflict_marker_encountered = 4029, + + ERR_InsufficientStack = 4030, + ERR_NamespaceNotAllowedInScript = 4031, + ERR_GlobalDefinitionOrStatementExpected = 4032, + ERR_EOFExpected = 4033, + ERR_InvalidExprTerm = 4034, + ERR_BadAwaitAsIdentifier = 4035, + ERR_UsingAfterElements = 4036, + ERR_TopLevelStatementAfterNamespaceOrType = 4037, + ERR_UnexpectedAliasedName = 4038, + ERR_TypeExpected = 4039, + ERR_BadModifierLocation = 4040, + ERR_UnexpectedToken = 4041, + ERR_UnexpectedSemicolon = 4042, + ERR_SemiOrLBraceOrArrowExpected = 4043, + ERR_SemiOrLBraceExpected = 4044, + ERR_InvalidMemberDecl = 4045, + ERR_NewlinesAreNotAllowedInsideANonVerbatimInterpolatedString = 4046, + ERR_UnterminatedStringLit = 4047, + ERR_UnescapedCurly = 4048, + ERR_UnclosedExpressionHole = 4049, + ERR_EscapedCurly = 4050, + ERR_SingleLineCommentInExpressionHole = 4051, + ERR_TooManyCharsInConst = 4052, + ERR_EmptyCharConst = 4053, + WRN_NonECMAFeature = 4054, + ERR_PartialMisplaced = 4055, + ERR_BadArraySyntax = 4056, + ERR_NoVoidParameter = 4057, + ERR_NoVoidHere = 4058, + ERR_IllegalVarianceSyntax = 4059, + ERR_ValueExpected = 4060, + ERR_BadNewExpr = 4061, + WRN_PrecedenceInversion = 4062, + ERR_ConditionalInInterpolation = 4063, + ERR_MissingArgument = 4064, + ERR_ExpressionExpected = 4065, + ERR_AliasQualAsExpression = 4066, + ERR_NamespaceUnexpected = 4067, + ERR_BadMemberFlag = 4068, + ERR_ConstValueRequired = 4069, + ERR_FixedDimsRequired = 4070, + ERR_CStyleArray = 4071, + ERR_ArraySizeInDeclaration = 4072, + ERR_BadVarDecl = 4073, + ERR_MultiTypeInDeclaration = 4074, + ERR_ElseCannotStartStatement = 4075, + ERR_InExpected = 4076, + ERR_ExpectedEndTry = 4077, + ERR_NameExpected = 4078, + + #endregion + + #region Compilation + + ERR_BadCompilationOptionValue = 4079, + ERR_BadWin32Resource = 4080, + ERR_BinaryFile = 4081, + ERR_CantOpenFileWrite = 4082, + ERR_CantOpenWin32Icon = 4083, + ERR_CantOpenWin32Manifest = 4084, + ERR_CantOpenWin32Resource = 4085, + ERR_CantReadResource = 4086, + ERR_CantReadRulesetFile = 4087, + ERR_CompileCancelled = 4088, + ERR_EncReferenceToAddedMember = 4089, + ERR_ErrorBuildingWin32Resource = 4090, + ERR_ErrorOpeningAssemblyFile = 4091, + ERR_ErrorOpeningModuleFile = 4092, + ERR_ExpectedSingleScript = 4093, + ERR_FailedToCreateTempFile = 4094, + ERR_FileNotFound = 4095, + ERR_InvalidAssemblyMetadata = 4096, + ERR_InvalidDebugInformationFormat = 4097, + ERR_MetadataFileNotAssembly = 4098, + ERR_InvalidFileAlignment = 4099, + ERR_InvalidModuleMetadata = 4100, + ERR_InvalidOutputName = 4101, + ERR_InvalidPathMap = 4102, + ERR_InvalidSubsystemVersion = 4103, + ERR_LinkedNetmoduleMetadataMustProvideFullPEImage = 4104, + ERR_MetadataFileNotFound = 4105, + ERR_MetadataFileNotModule = 4106, + ERR_MetadataNameTooLong = 4107, + ERR_MetadataReferencesNotSupported = 4108, + ERR_NoSourceFile = 4109, + ERR_StartupObjectNotFound = 4110, + ERR_OpenResponseFile = 4111, + ERR_OutputWriteFailed = 4112, + ERR_PdbWritingFailed = 4113, + ERR_PermissionSetAttributeFileReadError = 4114, + ERR_PublicKeyContainerFailure = 4115, + ERR_PublicKeyFileFailure = 4116, + ERR_ResourceFileNameNotUnique = 4117, + ERR_ResourceInModule = 4118, + ERR_ResourceNotUnique = 4119, + ERR_TooManyUserStrings = 4120, + ERR_NotYetImplemented = 4121, // Used for all valid Aquila constructs + ERR_CircularBase = 4122, + ERR_TypeNameCannotBeResolved = 4123, + ERR_PositionalArgAfterUnpacking = 4124, // Cannot use positional argument after argument unpacking + + ERR_InvalidMetadataConsistance = 4125, /// Call to a member function {0} on {1} - ERR_MethodCalledOnNonObject, + ERR_MethodCalledOnNonObject = 4126, /// Value of type {0} cannot be passed by reference - ERR_ValueOfTypeCannotBeAliased, + ERR_ValueOfTypeCannotBeAliased = 4127, /// "Cannot instantiate {0} {1}", e.g. "interface", the type name - ERR_CannotInstantiateType, + ERR_CannotInstantiateType = 4128, /// "{0} cannot use {1} - it is not a trait" - ERR_CannotUseNonTrait, + ERR_CannotUseNonTrait = 4129, /// "Class {0} cannot extend from {1} {2}", e.g. from trait T - ERR_CannotExtendFrom, + ERR_CannotExtendFrom = 4130, /// "{0} cannot implement {1} - it is not an interface" - ERR_CannotImplementNonInterface, + ERR_CannotImplementNonInterface = 4131, /// Cannot re-assign $this - ERR_CannotAssignToThis, + ERR_CannotAssignToThis = 4132, /// {0}() cannot declare a return type - ERR_CannotDeclareReturnType, + ERR_CannotDeclareReturnType = 4133, /// A void function must not return a value - ERR_VoidFunctionCannotReturnValue, + ERR_VoidFunctionCannotReturnValue = 4134, /// {0} {1}() must take exactly {2} arguments - ERR_MustTakeArgs, + ERR_MustTakeArgs = 4135, /// Function name must be a string, {0} given - ERR_InvalidFunctionName, + ERR_InvalidFunctionName = 4136, /// Cannot use the final modifier on an abstract class - ERR_FinalAbstractClassDeclared, + ERR_FinalAbstractClassDeclared = 4137, /// Access level to {0}::${1} must be {2} (as in class {3}) or weaker - ERR_PropertyAccessibilityError, + ERR_PropertyAccessibilityError = 4138, /// Use of primitive type '{0}' is misused - ERR_PrimitiveTypeNameMisused, + ERR_PrimitiveTypeNameMisused = 4139, /// Missing value for '{0}' option - ERR_SwitchNeedsValue, + ERR_SwitchNeedsValue = 4140, /// '{0}' not in the 'loop' or 'switch' context - ERR_NeedsLoopOrSwitch, + ERR_NeedsLoopOrSwitch = 4141, /// Provided source code kind is unsupported or invalid: '{0}' - ERR_BadSourceCodeKind, + ERR_BadSourceCodeKind = 4142, /// Provided documentation mode is unsupported or invalid: '{0}'. - ERR_BadDocumentationMode, + ERR_BadDocumentationMode = 4143, /// Compilation options '{0}' and '{1}' can't both be specified at the same time. - ERR_MutuallyExclusiveOptions, + ERR_MutuallyExclusiveOptions = 4144, /// Invalid instrumentation kind: {0} - ERR_InvalidInstrumentationKind, + ERR_InvalidInstrumentationKind = 4145, /// Invalid hash algorithm name: '{0}' - ERR_InvalidHashAlgorithmName, + ERR_InvalidHashAlgorithmName = 4146, /// Option '{0}' must be an absolute path. - ERR_OptionMustBeAbsolutePath, + ERR_OptionMustBeAbsolutePath = 4147, /// Cannot emit debug information for a source text without encoding. - ERR_EncodinglessSyntaxTree, + ERR_EncodinglessSyntaxTree = 4148, /// An error occurred while writing the output file: {0}. - ERR_PeWritingFailure, + ERR_PeWritingFailure = 4149, /// Failed to emit module '{0}'. - ERR_ModuleEmitFailure, + ERR_ModuleEmitFailure = 4150, /// Cannot update '{0}'; attribute '{1}' is missing. - ERR_EncUpdateFailedMissingAttribute, + ERR_EncUpdateFailedMissingAttribute = 4151, /// Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - ERR_InvalidDebugInfo, + ERR_InvalidDebugInfo = 4152, /// Invalid assembly name: {0} - ERR_BadAssemblyName, + ERR_BadAssemblyName = 4153, /// /embed switch is only supported when emitting Portable PDB (/debug:portable or /debug:embedded). - ERR_CannotEmbedWithoutPdb, + ERR_CannotEmbedWithoutPdb = 4154, /// No overload for method {0} can be called. - ERR_NoMatchingOverload, + ERR_NoMatchingOverload = 4155, /// Default value for parameter ${0} with a {1} type can only be {1} or NULL, {2} given - ERR_DefaultParameterValueTypeMismatch, + ERR_DefaultParameterValueTypeMismatch = 4156, /// Constant expression contains invalid operations - ERR_InvalidConstantExpression, + ERR_InvalidConstantExpression = 4157, /// Using $this when not in object context - ERR_ThisOutOfObjectContext, + ERR_ThisOutOfObjectContext = 4158, /// Cannot set read-only property {0}::${1} - ERR_ReadOnlyPropertyWritten, + ERR_ReadOnlyPropertyWritten = 4159, /// Only the last parameter can be variadic - ERR_VariadicParameterNotLast, - ERR_CtorPropertyVariadic, - ERR_CtorPropertyAbstractCtor, - ERR_CtorPropertyNotCtor, - ERR_CtorPropertyStaticCtor, + ERR_VariadicParameterNotLast = 4160, + ERR_CtorPropertyVariadic = 4161, + ERR_CtorPropertyAbstractCtor = 4162, + ERR_CtorPropertyNotCtor = 4163, + ERR_CtorPropertyStaticCtor = 4164, /// Property {0}::${1} cannot have type {2} - ERR_PropertyTypeNotAllowed, + ERR_PropertyTypeNotAllowed = 4165, /// Multiple analyzer config files cannot be in the same directory ('{0}'). - ERR_MultipleAnalyzerConfigsInSameDir, + ERR_MultipleAnalyzerConfigsInSameDir = 4166, /// Method '{0}' not found for type {1}. - ERR_MethodNotFound, + ERR_MethodNotFound = 4167, - ERR_MissingIdentifierSymbol, + ERR_MissingIdentifierSymbol = 4168, + + #endregion + + #endregion + + #region 5xxx Warnings - // - // Warnings - // //Parse WRN_XMLParseError = 5000, - //Compilation - WRN_AnalyzerCannotBeCreated, - WRN_NoAnalyzerInAssembly, - WRN_NoConfigNotOnCommandLine, - WRN_PdbLocalNameTooLong, - WRN_PdbUsingNameTooLong, - WRN_UnableToLoadAnalyzer, - WRN_UndefinedFunctionCall, - WRN_UninitializedVariableUse, - WRN_UndefinedType, - WRN_UndefinedMethodCall, + WRN_AnalyzerCannotBeCreated = 5001, + WRN_NoAnalyzerInAssembly = 5002, + WRN_NoConfigNotOnCommandLine = 5003, + WRN_PdbLocalNameTooLong = 5004, + WRN_PdbUsingNameTooLong = 5005, + WRN_UnableToLoadAnalyzer = 5006, + WRN_UndefinedFunctionCall = 5007, + WRN_UninitializedVariableUse = 5008, + WRN_UndefinedType = 5009, + WRN_UndefinedMethodCall = 5010, /// The declaration of class, interface or trait is ambiguous since its base types cannot be resolved. - WRN_AmbiguousDeclaration, - WRN_UnreachableCode, - WRN_NotYetImplementedIgnored, - WRN_NoSourceFiles, + WRN_AmbiguousDeclaration = 5011, + WRN_UnreachableCode = 5012, + WRN_NotYetImplementedIgnored = 5013, + WRN_NoSourceFiles = 5014, /// {0}() expects {1} parameter(s), {2} given - WRN_TooManyArguments, + WRN_TooManyArguments = 5015, /// {0}() expects at least {1} parameter(s), {2} given - WRN_MissingArguments, + WRN_MissingArguments = 5016, /// Assertion will always fail - WRN_AssertAlwaysFail, + WRN_AssertAlwaysFail = 5017, /// Using string as the assertion is deprecated - WRN_StringAssertionDeprecated, + WRN_StringAssertionDeprecated = 5018, /// Deprecated: {0} '{1}' has been deprecated. {2} - WRN_SymbolDeprecated, + WRN_SymbolDeprecated = 5019, /// The expression is not being read. Did you mean to assign it somewhere? - WRN_ExpressionNotRead, + WRN_ExpressionNotRead = 5020, /// Assignment made to same variable; did you mean to assign something else? - WRN_AssigningSameVariable, + WRN_AssigningSameVariable = 5021, /// Invalid array key type: {0}. - WRN_InvalidArrayKeyType, + WRN_InvalidArrayKeyType = 5022, /// Duplicate array key: '{0}'. - WRN_DuplicateArrayKey, + WRN_DuplicateArrayKey = 5023, /// Cloning of non-object: {0}. - WRN_CloneNonObject, + WRN_CloneNonObject = 5024, /// Using non-iterable type in foreach: {0}. - WRN_ForeachNonIterable, + WRN_ForeachNonIterable = 5025, /// Call to '{0}()' expects {1} argument(s), {2} given. - WRN_FormatStringWrongArgCount, + WRN_FormatStringWrongArgCount = 5026, /// Missing the call of parent::__construct from {0}::__construct. - WRN_ParentCtorNotCalled, + WRN_ParentCtorNotCalled = 5027, /// Method {0}::__toString() must return a string value - WRN_ToStringMustReturnString, + WRN_ToStringMustReturnString = 5028, /// Argument has no value, parameter will be always NULL - WRN_ArgumentVoid, + WRN_ArgumentVoid = 5029, /// PCRE pattern parse error: {0} at offset {1} - WRN_PCRE_Pattern_Error, + WRN_PCRE_Pattern_Error = 5030, /// {0} '{1}' is already defined - WRN_TypeNameInUse, + WRN_TypeNameInUse = 5031, /// Script file '{0}' could not be resolved, the script inclusion is unbound. - WRN_CannotIncludeFile, + WRN_CannotIncludeFile = 5032, /// Called from the global scope - WRN_CalledFromGlobalScope, + WRN_CalledFromGlobalScope = 5033, /// Generator '{0}' failed to initialize. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}' - WRN_GeneratorFailedDuringInitialization, + WRN_GeneratorFailedDuringInitialization = 5034, /// Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}' - WRN_GeneratorFailedDuringGeneration, + WRN_GeneratorFailedDuringGeneration = 5035, + + #endregion + + #region 6xxx Visible information // // Visible information // INF_UnableToLoadSomeTypesInAnalyzer = 6000, - INF_EvalDiscouraged, - INF_RedundantCast, + INF_EvalDiscouraged = 6001, + INF_RedundantCast = 6002, /// Name '{0}' does not match the expected name '{1}', letter casing mismatch. - INF_TypeNameCaseMismatch, + INF_TypeNameCaseMismatch = 6003, /// - INF_DestructDiscouraged, + INF_DestructDiscouraged = 6004, /// Overriden function name '{0}' does not match it's parent name '{1}', letter casing mismatch. - INF_OverrideNameCaseMismatch, + INF_OverrideNameCaseMismatch = 6005, /// The symbol can not been resolved - INF_CantResolveSymbol + INF_CantResolveSymbol = 6006 + + #endregion } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Internal.Generated.cs b/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Internal.Generated.cs index a926edfeb..3300a757f 100644 --- a/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Internal.Generated.cs +++ b/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Internal.Generated.cs @@ -4823,6 +4823,209 @@ static CastEx() } } + internal sealed partial class FuncEx : ExprSyntax + { + internal readonly SyntaxToken fnKeyword; + internal readonly ParameterListSyntax parameterList; + internal readonly TypeEx? returnType; + internal readonly BlockStmt? body; + internal readonly ArrowExClause? expressionBody; + internal readonly SyntaxToken? semicolonToken; + + internal FuncEx(SyntaxKind kind, SyntaxToken fnKeyword, ParameterListSyntax parameterList, TypeEx? returnType, BlockStmt? body, ArrowExClause? expressionBody, SyntaxToken? semicolonToken, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) + : base(kind, diagnostics, annotations) + { + this.SlotCount = 6; + this.AdjustFlagsAndWidth(fnKeyword); + this.fnKeyword = fnKeyword; + this.AdjustFlagsAndWidth(parameterList); + this.parameterList = parameterList; + if (returnType != null) + { + this.AdjustFlagsAndWidth(returnType); + this.returnType = returnType; + } + if (body != null) + { + this.AdjustFlagsAndWidth(body); + this.body = body; + } + if (expressionBody != null) + { + this.AdjustFlagsAndWidth(expressionBody); + this.expressionBody = expressionBody; + } + if (semicolonToken != null) + { + this.AdjustFlagsAndWidth(semicolonToken); + this.semicolonToken = semicolonToken; + } + } + + internal FuncEx(SyntaxKind kind, SyntaxToken fnKeyword, ParameterListSyntax parameterList, TypeEx? returnType, BlockStmt? body, ArrowExClause? expressionBody, SyntaxToken? semicolonToken, SyntaxFactoryContext context) + : base(kind) + { + this.SetFactoryContext(context); + this.SlotCount = 6; + this.AdjustFlagsAndWidth(fnKeyword); + this.fnKeyword = fnKeyword; + this.AdjustFlagsAndWidth(parameterList); + this.parameterList = parameterList; + if (returnType != null) + { + this.AdjustFlagsAndWidth(returnType); + this.returnType = returnType; + } + if (body != null) + { + this.AdjustFlagsAndWidth(body); + this.body = body; + } + if (expressionBody != null) + { + this.AdjustFlagsAndWidth(expressionBody); + this.expressionBody = expressionBody; + } + if (semicolonToken != null) + { + this.AdjustFlagsAndWidth(semicolonToken); + this.semicolonToken = semicolonToken; + } + } + + internal FuncEx(SyntaxKind kind, SyntaxToken fnKeyword, ParameterListSyntax parameterList, TypeEx? returnType, BlockStmt? body, ArrowExClause? expressionBody, SyntaxToken? semicolonToken) + : base(kind) + { + this.SlotCount = 6; + this.AdjustFlagsAndWidth(fnKeyword); + this.fnKeyword = fnKeyword; + this.AdjustFlagsAndWidth(parameterList); + this.parameterList = parameterList; + if (returnType != null) + { + this.AdjustFlagsAndWidth(returnType); + this.returnType = returnType; + } + if (body != null) + { + this.AdjustFlagsAndWidth(body); + this.body = body; + } + if (expressionBody != null) + { + this.AdjustFlagsAndWidth(expressionBody); + this.expressionBody = expressionBody; + } + if (semicolonToken != null) + { + this.AdjustFlagsAndWidth(semicolonToken); + this.semicolonToken = semicolonToken; + } + } + + public SyntaxToken FnKeyword => this.fnKeyword; + /// Gets the parameter list. + public ParameterListSyntax ParameterList => this.parameterList; + /// Gets the return type syntax. + public TypeEx? ReturnType => this.returnType; + public BlockStmt? Body => this.body; + public ArrowExClause? ExpressionBody => this.expressionBody; + /// Gets the optional semicolon token. + public SyntaxToken? SemicolonToken => this.semicolonToken; + + internal override GreenNode? GetSlot(int index) + => index switch + { + 0 => this.fnKeyword, + 1 => this.parameterList, + 2 => this.returnType, + 3 => this.body, + 4 => this.expressionBody, + 5 => this.semicolonToken, + _ => null, + }; + + internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new Aquila.CodeAnalysis.Syntax.FuncEx(this, parent, position); + + public override void Accept(AquilaSyntaxVisitor visitor) => visitor.VisitFuncEx(this); + public override TResult Accept(AquilaSyntaxVisitor visitor) => visitor.VisitFuncEx(this); + + public FuncEx Update(SyntaxToken fnKeyword, ParameterListSyntax parameterList, TypeEx returnType, BlockStmt body, ArrowExClause expressionBody, SyntaxToken semicolonToken) + { + if (fnKeyword != this.FnKeyword || parameterList != this.ParameterList || returnType != this.ReturnType || body != this.Body || expressionBody != this.ExpressionBody || semicolonToken != this.SemicolonToken) + { + var newNode = SyntaxFactory.FuncEx(fnKeyword, parameterList, returnType, body, expressionBody, semicolonToken); + var diags = GetDiagnostics(); + if (diags?.Length > 0) + newNode = newNode.WithDiagnosticsGreen(diags); + var annotations = GetAnnotations(); + if (annotations?.Length > 0) + newNode = newNode.WithAnnotationsGreen(annotations); + return newNode; + } + + return this; + } + + internal override GreenNode SetDiagnostics(DiagnosticInfo[]? diagnostics) + => new FuncEx(this.Kind, this.fnKeyword, this.parameterList, this.returnType, this.body, this.expressionBody, this.semicolonToken, diagnostics, GetAnnotations()); + + internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) + => new FuncEx(this.Kind, this.fnKeyword, this.parameterList, this.returnType, this.body, this.expressionBody, this.semicolonToken, GetDiagnostics(), annotations); + + internal FuncEx(ObjectReader reader) + : base(reader) + { + this.SlotCount = 6; + var fnKeyword = (SyntaxToken)reader.ReadValue(); + AdjustFlagsAndWidth(fnKeyword); + this.fnKeyword = fnKeyword; + var parameterList = (ParameterListSyntax)reader.ReadValue(); + AdjustFlagsAndWidth(parameterList); + this.parameterList = parameterList; + var returnType = (TypeEx?)reader.ReadValue(); + if (returnType != null) + { + AdjustFlagsAndWidth(returnType); + this.returnType = returnType; + } + var body = (BlockStmt?)reader.ReadValue(); + if (body != null) + { + AdjustFlagsAndWidth(body); + this.body = body; + } + var expressionBody = (ArrowExClause?)reader.ReadValue(); + if (expressionBody != null) + { + AdjustFlagsAndWidth(expressionBody); + this.expressionBody = expressionBody; + } + var semicolonToken = (SyntaxToken?)reader.ReadValue(); + if (semicolonToken != null) + { + AdjustFlagsAndWidth(semicolonToken); + this.semicolonToken = semicolonToken; + } + } + + internal override void WriteTo(ObjectWriter writer) + { + base.WriteTo(writer); + writer.WriteValue(this.fnKeyword); + writer.WriteValue(this.parameterList); + writer.WriteValue(this.returnType); + writer.WriteValue(this.body); + writer.WriteValue(this.expressionBody); + writer.WriteValue(this.semicolonToken); + } + + static FuncEx() + { + ObjectBinder.RegisterTypeReader(typeof(FuncEx), r => new FuncEx(r)); + } + } + /// Represents a match expression syntax. internal sealed partial class MatchEx : ExprSyntax { @@ -16159,6 +16362,7 @@ internal partial class AquilaSyntaxVisitor public virtual TResult VisitInitializerEx(InitializerEx node) => this.DefaultVisit(node); public virtual TResult VisitAllocEx(AllocEx node) => this.DefaultVisit(node); public virtual TResult VisitCastEx(CastEx node) => this.DefaultVisit(node); + public virtual TResult VisitFuncEx(FuncEx node) => this.DefaultVisit(node); public virtual TResult VisitMatchEx(MatchEx node) => this.DefaultVisit(node); public virtual TResult VisitMatchArm(MatchArm node) => this.DefaultVisit(node); public virtual TResult VisitInterpolatedStringText(InterpolatedStringTextSyntax node) => this.DefaultVisit(node); @@ -16285,6 +16489,7 @@ internal partial class AquilaSyntaxVisitor public virtual void VisitInitializerEx(InitializerEx node) => this.DefaultVisit(node); public virtual void VisitAllocEx(AllocEx node) => this.DefaultVisit(node); public virtual void VisitCastEx(CastEx node) => this.DefaultVisit(node); + public virtual void VisitFuncEx(FuncEx node) => this.DefaultVisit(node); public virtual void VisitMatchEx(MatchEx node) => this.DefaultVisit(node); public virtual void VisitMatchArm(MatchArm node) => this.DefaultVisit(node); public virtual void VisitInterpolatedStringText(InterpolatedStringTextSyntax node) => this.DefaultVisit(node); @@ -16481,6 +16686,9 @@ public override AquilaSyntaxNode VisitAllocEx(AllocEx node) public override AquilaSyntaxNode VisitCastEx(CastEx node) => node.Update((SyntaxToken)Visit(node.OpenParenToken), (TypeEx)Visit(node.Type), (SyntaxToken)Visit(node.CloseParenToken), (ExprSyntax)Visit(node.Expression)); + public override AquilaSyntaxNode VisitFuncEx(FuncEx node) + => node.Update((SyntaxToken)Visit(node.FnKeyword), (ParameterListSyntax)Visit(node.ParameterList), (TypeEx)Visit(node.ReturnType), (BlockStmt)Visit(node.Body), (ArrowExClause)Visit(node.ExpressionBody), (SyntaxToken)Visit(node.SemicolonToken)); + public override AquilaSyntaxNode VisitMatchEx(MatchEx node) => node.Update((SyntaxToken)Visit(node.MatchKeyword), (SyntaxToken)Visit(node.OpenParenToken), (ExprSyntax)Visit(node.Expression), (SyntaxToken)Visit(node.CloseParenToken), (SyntaxToken)Visit(node.OpenBraceToken), VisitList(node.Arms), (SyntaxToken)Visit(node.CloseBraceToken)); @@ -17619,6 +17827,26 @@ public CastEx CastEx(SyntaxToken openParenToken, TypeEx type, SyntaxToken closeP return new CastEx(SyntaxKind.CastExpression, openParenToken, type, closeParenToken, expression, this.context); } + public FuncEx FuncEx(SyntaxToken fnKeyword, ParameterListSyntax parameterList, TypeEx? returnType, BlockStmt? body, ArrowExClause? expressionBody, SyntaxToken? semicolonToken) + { +#if DEBUG + if (fnKeyword == null) throw new ArgumentNullException(nameof(fnKeyword)); + if (fnKeyword.Kind != SyntaxKind.FnKeyword) throw new ArgumentException(nameof(fnKeyword)); + if (parameterList == null) throw new ArgumentNullException(nameof(parameterList)); + if (semicolonToken != null) + { + switch (semicolonToken.Kind) + { + case SyntaxKind.SemicolonToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(semicolonToken)); + } + } +#endif + + return new FuncEx(SyntaxKind.AnonymousFunctionExpression, fnKeyword, parameterList, returnType, body, expressionBody, semicolonToken, this.context); + } + public MatchEx MatchEx(SyntaxToken matchKeyword, SyntaxToken? openParenToken, ExprSyntax expression, SyntaxToken? closeParenToken, SyntaxToken openBraceToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList arms, SyntaxToken closeBraceToken) { #if DEBUG @@ -20296,6 +20524,26 @@ public static CastEx CastEx(SyntaxToken openParenToken, TypeEx type, SyntaxToken return new CastEx(SyntaxKind.CastExpression, openParenToken, type, closeParenToken, expression); } + public static FuncEx FuncEx(SyntaxToken fnKeyword, ParameterListSyntax parameterList, TypeEx? returnType, BlockStmt? body, ArrowExClause? expressionBody, SyntaxToken? semicolonToken) + { +#if DEBUG + if (fnKeyword == null) throw new ArgumentNullException(nameof(fnKeyword)); + if (fnKeyword.Kind != SyntaxKind.FnKeyword) throw new ArgumentException(nameof(fnKeyword)); + if (parameterList == null) throw new ArgumentNullException(nameof(parameterList)); + if (semicolonToken != null) + { + switch (semicolonToken.Kind) + { + case SyntaxKind.SemicolonToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(semicolonToken)); + } + } +#endif + + return new FuncEx(SyntaxKind.AnonymousFunctionExpression, fnKeyword, parameterList, returnType, body, expressionBody, semicolonToken); + } + public static MatchEx MatchEx(SyntaxToken matchKeyword, SyntaxToken? openParenToken, ExprSyntax expression, SyntaxToken? closeParenToken, SyntaxToken openBraceToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList arms, SyntaxToken closeBraceToken) { #if DEBUG @@ -22139,6 +22387,7 @@ internal static IEnumerable GetNodeTypes() typeof(InitializerEx), typeof(AllocEx), typeof(CastEx), + typeof(FuncEx), typeof(MatchEx), typeof(MatchArm), typeof(InterpolatedStringTextSyntax), diff --git a/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Main.Generated.cs b/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Main.Generated.cs index 0e7800151..730771964 100644 --- a/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Main.Generated.cs +++ b/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Main.Generated.cs @@ -121,6 +121,9 @@ public partial class AquilaSyntaxVisitor /// Called when the visitor visits a CastEx node. public virtual TResult? VisitCastEx(CastEx node) => this.DefaultVisit(node); + /// Called when the visitor visits a FuncEx node. + public virtual TResult? VisitFuncEx(FuncEx node) => this.DefaultVisit(node); + /// Called when the visitor visits a MatchEx node. public virtual TResult? VisitMatchEx(MatchEx node) => this.DefaultVisit(node); @@ -490,6 +493,9 @@ public partial class AquilaSyntaxVisitor /// Called when the visitor visits a CastEx node. public virtual void VisitCastEx(CastEx node) => this.DefaultVisit(node); + /// Called when the visitor visits a FuncEx node. + public virtual void VisitFuncEx(FuncEx node) => this.DefaultVisit(node); + /// Called when the visitor visits a MatchEx node. public virtual void VisitMatchEx(MatchEx node) => this.DefaultVisit(node); @@ -859,6 +865,9 @@ public partial class AquilaSyntaxRewriter : AquilaSyntaxVisitor public override SyntaxNode? VisitCastEx(CastEx node) => node.Update(VisitToken(node.OpenParenToken), (TypeEx?)Visit(node.Type) ?? throw new ArgumentNullException("type"), VisitToken(node.CloseParenToken), (ExprSyntax?)Visit(node.Expression) ?? throw new ArgumentNullException("expression")); + public override SyntaxNode? VisitFuncEx(FuncEx node) + => node.Update(VisitToken(node.FnKeyword), (ParameterListSyntax?)Visit(node.ParameterList) ?? throw new ArgumentNullException("parameterList"), (TypeEx?)Visit(node.ReturnType), (BlockStmt?)Visit(node.Body), (ArrowExClause?)Visit(node.ExpressionBody), VisitToken(node.SemicolonToken)); + public override SyntaxNode? VisitMatchEx(MatchEx node) => node.Update(VisitToken(node.MatchKeyword), VisitToken(node.OpenParenToken), (ExprSyntax?)Visit(node.Expression) ?? throw new ArgumentNullException("expression"), VisitToken(node.CloseParenToken), VisitToken(node.OpenBraceToken), VisitList(node.Arms), VisitToken(node.CloseBraceToken)); @@ -1894,6 +1903,28 @@ public static CastEx CastEx(SyntaxToken openParenToken, TypeEx type, SyntaxToken public static CastEx CastEx(TypeEx type, ExprSyntax expression) => SyntaxFactory.CastEx(SyntaxFactory.Token(SyntaxKind.OpenParenToken), type, SyntaxFactory.Token(SyntaxKind.CloseParenToken), expression); + /// Creates a new FuncEx instance. + public static FuncEx FuncEx(SyntaxToken fnKeyword, ParameterListSyntax parameterList, TypeEx? returnType, BlockStmt? body, ArrowExClause? expressionBody, SyntaxToken semicolonToken) + { + if (fnKeyword.Kind() != SyntaxKind.FnKeyword) throw new ArgumentException(nameof(fnKeyword)); + if (parameterList == null) throw new ArgumentNullException(nameof(parameterList)); + switch (semicolonToken.Kind()) + { + case SyntaxKind.SemicolonToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(semicolonToken)); + } + return (FuncEx)Syntax.InternalSyntax.SyntaxFactory.FuncEx((Syntax.InternalSyntax.SyntaxToken)fnKeyword.Node!, (Syntax.InternalSyntax.ParameterListSyntax)parameterList.Green, returnType == null ? null : (Syntax.InternalSyntax.TypeEx)returnType.Green, body == null ? null : (Syntax.InternalSyntax.BlockStmt)body.Green, expressionBody == null ? null : (Syntax.InternalSyntax.ArrowExClause)expressionBody.Green, (Syntax.InternalSyntax.SyntaxToken?)semicolonToken.Node).CreateRed(); + } + + /// Creates a new FuncEx instance. + public static FuncEx FuncEx(ParameterListSyntax parameterList, TypeEx? returnType, BlockStmt? body, ArrowExClause? expressionBody) + => SyntaxFactory.FuncEx(SyntaxFactory.Token(SyntaxKind.FnKeyword), parameterList, returnType, body, expressionBody, default); + + /// Creates a new FuncEx instance. + public static FuncEx FuncEx() + => SyntaxFactory.FuncEx(SyntaxFactory.Token(SyntaxKind.FnKeyword), SyntaxFactory.ParameterList(), default, default, default, default); + /// Creates a new MatchEx instance. public static MatchEx MatchEx(SyntaxToken matchKeyword, SyntaxToken openParenToken, ExprSyntax expression, SyntaxToken closeParenToken, SyntaxToken openBraceToken, SeparatedSyntaxList arms, SyntaxToken closeBraceToken) { diff --git a/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Syntax.Generated.cs b/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Syntax.Generated.cs index 0b18ef1c6..42b7c5293 100644 --- a/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Syntax.Generated.cs +++ b/src/Aquila.CodeAnalysis/Generated/Syntax.xml.Syntax.Generated.cs @@ -2303,6 +2303,96 @@ public CastEx Update(SyntaxToken openParenToken, TypeEx type, SyntaxToken closeP public CastEx WithExpression(ExprSyntax expression) => Update(this.OpenParenToken, this.Type, this.CloseParenToken, expression); } + /// + /// This node is associated with the following syntax kinds: + /// + /// + /// + /// + public sealed partial class FuncEx : ExprSyntax + { + private ParameterListSyntax? parameterList; + private TypeEx? returnType; + private BlockStmt? body; + private ArrowExClause? expressionBody; + + internal FuncEx(InternalSyntax.AquilaSyntaxNode green, SyntaxNode? parent, int position) + : base(green, parent, position) + { + } + + public SyntaxToken FnKeyword => new SyntaxToken(this, ((Syntax.InternalSyntax.FuncEx)this.Green).fnKeyword, Position, 0); + + /// Gets the parameter list. + public ParameterListSyntax ParameterList => GetRed(ref this.parameterList, 1)!; + + /// Gets the return type syntax. + public TypeEx? ReturnType => GetRed(ref this.returnType, 2); + + public BlockStmt? Body => GetRed(ref this.body, 3); + + public ArrowExClause? ExpressionBody => GetRed(ref this.expressionBody, 4); + + /// Gets the optional semicolon token. + public SyntaxToken SemicolonToken + { + get + { + var slot = ((Syntax.InternalSyntax.FuncEx)this.Green).semicolonToken; + return slot != null ? new SyntaxToken(this, slot, GetChildPosition(5), GetChildIndex(5)) : default; + } + } + + internal override SyntaxNode? GetNodeSlot(int index) + => index switch + { + 1 => GetRed(ref this.parameterList, 1)!, + 2 => GetRed(ref this.returnType, 2), + 3 => GetRed(ref this.body, 3), + 4 => GetRed(ref this.expressionBody, 4), + _ => null, + }; + + internal override SyntaxNode? GetCachedSlot(int index) + => index switch + { + 1 => this.parameterList, + 2 => this.returnType, + 3 => this.body, + 4 => this.expressionBody, + _ => null, + }; + + public override void Accept(AquilaSyntaxVisitor visitor) => visitor.VisitFuncEx(this); + public override TResult? Accept(AquilaSyntaxVisitor visitor) where TResult : default => visitor.VisitFuncEx(this); + + public FuncEx Update(SyntaxToken fnKeyword, ParameterListSyntax parameterList, TypeEx? returnType, BlockStmt? body, ArrowExClause? expressionBody, SyntaxToken semicolonToken) + { + if (fnKeyword != this.FnKeyword || parameterList != this.ParameterList || returnType != this.ReturnType || body != this.Body || expressionBody != this.ExpressionBody || semicolonToken != this.SemicolonToken) + { + var newNode = SyntaxFactory.FuncEx(fnKeyword, parameterList, returnType, body, expressionBody, semicolonToken); + var annotations = GetAnnotations(); + return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode; + } + + return this; + } + + public FuncEx WithFnKeyword(SyntaxToken fnKeyword) => Update(fnKeyword, this.ParameterList, this.ReturnType, this.Body, this.ExpressionBody, this.SemicolonToken); + public FuncEx WithParameterList(ParameterListSyntax parameterList) => Update(this.FnKeyword, parameterList, this.ReturnType, this.Body, this.ExpressionBody, this.SemicolonToken); + public FuncEx WithReturnType(TypeEx? returnType) => Update(this.FnKeyword, this.ParameterList, returnType, this.Body, this.ExpressionBody, this.SemicolonToken); + public FuncEx WithBody(BlockStmt? body) => Update(this.FnKeyword, this.ParameterList, this.ReturnType, body, this.ExpressionBody, this.SemicolonToken); + public FuncEx WithExpressionBody(ArrowExClause? expressionBody) => Update(this.FnKeyword, this.ParameterList, this.ReturnType, this.Body, expressionBody, this.SemicolonToken); + public FuncEx WithSemicolonToken(SyntaxToken semicolonToken) => Update(this.FnKeyword, this.ParameterList, this.ReturnType, this.Body, this.ExpressionBody, semicolonToken); + + public FuncEx AddParameterListParameters(params ParameterSyntax[] items) => WithParameterList(this.ParameterList.WithParameters(this.ParameterList.Parameters.AddRange(items))); + public FuncEx AddBodyStatements(params StmtSyntax[] items) + { + var body = this.Body ?? SyntaxFactory.BlockStmt(); + return WithBody(body.WithStatements(body.Statements.AddRange(items))); + } + } + /// Represents a match expression syntax. /// /// This node is associated with the following syntax kinds: diff --git a/src/Aquila.CodeAnalysis/Parser/LanguageParser.cs b/src/Aquila.CodeAnalysis/Parser/LanguageParser.cs index 223c36bfb..3c57923b2 100644 --- a/src/Aquila.CodeAnalysis/Parser/LanguageParser.cs +++ b/src/Aquila.CodeAnalysis/Parser/LanguageParser.cs @@ -2629,7 +2629,7 @@ private VariableInit ParseVariableDeclarator( if (string.IsNullOrWhiteSpace(name.GetValueText())) { - throw new Exception("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + name = this.AddError(name, ErrorCode.ERR_NameExpected); } return _syntaxFactory.VariableInit(name, argumentList, initializer); @@ -5897,7 +5897,7 @@ private static Precedence GetPrecedence(SyntaxKind op) return Precedence.Expression; case SyntaxKind.ParenthesizedLambdaExpression: case SyntaxKind.SimpleLambdaExpression: - case SyntaxKind.AnonymousMethodExpression: + case SyntaxKind.AnonymousFunctionExpression: return Precedence.Lambda; case SyntaxKind.SimpleAssignmentExpression: case SyntaxKind.AddAssignmentExpression: @@ -6149,7 +6149,6 @@ private ExprSyntax ParseSubExpressionCore(Precedence precedence) leftOperand = _syntaxFactory.RangeEx(leftOperand: null, opToken, rightOperand); } - else if (this.IsQueryExpression(mayBeVariableDeclaration: false, mayBeMemberDeclaration: false)) { leftOperand = null; @@ -6392,6 +6391,8 @@ private ExprSyntax ParseTermWithoutPostfix(Precedence precedence) return this.ParseAliasQualifiedName(NameOptions.InExpression); case SyntaxKind.MatchKeyword: return this.ParseMatch(); + case SyntaxKind.FnKeyword: + return this.ParseAnonymousFunction(); case SyntaxKind.IdentifierToken: if (this.IsTrueIdentifier()) { diff --git a/src/Aquila.CodeAnalysis/Parser/LanguageParser_Expr.cs b/src/Aquila.CodeAnalysis/Parser/LanguageParser_Expr.cs index 6b0a2caf2..2a3c47d91 100644 --- a/src/Aquila.CodeAnalysis/Parser/LanguageParser_Expr.cs +++ b/src/Aquila.CodeAnalysis/Parser/LanguageParser_Expr.cs @@ -55,7 +55,6 @@ private SeparatedSyntaxList ParseArms() return arms; } - private ExprSyntax ParseCastOrParenExpression() { Debug.Assert(this.CurrentToken.Kind == SyntaxKind.OpenParenToken); @@ -96,5 +95,20 @@ private ExprSyntax ParseCastOrParenExpression() this.Release(ref resetPoint); } } + + + private bool IsPossibleFunctionExpression() + => CurrentToken.Kind == SyntaxKind.FnKeyword + && this.PeekToken(1).Kind == SyntaxKind.OpenParenToken; + + private FuncEx ParseAnonymousFunction() + { + var fnToken = EatToken(SyntaxKind.FnKeyword); + + var parameterList = ParseParenthesizedParameterList(); + var returnType = ParseType(); + var body = ParseMethodOrAccessorBodyBlock(new SyntaxList(), false); + return _syntaxFactory.FuncEx(fnToken, parameterList, returnType, body, null, null); + } } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Syntax/Syntax.xml b/src/Aquila.CodeAnalysis/Syntax/Syntax.xml index 8f917148f..0d94dcf3d 100644 --- a/src/Aquila.CodeAnalysis/Syntax/Syntax.xml +++ b/src/Aquila.CodeAnalysis/Syntax/Syntax.xml @@ -43,11 +43,6 @@ - - - - - @@ -891,6 +886,34 @@ Creates a CastExpressionSyntax node. + + + + + + + + Gets the parameter list. + + + + + Gets the return type syntax. + + + + + + + + + Gets the optional semicolon token. + + + + + + diff --git a/src/Aquila.CodeAnalysis/Syntax/SyntaxFacts.cs b/src/Aquila.CodeAnalysis/Syntax/SyntaxFacts.cs index 92e82eb88..3449d5a71 100644 --- a/src/Aquila.CodeAnalysis/Syntax/SyntaxFacts.cs +++ b/src/Aquila.CodeAnalysis/Syntax/SyntaxFacts.cs @@ -136,7 +136,7 @@ internal static bool IsNestedFunction(SyntaxNode child) switch (child.Kind()) { case SyntaxKind.LocalFunctionStatement: - case SyntaxKind.AnonymousMethodExpression: + case SyntaxKind.AnonymousFunctionExpression: case SyntaxKind.SimpleLambdaExpression: case SyntaxKind.ParenthesizedLambdaExpression: return true; diff --git a/src/Aquila.CodeAnalysis/Syntax/SyntaxKind.cs b/src/Aquila.CodeAnalysis/Syntax/SyntaxKind.cs index 89940ccf6..62dcf50f6 100644 --- a/src/Aquila.CodeAnalysis/Syntax/SyntaxKind.cs +++ b/src/Aquila.CodeAnalysis/Syntax/SyntaxKind.cs @@ -795,7 +795,7 @@ public enum SyntaxKind : ushort Argument = 8638, NameColon = 8639, CastExpression = 8640, - AnonymousMethodExpression = 8641, + AnonymousFunctionExpression = 8641, SimpleLambdaExpression = 8642, ParenthesizedLambdaExpression = 8643, ObjectInitializerExpression = 8644, @@ -1099,7 +1099,6 @@ public enum SyntaxKind : ushort MatchExpression, MatchArm, UnionType, - AllocExpression, #region Html diff --git a/src/Aquila.Syntax.Test/SourceParserTest.cs b/src/Aquila.Syntax.Test/SourceParserTest.cs index f2a15411b..242d95711 100644 --- a/src/Aquila.Syntax.Test/SourceParserTest.cs +++ b/src/Aquila.Syntax.Test/SourceParserTest.cs @@ -402,7 +402,7 @@ fn main() [Fact] public void TryParse() { - ParseAndVerify(@" + ParseAndVerify(@" fn main() { try @@ -420,13 +420,25 @@ fn main() }"); } + [Fact] + public void AnonymousFunctionParse() + { + ParseAndVerify(@" +fn main() +{ + var simple = fn (i int) int { return i + 1; }; +} +"); + } + + private void ParseAndVerify(string code) { var tp = new TreePrinter(_output); var tree = AquilaSyntaxTree.ParseText(code); var parsedCode = tree.ToString(); tp.Visit(tree.GetRoot()); - + Assert.Empty(tree.GetDiagnostics()); Assert.Equal(code, parsedCode); } } From 1968b0a20fd5745412f5af6c098d4fc270c85d69 Mon Sep 17 00:00:00 2001 From: cm4ker Date: Tue, 24 Jan 2023 02:22:09 +0600 Subject: [PATCH 02/16] add lambda test expression --- .../Source/Web/SourceViewTypeSymbol.cs | 3 - .../Synthesized/SynthesizedDelegateSymbol.cs | 12 +- .../Synthesized/SynthesizedFinalizeSymbol.cs | 63 --------- .../SynthesizedInstanceTypeSymbol.cs | 122 ------------------ .../SynthesizedStaticTypeSymbol.cs | 122 ------------------ .../SynthesizedTraitMethodSymbol.cs | 43 ------ src/Aquila.Networking/MessageExtension.cs | 2 +- .../Instance/AqFilteredInstanceManager.cs | 4 +- .../Instance/AqInstanceManager.cs | 4 +- .../Instance/IAqInstanceManager.cs | 2 +- src/Aquila.Test.Tools/DatabaseFixture.cs | 8 +- tests/lambdas/lambda_declare_and_call.aq | 4 + tests/lambdas/lambda_declare_and_call.expect | 1 + 13 files changed, 23 insertions(+), 367 deletions(-) delete mode 100644 src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedFinalizeSymbol.cs delete mode 100644 src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedInstanceTypeSymbol.cs delete mode 100644 src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedStaticTypeSymbol.cs delete mode 100644 src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedTraitMethodSymbol.cs create mode 100644 tests/lambdas/lambda_declare_and_call.aq create mode 100644 tests/lambdas/lambda_declare_and_call.expect diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs index cbb9453c7..6e8f95c24 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs @@ -3,15 +3,12 @@ using System.Collections.Immutable; using System.IO; using System.Linq; -using System.Reflection.Metadata; using System.Threading; using Aquila.CodeAnalysis.CodeGen; using Aquila.CodeAnalysis.FlowAnalysis; using Aquila.CodeAnalysis.Semantics.Graph; using Aquila.CodeAnalysis.Symbols.Attributes; -using Aquila.CodeAnalysis.Symbols.Synthesized; using Aquila.CodeAnalysis.Syntax; -using Aquila.Querying; using Microsoft.CodeAnalysis; using Roslyn.Utilities; using TypeLayout = Microsoft.CodeAnalysis.TypeLayout; diff --git a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedDelegateSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedDelegateSymbol.cs index 5237623d2..3bd9b533d 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedDelegateSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedDelegateSymbol.cs @@ -55,10 +55,12 @@ public override ImmutableArray GetMembers() public override ImmutableArray GetMembers(string name) { - return - (name.StringsEqual(_constructor.Name, false)) ? ImmutableArray.Create(_constructor) : - (name.StringsEqual(_invoke.Name, false)) ? ImmutableArray.Create(_invoke) : - ImmutableArray.Empty; + if (name.StringsEqual(_constructor.Name, false)) + return ImmutableArray.Create(_constructor); + + return name.StringsEqual(_invoke.Name, false) + ? ImmutableArray.Create(_invoke) + : ImmutableArray.Empty; } public override Accessibility DeclaredAccessibility @@ -71,7 +73,7 @@ public override bool IsSealed get { return true; } } - public override NamedTypeSymbol BaseType // NoUseSiteDiagnostics + public override NamedTypeSymbol BaseType { get { return ContainingAssembly.GetSpecialType(SpecialType.System_MulticastDelegate); } } diff --git a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedFinalizeSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedFinalizeSymbol.cs deleted file mode 100644 index 703e3dcc0..000000000 --- a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedFinalizeSymbol.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections.Immutable; -using System.Diagnostics; -using System.Linq; -using Microsoft.CodeAnalysis; - -namespace Aquila.CodeAnalysis.Symbols.Synthesized -{ - #region SynthesizedDtorSymbol // generated Finalize method - - internal class SynthesizedFinalizeSymbol : SynthesizedMethodSymbol - { - public SynthesizedFinalizeSymbol(NamedTypeSymbol container) - : base(container, WellKnownMemberNames.DestructorName, false, true, - container.DeclaringCompilation.CoreTypes.Void, aquilahidden: true) - { - Debug.Assert(!container.IsStatic); - - SetOverride((MethodSymbol)container.DeclaringCompilation - .GetSpecialType(SpecialType.System_Object) - .GetMembers(WellKnownMemberNames.DestructorName) - .Single()); - } - - public override bool HidesBaseMethodsByName => false; - - internal override bool HasSpecialName => false; - - public override Accessibility DeclaredAccessibility => Accessibility.Protected; - - public sealed override bool IsAbstract => false; - - public sealed override bool IsExtern => false; - - public sealed override bool IsSealed => false; - - public sealed override MethodKind MethodKind => MethodKind.Destructor; - - internal override bool IsExplicitInterfaceImplementation => true; - - internal override ObsoleteAttributeData ObsoleteAttributeData => null; - - internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) => false; - - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) => true; - - internal override bool IsMetadataFinal => false; - - public override ImmutableArray DeclaringSyntaxReferences - { - get { throw new NotImplementedException(); } - } - - public override ImmutableArray Locations - { - get { throw new NotImplementedException(); } - } - - public override ImmutableArray Parameters => ImmutableArray.Empty; - } - - #endregion -} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedInstanceTypeSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedInstanceTypeSymbol.cs deleted file mode 100644 index 7e86312ad..000000000 --- a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedInstanceTypeSymbol.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading; -using Microsoft.CodeAnalysis; -using Roslyn.Utilities; - -namespace Aquila.CodeAnalysis.Symbols.Synthesized -{ - /// - /// Synthesized non-generic static class. - /// class { ... } - /// - class SynthesizedInstanceTypeSymbol : NamedTypeSymbol - { - readonly AquilaCompilation _compilation; - private NamedTypeSymbol _baseType; - readonly NamedTypeSymbol _containingType; - - ConcurrentBag _lazyMembers; - - public void AddMember(Symbol symbol) - { - if (_lazyMembers == null) - { - Interlocked.CompareExchange(ref _lazyMembers, new ConcurrentBag(), null); - } - - _lazyMembers.Add(symbol); - } - - public SynthesizedInstanceTypeSymbol(AquilaCompilation compilation, string name, - NamedTypeSymbol baseType = null, - NamedTypeSymbol containingType = null, Accessibility accessibility = Accessibility.Internal) - { - _compilation = compilation; - _baseType = baseType ?? _compilation.CoreTypes.Object; - ; - - _containingType = containingType; - - this.Name = name ?? throw new ArgumentNullException(nameof(name)); - this.DeclaredAccessibility = accessibility; - } - - public override int Arity => 0; - - internal override bool HasTypeArgumentsCustomModifiers => false; - - public override ImmutableArray GetTypeArgumentCustomModifiers(int ordinal) => - GetEmptyTypeArgumentCustomModifiers(ordinal); - - public override Symbol ContainingSymbol => (Symbol)_containingType ?? _compilation.SourceModule; - - internal override ModuleSymbol ContainingModule => _compilation.SourceModule; - - public override Accessibility DeclaredAccessibility { get; } - - public override ImmutableArray DeclaringSyntaxReferences - { - get { throw new NotImplementedException(); } - } - - public override bool IsAbstract => false; - - public override bool IsSealed => false; - - public override bool IsStatic => false; - - public override bool IsSerializable => false; - - public override string Name { get; } - - public override string NamespaceName => string.Empty; - - public override NamedTypeSymbol BaseType => _baseType; - - public override TypeKind TypeKind => TypeKind.Class; - - internal override bool IsInterface => false; - - internal override bool IsWindowsRuntimeImport => false; - - public override bool IsImplicitlyDeclared => true; - - public override bool IsImplicitClass => true; - - internal override TypeLayout Layout => default; - - internal override bool MangleName => false; - - internal override ObsoleteAttributeData ObsoleteAttributeData => null; - - internal override bool ShouldAddWinRTMembers => false; - - public override ImmutableArray GetMembers() => - _lazyMembers != null ? _lazyMembers.AsImmutable() : ImmutableArray.Empty; - - public override ImmutableArray GetMembers(string name) => _lazyMembers != null - ? _lazyMembers.Where(s => s.Name == name).AsImmutable() - : ImmutableArray.Empty; - - public override ImmutableArray GetTypeMembers() => ImmutableArray.Empty; - - public override ImmutableArray GetTypeMembers(string name) => - ImmutableArray.Empty; - - internal override ImmutableArray GetDeclaredInterfaces(ConsList basesBeingResolved) => - ImmutableArray.Empty; - - internal override IEnumerable GetFieldsToEmit() => _lazyMembers != null - ? _lazyMembers.OfType().AsImmutable() - : ImmutableArray.Empty; - - internal override ImmutableArray GetInterfacesToEmit() => - ImmutableArray.Empty; - - public override ImmutableArray StaticConstructors => ImmutableArray.Empty; - } -} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedStaticTypeSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedStaticTypeSymbol.cs deleted file mode 100644 index f7bdf63fe..000000000 --- a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedStaticTypeSymbol.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Threading; -using Microsoft.CodeAnalysis; -using Roslyn.Utilities; - -namespace Aquila.CodeAnalysis.Symbols.Synthesized -{ - /// - /// Synthesized non-generic static class. - /// class { ... } - /// - class SynthesizedStaticTypeSymbol : NamedTypeSymbol - { - readonly AquilaCompilation _compilation; - private NamedTypeSymbol _baseType; - readonly NamedTypeSymbol _containingType; - - ConcurrentBag _lazyMembers; - - public void AddMember(Symbol symbol) - { - if (_lazyMembers == null) - { - Interlocked.CompareExchange(ref _lazyMembers, new ConcurrentBag(), null); - } - - _lazyMembers.Add(symbol); - } - - public SynthesizedStaticTypeSymbol(AquilaCompilation compilation, string name, - NamedTypeSymbol containingType = null, Accessibility accessibility = Accessibility.Internal) - { - _compilation = compilation; - _baseType = _compilation.CoreTypes.Object; - ; - - _containingType = containingType; - - this.Name = name ?? throw new ArgumentNullException(nameof(name)); - this.DeclaredAccessibility = accessibility; - } - - public override int Arity => 0; - - internal override bool HasTypeArgumentsCustomModifiers => false; - - public override ImmutableArray GetTypeArgumentCustomModifiers(int ordinal) => - GetEmptyTypeArgumentCustomModifiers(ordinal); - - public override Symbol ContainingSymbol => (Symbol)_containingType ?? _compilation.SourceModule; - - internal override ModuleSymbol ContainingModule => _compilation.SourceModule; - - public override Accessibility DeclaredAccessibility { get; } - - public override ImmutableArray DeclaringSyntaxReferences - { - get { throw new NotImplementedException(); } - } - - public override bool IsAbstract => false; - - public override bool IsSealed => false; - - public override bool IsStatic => true; - - public override bool IsSerializable => false; - - public override string Name { get; } - - public override string NamespaceName => string.Empty; - - public override NamedTypeSymbol BaseType => _baseType; - - public override TypeKind TypeKind => TypeKind.Class; - - internal override bool IsInterface => false; - - internal override bool IsWindowsRuntimeImport => false; - - public override bool IsImplicitlyDeclared => true; - - public override bool IsImplicitClass => true; - - internal override TypeLayout Layout => default; - - internal override bool MangleName => false; - - internal override ObsoleteAttributeData ObsoleteAttributeData => null; - - internal override bool ShouldAddWinRTMembers => false; - - public override ImmutableArray GetMembers() => - _lazyMembers != null ? _lazyMembers.AsImmutable() : ImmutableArray.Empty; - - public override ImmutableArray GetMembers(string name) => _lazyMembers != null - ? _lazyMembers.Where(s => s.Name == name).AsImmutable() - : ImmutableArray.Empty; - - - public override ImmutableArray GetTypeMembers() => ImmutableArray.Empty; - - public override ImmutableArray GetTypeMembers(string name) => - ImmutableArray.Empty; - - internal override ImmutableArray GetDeclaredInterfaces(ConsList basesBeingResolved) => - ImmutableArray.Empty; - - internal override IEnumerable GetFieldsToEmit() => _lazyMembers != null - ? _lazyMembers.OfType().AsImmutable() - : ImmutableArray.Empty; - - internal override ImmutableArray GetInterfacesToEmit() => - ImmutableArray.Empty; - - public override ImmutableArray StaticConstructors => ImmutableArray.Empty; - } -} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedTraitMethodSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedTraitMethodSymbol.cs deleted file mode 100644 index e7beb4194..000000000 --- a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedTraitMethodSymbol.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; - -namespace Aquila.CodeAnalysis.Symbols.Synthesized -{ - /// - /// Synthesized method representing implementation of used trait method inside a containing class. - /// - sealed class SynthesizedTraitMethodSymbol : SynthesizedMethodSymbol - { - public SynthesizedTraitMethodSymbol(TypeSymbol containingType, string name, MethodSymbol traitmethod, - Accessibility accessibility, bool isfinal = true) - : base(containingType, name, traitmethod.IsStatic, !traitmethod.IsStatic, null, accessibility, isfinal) - { - _parameters = default; // as uninitialized - - this.ForwardedCall = traitmethod; - } - - public override ImmutableArray Parameters - { - get - { - if (!_parameters.IsDefault && _parameters.Length != ForwardedCall.Parameters.Length) - { - // parameters has changed during analysis, - // reset this as well - // IMPORTANT: we must not change it when emit started already - _parameters = default; - } - - if (_parameters.IsDefault) - { - ImmutableInterlocked.InterlockedInitialize(ref _parameters, - SynthesizedParameterSymbol.Create(this, ForwardedCall.Parameters)); - } - - // - return _parameters; - } - } - } -} \ No newline at end of file diff --git a/src/Aquila.Networking/MessageExtension.cs b/src/Aquila.Networking/MessageExtension.cs index 687d09a5d..f37bdd7c6 100644 --- a/src/Aquila.Networking/MessageExtension.cs +++ b/src/Aquila.Networking/MessageExtension.cs @@ -73,7 +73,7 @@ public static async Task UseEnvironment(this RequestEnvironment { try { - var env = manager.GetInstance(request.Name); + var env = manager.TryGetInstance(request.Name); useCallBack(env); return new ResponceEnvironmentUseNetworkMessage(request); } diff --git a/src/Aquila.Runtime/Infrastructure/Instance/AqFilteredInstanceManager.cs b/src/Aquila.Runtime/Infrastructure/Instance/AqFilteredInstanceManager.cs index e2f81575c..f4b215434 100644 --- a/src/Aquila.Runtime/Infrastructure/Instance/AqFilteredInstanceManager.cs +++ b/src/Aquila.Runtime/Infrastructure/Instance/AqFilteredInstanceManager.cs @@ -30,9 +30,9 @@ public void AddInstance(StartupConfig config) _manager.AddInstance(config); } - public AqInstance GetInstance(string name) + public AqInstance TryGetInstance(string name) { - var env = _manager.GetInstance(name); + var env = _manager.TryGetInstance(name); if (_filter(env)) return env; return null; diff --git a/src/Aquila.Runtime/Infrastructure/Instance/AqInstanceManager.cs b/src/Aquila.Runtime/Infrastructure/Instance/AqInstanceManager.cs index 3c53e3d1c..12f72f855 100644 --- a/src/Aquila.Runtime/Infrastructure/Instance/AqInstanceManager.cs +++ b/src/Aquila.Runtime/Infrastructure/Instance/AqInstanceManager.cs @@ -58,14 +58,14 @@ protected AqInstance CreatePlatformEnvironment(StartupConfig config) return null; } - public AqInstance GetInstance(string name) + public AqInstance TryGetInstance(string name) { return _instances.FirstOrDefault(m => m.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); } public bool TryGetInstance(string name, out AqInstance instance) { - instance = GetInstance(name); + instance = TryGetInstance(name); return instance != null; } diff --git a/src/Aquila.Runtime/Infrastructure/Instance/IAqInstanceManager.cs b/src/Aquila.Runtime/Infrastructure/Instance/IAqInstanceManager.cs index 0a95536e1..362615dd4 100644 --- a/src/Aquila.Runtime/Infrastructure/Instance/IAqInstanceManager.cs +++ b/src/Aquila.Runtime/Infrastructure/Instance/IAqInstanceManager.cs @@ -5,7 +5,7 @@ namespace Aquila.Core.Instance public interface IAqInstanceManager { void AddInstance(StartupConfig config); - AqInstance GetInstance(string name); + AqInstance TryGetInstance(string name); IEnumerable GetInstances(); } } \ No newline at end of file diff --git a/src/Aquila.Test.Tools/DatabaseFixture.cs b/src/Aquila.Test.Tools/DatabaseFixture.cs index 2764d5fb4..911403e45 100644 --- a/src/Aquila.Test.Tools/DatabaseFixture.cs +++ b/src/Aquila.Test.Tools/DatabaseFixture.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Threading.Tasks; using Aquila.Core; using Aquila.Core.Infrastructure.Settings; @@ -51,11 +52,12 @@ private void InitCore() config.Get().Instances.Add(new StartupConfig { ConnectionString = _container.ConnectionString, - DatabaseType = SqlDatabaseType.Postgres + DatabaseType = SqlDatabaseType.Postgres, + InstanceName = "Library" }); var manager = service.GetService(); - Instance = manager.GetInstance("Library"); + Instance = manager.TryGetInstance("Library") ?? throw new InvalidOperationException("Instance not found"); var drContext = Instance.DatabaseRuntimeContext; var dcContext = Instance.DataContextManager.GetContext(); diff --git a/tests/lambdas/lambda_declare_and_call.aq b/tests/lambdas/lambda_declare_and_call.aq new file mode 100644 index 000000000..4df02962f --- /dev/null +++ b/tests/lambdas/lambda_declare_and_call.aq @@ -0,0 +1,4 @@ +fn main() { + var lambda = fn() int { return 1 + 1; }; + print(lambda()); +} \ No newline at end of file diff --git a/tests/lambdas/lambda_declare_and_call.expect b/tests/lambdas/lambda_declare_and_call.expect new file mode 100644 index 000000000..2a11c14f4 --- /dev/null +++ b/tests/lambdas/lambda_declare_and_call.expect @@ -0,0 +1 @@ +2 \ No newline at end of file From 9a5206d0924ecf6affb78985d1793c3d04d50816 Mon Sep 17 00:00:00 2001 From: cm4ker Date: Wed, 25 Jan 2023 02:37:31 +0600 Subject: [PATCH 03/16] add SourceLambdaSymbol - container for lambda code --- .../Symbols/Source/SourceLambdaSymbol.cs | 41 ++++++++++++++++ .../Symbols/Source/SourceMethodSymbol.cs | 46 ++---------------- .../Symbols/Source/SourceMethodSymbolBase.cs | 47 ++++++++++++++++++- .../Source/Web/SourceViewTypeSymbol.cs | 33 +++++++++++-- 4 files changed, 120 insertions(+), 47 deletions(-) create mode 100644 src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs new file mode 100644 index 000000000..65bf3f2ad --- /dev/null +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using Aquila.CodeAnalysis.Semantics; +using Aquila.CodeAnalysis.Semantics.Graph; +using Aquila.CodeAnalysis.Syntax; +using Microsoft.CodeAnalysis; + +namespace Aquila.CodeAnalysis.Symbols; + +internal sealed class SourceLambdaSymbol : SourceMethodSymbolBase +{ + private readonly FuncEx _functionExpr; + + public SourceLambdaSymbol(NamedTypeSymbol type, FuncEx functionExpr) : base(type) + { + _functionExpr = functionExpr; + } + + public override Accessibility DeclaredAccessibility { get; } + + public override bool IsStatic => false; + + internal override ParameterListSyntax SyntaxSignature { get; } + + internal override TypeEx SyntaxReturnType => _functionExpr.ReturnType; + + internal override AquilaSyntaxNode Syntax => _functionExpr; + + internal override IEnumerable Statements => _functionExpr.Body?.Statements; + + public override ControlFlowGraph ControlFlowGraph { get; internal set; } + + protected override Binder GetMethodBinder() + { + return DeclaringCompilation.GetBinder(_functionExpr); + } + + public override void GetDiagnostics(DiagnosticBag diagnostic) + { + throw new System.NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbol.cs index 44ca83737..0b22a3a4e 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbol.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Threading; using Aquila.CodeAnalysis.FlowAnalysis; -using Aquila.CodeAnalysis.Semantics.Graph; +using Aquila.CodeAnalysis.Semantics; using Aquila.CodeAnalysis.Symbols.Attributes; using Aquila.CodeAnalysis.Symbols.Source; using Aquila.CodeAnalysis.Syntax; @@ -33,7 +33,7 @@ public SourceMethodSymbol(NamedTypeSymbol type, FuncDecl syntax): base(type) internal override AquilaSyntaxNode Syntax => _syntax; - internal override IList Statements => _syntax.Body?.Statements.ToList(); + internal override IEnumerable Statements => _syntax.Body?.Statements; public override void GetDiagnostics(DiagnosticBag diagnostic) { @@ -42,50 +42,14 @@ public override void GetDiagnostics(DiagnosticBag diagnostic) public override string Name => _syntax.Identifier.Text; - public override TypeSymbol ReturnType - { - get - { - if (SyntaxReturnType == null) - return DeclaringCompilation.GetSpecialType(SpecialType.System_Void); - - return DeclaringCompilation.GetBinder(_syntax).BindType(SyntaxReturnType); - } - } - public override bool IsStatic => ContainingSymbol is SourceModuleTypeSymbol || _syntax.GetModifiers().IsStatic(); - - /// - /// Lazily bound semantic block. - /// Entry point of analysis and emitting. - /// - public override ControlFlowGraph ControlFlowGraph - { - get - { - if (_cfg == null && this.Statements != null) // ~ Statements => non abstract method - { - // create initial flow state - var state = StateBinder.CreateInitialState(this); - - var binder = DeclaringCompilation.GetBinder(_syntax); - // build control flow graph - var cfg = new ControlFlowGraph(this.Statements, binder); - cfg.Start.FlowState = state; - - // - Interlocked.CompareExchange(ref _cfg, cfg, null); - } - - // - return _cfg; - } - internal set { _cfg = value; } + protected override Binder GetMethodBinder() + { + return DeclaringCompilation.GetBinder(_syntax); } - public override Accessibility DeclaredAccessibility { get diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbolBase.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbolBase.cs index b3cb4bb71..6a4f7d17f 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbolBase.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbolBase.cs @@ -60,7 +60,7 @@ public override IMethodSymbol OverriddenMethod internal abstract AquilaSyntaxNode Syntax { get; } - internal abstract IList Statements { get; } + internal abstract IEnumerable Statements { get; } public abstract void GetDiagnostics(DiagnosticBag diagnostic); @@ -371,6 +371,11 @@ public sealed override int ParameterCount } } + public override TypeSymbol ReturnType => + SyntaxReturnType == null + ? DeclaringCompilation.GetSpecialType(SpecialType.System_Void) + : GetMethodBinder().BindType(SyntaxReturnType); + public override bool ReturnsVoid => ReturnType.SpecialType == SpecialType.System_Void; /// @@ -383,6 +388,46 @@ public bool ReturnsNull public override RefKind RefKind => RefKind.None; + + /// + /// Lazily bound semantic block. + /// Entry point of analysis and emitting. + /// + public override ControlFlowGraph ControlFlowGraph + { + get + { + if (_cfg != null || this.Statements == null) + { + return _cfg; + } + + Interlocked.CompareExchange(ref _cfg, CreateControlFlowGraph(), null); + + return _cfg; + } + internal set { _cfg = value; } + } + + protected virtual Binder GetMethodBinder() + { + throw new NotImplementedException(); + } + + protected virtual ControlFlowGraph CreateControlFlowGraph() + { + var binder = GetMethodBinder(); + + var cfg = new ControlFlowGraph(this.Statements, binder) + { + Start = + { + FlowState = StateBinder.CreateInitialState(this) + } + }; + return cfg; + } + public override ImmutableArray GetReturnTypeAttributes() { if (!ReturnsNull) diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs index 6e8f95c24..0407bc766 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs @@ -6,6 +6,7 @@ using System.Threading; using Aquila.CodeAnalysis.CodeGen; using Aquila.CodeAnalysis.FlowAnalysis; +using Aquila.CodeAnalysis.Semantics; using Aquila.CodeAnalysis.Semantics.Graph; using Aquila.CodeAnalysis.Symbols.Attributes; using Aquila.CodeAnalysis.Syntax; @@ -171,7 +172,7 @@ public MethodTreeBuilderSymbol(NamedTypeSymbol type, HtmlDecl htmlDecl) : base(t SyntaxFactory.PredefinedTypeEx(SyntaxFactory.Token(SyntaxKind.VoidKeyword)); internal override AquilaSyntaxNode Syntax => _htmlDecl; - internal override IList Statements => new List(); + internal override IEnumerable Statements => new List(); public override string Name => _overridenMethod.Name; internal override ObsoleteAttributeData ObsoleteAttributeData => _overridenMethod.ObsoleteAttributeData; @@ -206,6 +207,28 @@ public override void GetDiagnostics(DiagnosticBag diagnostic) public override bool IsExtern => false; + protected override Binder GetMethodBinder() + { + return DeclaringCompilation.GetBinder(_htmlDecl.HtmlMarkup); + } + + protected override ControlFlowGraph CreateControlFlowGraph() + { + var markup = _htmlDecl.HtmlMarkup; + if (markup == null) return null; + + var cfg = new ControlFlowGraph(markup.HtmlNodes, GetMethodBinder()) + { + Start = + { + FlowState = StateBinder.CreateInitialState(this) + } + }; + + return cfg; + + } + /// public override ControlFlowGraph ControlFlowGraph { @@ -221,11 +244,11 @@ public override ControlFlowGraph ControlFlowGraph return null; } - var state = StateBinder.CreateInitialState(this); - var binder = DeclaringCompilation.GetBinder(_htmlDecl.HtmlMarkup); - var cfg = new ControlFlowGraph(this._htmlDecl.HtmlMarkup.HtmlNodes, binder); + + var binder = + var cfg = Interlocked.CompareExchange(ref _cfg, cfg, null); - cfg.Start.FlowState = state; + return _cfg; } internal set => _cfg = value; From 9280f993156e0c31223685951a396bbb6eea7821 Mon Sep 17 00:00:00 2001 From: cm4ker Date: Wed, 25 Jan 2023 17:56:45 +0600 Subject: [PATCH 04/16] remove unused code --- src/Aquila.Web/AquilaHandlerMiddleware.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/Aquila.Web/AquilaHandlerMiddleware.cs b/src/Aquila.Web/AquilaHandlerMiddleware.cs index 380f7de14..1129f1879 100644 --- a/src/Aquila.Web/AquilaHandlerMiddleware.cs +++ b/src/Aquila.Web/AquilaHandlerMiddleware.cs @@ -178,16 +178,8 @@ private Task InvokeDeploy(HttpContext context) return Task.CompletedTask; } - try - { - var zipStream = context.Request.Body; - instance.Deploy(zipStream); - } - catch (Exception ex) - { - //Do smth package is corrupted - throw; - } + var zipStream = context.Request.Body; + instance.Deploy(zipStream); return Task.CompletedTask; } From 292b5b4f98bce0cfb6d98b84ead17f1168ac6245 Mon Sep 17 00:00:00 2001 From: cm4ker Date: Thu, 26 Jan 2023 02:13:02 +0600 Subject: [PATCH 05/16] add to flow context Lambda symbol for the enqueue it on analysis step. --- .../Compilation/AquilaCompilation.Types.cs | 4 +- .../Compilation/AquilaCompilation.cs | 21 +- .../Compilation/SourceCompiler.cs | 44 +-- .../FlowAnalysis/ExpressionAnalysis.cs | 24 +- .../FlowAnalysis/FlowContext.cs | 177 +++------ .../FlowAnalysis/FlowState.cs | 26 +- .../FlowAnalysis/Graph/ControlFlowGraph.cs | 7 - .../FlowAnalysis/StateBinder.cs | 10 - .../FlowAnalysis/Worklist.cs | 26 +- .../Generated/Generated.BoundTree.xml.cs | 149 +++++--- .../Semantics/Binder/Binder.cs | 352 +++++------------- .../Semantics/Binder/ForeachBindInfo.cs | 18 + .../Semantics/Binder/GlobalBinder.cs | 22 ++ .../Semantics/Binder/InClrImportBinder.cs | 61 +++ .../Semantics/Binder/InContainerBinder.cs | 52 +++ .../Semantics/Binder/InMethodBinder.cs | 25 ++ .../Semantics/Binder/InModuleBinder.cs | 8 + .../Semantics/Graph/ControlFlowGraph.cs | 6 +- .../Semantics/Graph/GraphBuilder.cs | 40 +- .../Semantics/TypeRef/BoundTypeRef.cs | 2 +- .../Symbols/Source/SourceLambdaSymbol.cs | 10 +- .../Source/Web/SourceViewTypeSymbol.cs | 25 -- src/Aquila.SyntaxGenerator/BoundTree.xml | 19 +- 23 files changed, 521 insertions(+), 607 deletions(-) create mode 100644 src/Aquila.CodeAnalysis/Semantics/Binder/ForeachBindInfo.cs create mode 100644 src/Aquila.CodeAnalysis/Semantics/Binder/GlobalBinder.cs create mode 100644 src/Aquila.CodeAnalysis/Semantics/Binder/InClrImportBinder.cs create mode 100644 src/Aquila.CodeAnalysis/Semantics/Binder/InContainerBinder.cs create mode 100644 src/Aquila.CodeAnalysis/Semantics/Binder/InMethodBinder.cs create mode 100644 src/Aquila.CodeAnalysis/Semantics/Binder/InModuleBinder.cs diff --git a/src/Aquila.CodeAnalysis/Compilation/AquilaCompilation.Types.cs b/src/Aquila.CodeAnalysis/Compilation/AquilaCompilation.Types.cs index 564c8d1e6..323b2ab9c 100644 --- a/src/Aquila.CodeAnalysis/Compilation/AquilaCompilation.Types.cs +++ b/src/Aquila.CodeAnalysis/Compilation/AquilaCompilation.Types.cs @@ -72,14 +72,14 @@ partial class AquilaCompilation /// /// Gets global semantics. To be replaced once we implement SyntaxNode (). /// - internal GlobalSymbolProvider GlobalSemantics => _model ?? (_model = new GlobalSymbolProvider(this)); + internal GlobalSymbolProvider GlobalSemantics => _model ??= new GlobalSymbolProvider(this); /// /// Merges two CLR types into one /// /// First type. /// Second type. - /// One type convering both and types. + /// One type covering both and types. internal TypeSymbol Merge(TypeSymbol first, TypeSymbol second) { Contract.ThrowIfNull(first); diff --git a/src/Aquila.CodeAnalysis/Compilation/AquilaCompilation.cs b/src/Aquila.CodeAnalysis/Compilation/AquilaCompilation.cs index b7cea4444..b0a606941 100644 --- a/src/Aquila.CodeAnalysis/Compilation/AquilaCompilation.cs +++ b/src/Aquila.CodeAnalysis/Compilation/AquilaCompilation.cs @@ -900,21 +900,26 @@ internal override CommonReferenceManager CommonGetBoundReferenceManager() internal new ReferenceManager GetBoundReferenceManager() { - if (_lazyAssemblySymbol == null) + if (_lazyAssemblySymbol != null) + return _referenceManager; + + lock (_referenceManager) { - lock (_referenceManager) - { - _lazyAssemblySymbol = _referenceManager.CreateSourceAssemblyForCompilation(this); - } - - Debug.Assert(_lazyAssemblySymbol != null); + _lazyAssemblySymbol = _referenceManager.CreateSourceAssemblyForCompilation(this); } + Debug.Assert(_lazyAssemblySymbol != null); + // referenceManager can only be accessed after we initialized the lazyAssemblySymbol. // In fact, initialization of the assembly symbol might change the reference manager. return _referenceManager; } + internal void EnsureSourceAssembly() + { + this.GetBoundReferenceManager(); + } + internal override ISymbolInternal CommonGetWellKnownTypeMember(WellKnownMember member) { return GetWellKnownTypeMember(member); @@ -964,7 +969,7 @@ public async Task> BindAndAnalyseTask(CancellationToken { if (_lazyAnalysisTask == null) { - _lazyAnalysisTask = Task.Run(() => SourceCompiler.BindAndAnalyze(this, cancellationToken)); + _lazyAnalysisTask = Task.Run(() => SourceCompiler.BindAndAnalyze(this, cancellationToken), cancellationToken); } return await _lazyAnalysisTask.ConfigureAwait(false); diff --git a/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs b/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs index d6263b010..184e9e517 100644 --- a/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs +++ b/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs @@ -51,6 +51,8 @@ private SourceCompiler(AquilaCompilation compilation, PEModuleBuilder moduleBuil Contract.ThrowIfNull(diagnostics); _compilation = compilation; + _compilation.EnsureSourceAssembly(); + _moduleBuilder = moduleBuilder; _emittingPdb = emittingPdb; _diagnostics = diagnostics; @@ -126,9 +128,8 @@ void EnqueueMethod(SourceMethodSymbolBase method) // lazily binds CFG and // adds their entry block to the worklist - // TODO: reset LocalsTable, FlowContext and CFG - _worklist.Enqueue(method.ControlFlowGraph?.Start); + // enqueue method parameter default values method.SourceParameters.ForEach(p => @@ -168,16 +169,17 @@ internal void AnalyzeMethods() _worklist.DoAll(concurrent: ConcurrentBuild); } - void AnalyzeBlock(BoundBlock block) // TODO: driver + void AnalyzeBlock(BoundBlock block) { - // TODO: pool of CFGAnalysis - // TODO: async - // TODO: in parallel + block.Accept(AnalysisFactory()); - block.Accept(AnalysisFactory(block.FlowState)); + foreach (var lambda in block.FlowState.FlowContext.Lambdas) + { + EnqueueMethod(lambda); + } } - GraphVisitor AnalysisFactory(FlowState state) + GraphVisitor AnalysisFactory() { return new ExpressionAnalysis(_worklist, _compilation.GlobalSemantics); } @@ -354,16 +356,17 @@ bool MakeLoweringTransformMethods(bool allowParallel) } + private void InvalidateAndEnque(SourceMethodSymbolBase m) + { + m.ControlFlowGraph?.FlowContext?.InvalidateAnalysis(); + EnqueueMethod(m); + } + public void LoweringMethods() { if (MakeLoweringTransformMethods(ConcurrentBuild)) { - WalkSourceMethods(m => - { - m.ControlFlowGraph?.FlowContext?.InvalidateAnalysis(); - EnqueueMethod(m); - }, - allowParallel: true); + WalkSourceMethods(InvalidateAndEnque, allowParallel: true); } } @@ -373,12 +376,7 @@ bool RewriteMethods() { if (TransformMethods(ConcurrentBuild)) { - WalkSourceMethods(m => - { - m.ControlFlowGraph?.FlowContext?.InvalidateAnalysis(); - EnqueueMethod(m); - }, - allowParallel: true); + WalkSourceMethods(InvalidateAndEnque, allowParallel: true); } else { @@ -386,17 +384,13 @@ bool RewriteMethods() return false; } } - - // + return true; } public static IEnumerable BindAndAnalyze(AquilaCompilation compilation, CancellationToken cancellationToken) { - var manager = - compilation.GetBoundReferenceManager(); // ensure the references are resolved! (binds ReferenceManager) - var diagnostics = new DiagnosticBag(); var compiler = new SourceCompiler(compilation, null, true, diagnostics, cancellationToken); diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs index e2d6c2af3..86d53336a 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs @@ -105,7 +105,7 @@ public ExpressionAnalysis(Worklist worklist, ISymbolProvider model) protected override FlowState CloneState(FlowState state) => state.Clone(); protected override FlowState MergeStates(FlowState a, FlowState b) => a.Merge(b); - + protected override void EnqueueBlock(BoundBlock block) => Worklist.Enqueue(block); @@ -158,6 +158,7 @@ public override T VisitStaticVarStmt(BoundStaticVarStmt x) return default; } + #endregion #region Visit Literals @@ -227,7 +228,6 @@ protected virtual void VisitLocalVariableRef(BoundVariableRef x, VariableHandle var previoustype = State.GetLocalType(local); // type of the variable in the previous state - // bind variable place if (x.Variable == null) { @@ -253,9 +253,6 @@ public override T VisitVariableRef(BoundVariableRef x) VisitLocalVariableRef(x, State.GetLocalHandle(x.Name.NameValue)); } } - else - { - } return default; } @@ -572,6 +569,7 @@ public override T VisitConversionEx(BoundConversionEx x) break; } } + return default; } @@ -591,8 +589,6 @@ public override T VisitTypeRef(BoundTypeRef tref) #endregion - #region Visit Function Call - public override T VisitCallEx(BoundCallEx arg) { if (arg.Instance != null) @@ -603,7 +599,11 @@ public override T VisitCallEx(BoundCallEx arg) return base.VisitCallEx(arg); } - #endregion + public override T VisitFuncEx(BoundFuncEx x) + { + State.VisitFuncEx(x); + return default; + } #region Visit FieldRef @@ -643,10 +643,6 @@ public override T VisitArrayItemOrdEx(BoundArrayItemOrdEx x) #endregion - #region VisitLambda - - #endregion - #region VisitYield public override T VisitYieldStmt(BoundYieldStmt x) @@ -702,14 +698,10 @@ public override T VisitReturnStmt(BoundReturnStmt x) { Accept(x.Returned); } - else - { - } return default; } - #endregion } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/FlowContext.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/FlowContext.cs index 5a15cd5ce..6cb04ca6c 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/FlowContext.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/FlowContext.cs @@ -1,8 +1,8 @@ using Aquila.CodeAnalysis.Symbols; using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; -using System.Linq; using Aquila.CodeAnalysis.Semantics; using Aquila.Compiler.Utilities; @@ -32,85 +32,57 @@ public TypeRefInfo(TypeSymbol symbol) internal void SetByRef(bool value) => _byReference = value; } - #region Constants + private int _version; + private readonly SourceMethodSymbolBase _method; + private TypeRefInfo[] _varsType = Array.Empty(); + private List _lambdas = new List(); - /// - /// Size of ulong bit array (64). - /// - internal const int BitsCount = sizeof(ulong) * 8; - - #endregion - #region Fields & Properties + internal FlowContext(SourceMethodSymbolBase method) + { + _method = method; + _varsIndex = new Dictionary(); + } /// - /// Associated type context. + /// Size of ulong bit array (64). /// - public TypeRefContext TypeRefContext => _typeCtx; - - readonly TypeRefContext - _typeCtx; + internal const int BitsCount = sizeof(ulong) * 8; /// /// Reference to corresponding method symbol. Can be a null reference. /// internal SourceMethodSymbolBase Method => _method; - readonly SourceMethodSymbolBase _method; - /// /// Map of variables name and their index. /// - readonly Dictionary - _varsIndex; - - /// - /// Bit mask of variables where bit with value 1 signalizes that variables with index corresponding to the bit number has been used. - /// - ulong _usedMask; + readonly Dictionary _varsIndex; /// /// Merged local variables type. /// internal TypeRefInfo[] VarsType => _varsType; - TypeRefInfo[] - _varsType = Array.Empty(); - /// - /// Merged return expressions type. - /// - internal TypeRefInfo ReturnType - { - get { return _returnType; } - set { _returnType = value; } - } - - TypeRefInfo _returnType; + internal ImmutableArray Lambdas => _lambdas.ToImmutableArray(); /// /// Version of the analysis, incremented whenever a set of semantic tree transformations happen. /// internal int Version => _version; - int _version; - - #endregion - - #region Construction - - internal FlowContext(SourceMethodSymbolBase method) + internal void AddVarType(int varIndex, TypeSymbol type) { - _method = method; - - // - _varsIndex = new Dictionary(); + if (varIndex >= 0 && varIndex < _varsType.Length) + { + _varsType[varIndex] = new TypeRefInfo(type); + } } - #endregion - - #region Public Methods - + internal void AddLambda(SourceLambdaSymbol lambda) + => _lambdas.Add(lambda); + /// /// Gets index of variable within the context. /// @@ -118,93 +90,37 @@ public VariableHandle GetVarIndex(VariableName name) { Debug.Assert(name.IsValid(), $"Invalid variable name '{name.Value}' in method '{_method.Name}'"); - // TODO: RW lock - - int index; - if (!_varsIndex.TryGetValue(name, out index)) + if (_varsIndex.TryGetValue(name, out var index)) + return new VariableHandle() { Slot = index, Name = name }; + + lock (_varsIndex) { - lock (_varsIndex) - { - index = _varsType.Length; - Array.Resize(ref _varsType, index + 1); - - // - _varsIndex[name] = index; - } + index = _varsType.Length; + Array.Resize(ref _varsType, index + 1); + + _varsIndex[name] = index; } - // return new VariableHandle() { Slot = index, Name = name }; } - /// - /// Enumerates all known variables as pairs of their index and name. - /// - public IEnumerable EnumerateVariables() + public void SetReference(int varIndex) { - return _varsIndex.Select(pair => new VariableHandle() + if (varIndex >= 0 && varIndex < _varsType.Length) { - Slot = pair.Value, - Name = pair.Key, - }); - } - - public void SetReference(int varindex) - { - if (varindex >= 0 && varindex < _varsType.Length) - { - _varsType[varindex].SetByRef(true); + _varsType[varIndex].SetByRef(true); } } /// /// Gets value indicating whether given variable might be a reference. /// - public bool IsReference(int varindex) + public bool IsReference(int varIndex) { // anything >= 64 is reported as a possible reference - return varindex < 0 || varindex >= _varsType.Length || _varsType[varindex].ByRef; - } - - internal void AddVarType(int varindex, TypeSymbol type) - { - if (varindex >= 0 && varindex < _varsType.Length) - { - _varsType[varindex] = new TypeRefInfo(type); - } + return varIndex < 0 || varIndex >= _varsType.Length || _varsType[varIndex].ByRef; } - - internal TypeRefInfo GetVarType(VariableName name) - { - var idx = GetVarIndex(name); - return _varsType[idx]; - } - - /// - /// Sets specified variable as being used. - /// - public void SetUsed(int varindex) - { - if (varindex >= 0 && varindex < BitsCount) - { - _usedMask |= (ulong)1 << varindex; - } - } - - /// - /// Marks all local variables as used. - /// - public void SetAllUsed() - { - _usedMask = ~(ulong)0; - } - - public bool IsUsed(int varindex) - { - // anything >= 64 is used - return varindex < 0 || varindex >= BitsCount || (_usedMask & (ulong)1 << varindex) != 0; - } - + /// /// Discard the current flow analysis information, should be called whenever the method is transformed. /// @@ -220,24 +136,17 @@ public void InvalidateAnalysis() _version++; // Reset internal structures to prevent possible bugs in re-analysis - _usedMask = 0; _varsIndex.Clear(); _varsType = Array.Empty(); + _lambdas = new List(); - // Revert the information regarding the return type to the default state - ReturnType = default; + if (_method == null) return; + + // Reset method properties related to the analysis + _method.IsReturnAnalysed = false; - // TODO: Recreate the state also in the case of a standalone expression (such as a parameter initializer) - if (_method != null) - { - // Reset method properties related to the analysis - _method.IsReturnAnalysed = false; - - // Recreate the entry state to enable another analysis - _method.ControlFlowGraph.Start.FlowState = StateBinder.CreateInitialState(_method, this); - } + // Recreate the entry state to enable another analysis + _method.ControlFlowGraph.Start.FlowState = StateBinder.CreateInitialState(_method, this); } - - #endregion } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/FlowState.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/FlowState.cs index 66ed1adaf..73a069339 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/FlowState.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/FlowState.cs @@ -202,33 +202,17 @@ public void SetLocalType(VariableHandle handle, TypeSymbol tmask) } /// - /// Sets variable type with byref flag in this state. - /// - /// Variable handle. - public void SetLocalRef(VariableHandle handle) - { - SetLocalType(handle, GetLocalType(handle)); - } - - /// - /// Marks variable as being referenced. + /// Handles use of a local variable. /// - public void MarkLocalByRef(VariableHandle handle) + public void VisitLocal(VariableHandle handle) { handle.ThrowIfInvalid(); - - this.FlowContext.SetReference(handle); - this.FlowContext.SetUsed(handle); - this.SetVarInitialized(handle); } - /// - /// Handles use of a local variable. - /// - public void VisitLocal(VariableHandle handle) + + public void VisitFuncEx(BoundFuncEx func) { - handle.ThrowIfInvalid(); - FlowContext.SetUsed(handle); + this.FlowContext.AddLambda(func.LambdaSymbol); } /// diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/Graph/ControlFlowGraph.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/Graph/ControlFlowGraph.cs index 623f2328e..602c7dd0c 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/Graph/ControlFlowGraph.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/Graph/ControlFlowGraph.cs @@ -11,12 +11,5 @@ partial class ControlFlowGraph /// /// CFG has to be analysed prior to getting this property. public FlowContext FlowContext => this.Start.FlowState?.FlowContext; - - /// - /// Gets possible types of a local variable. - /// - /// CFG has to be analysed prior to getting this property. - internal FlowContext.TypeRefInfo GetLocalType(string varname) => - this.FlowContext?.GetVarType(new VariableName(varname)); } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/StateBinder.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/StateBinder.cs index 65c3f6189..fdaf6368e 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/StateBinder.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/StateBinder.cs @@ -36,15 +36,5 @@ public static FlowState CreateInitialState(SourceMethodSymbolBase method, FlowCo // return state; } - - /// - /// Initializes $this variable, its type and initialized state. - /// - private static void InitThisVar(FlowContext ctx, FlowState initialState) - { - var thisHandle = ctx.GetVarIndex(VariableName.ThisVariableName); - initialState.SetLocalType(thisHandle, null); // set $this type - initialState.VisitLocal(thisHandle); // mark as visited (used) to not report as unused - } } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/Worklist.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/Worklist.cs index b94f5e7ca..454c4792f 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/Worklist.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/Worklist.cs @@ -144,12 +144,11 @@ public void DoAll(bool concurrent = false) { // Store the current batch and its count var todoBlocks = new T[256]; - int n; // Deque a batch of blocks and analyse them in parallel while (true) { - n = Dequeue(todoBlocks); + var n = Dequeue(todoBlocks); if (n == 0) { @@ -157,13 +156,10 @@ public void DoAll(bool concurrent = false) { break; } - else - { - // Process also the call blocks that weren't analysed due to circular dependencies - // TODO: Consider using something more advanced such as cycle detection - _dirtyCallBlocks.ForEach(kvp => Enqueue(kvp.Key)); - continue; - } + + // Process also the call blocks that weren't analysed due to circular dependencies + _dirtyCallBlocks.ForEach(kvp => Enqueue(kvp.Key)); + continue; } if (concurrent) @@ -229,7 +225,6 @@ int Dequeue(T[] todoBlocks) // from each method, delaying the rest int n = 0; while (n < todoBlocks.Length && _queue.TryDequeue(out T block)) - //TODO: TryDequeue() with a predicate so we won't have to maintain {delayedBlocks} { var typeCtx = block.FlowState?.Method.ContainingType; @@ -247,14 +242,13 @@ int Dequeue(T[] todoBlocks) delayedBlocks.Add(block); } } - + + if (delayedBlocks == null) return n; + // Return the delayed blocks back to the queue to be deenqueued the next time - if (delayedBlocks != null) + foreach (var block in delayedBlocks) { - foreach (var block in delayedBlocks) - { - _queue.Enqueue(block); - } + _queue.Enqueue(block); } return n; diff --git a/src/Aquila.CodeAnalysis/Generated/Generated.BoundTree.xml.cs b/src/Aquila.CodeAnalysis/Generated/Generated.BoundTree.xml.cs index b71886785..eaf1edad9 100644 --- a/src/Aquila.CodeAnalysis/Generated/Generated.BoundTree.xml.cs +++ b/src/Aquila.CodeAnalysis/Generated/Generated.BoundTree.xml.cs @@ -15,12 +15,12 @@ public enum BoundKind Block, DeclareStmt, ExpressionStmt, - MethodDeclStmt, GlobalConstDeclStmt, ReturnStmt, StaticVarStmt, YieldStmt, ForEachStmt, + BadStmt, HtmlMarkupStmt, HtmlOpenElementStmt, HtmlCloseElementStmt, @@ -38,6 +38,7 @@ public enum BoundKind MatchEx, MatchArm, BadEx, + FuncEx, CallEx, NewEx, ThrowEx, @@ -289,56 +290,6 @@ public BoundExpressionStmt Update(BoundExpression expression) } } -namespace Aquila.CodeAnalysis.Semantics -{ - partial class BoundMethodDeclStmt : BoundStatement - { - private SourceMethodSymbolBase _method; - internal BoundMethodDeclStmt(SourceMethodSymbolBase method) - { - _method = method; - OnCreateImpl(method); - } - - partial void OnCreateImpl(SourceMethodSymbolBase method); - internal SourceMethodSymbolBase Method - { - get - { - return _method; - } - } - - public override OperationKind Kind => OperationKind.LocalFunction; - public override BoundKind BoundKind => BoundKind.MethodDeclStmt; - partial void AcceptImpl(OperationVisitor visitor, TArg argument, ref TRes result); - partial void AcceptImpl(OperationVisitor visitor); - public override TRes Accept(OperationVisitor visitor, TArg argument) - { - TRes res = default; - AcceptImpl(visitor, argument, ref res); - return res; - } - - public override void Accept(OperationVisitor visitor) - { - AcceptImpl(visitor); - } - - public override TResult Accept(AquilaOperationVisitor visitor) - { - return visitor.VisitMethodDeclStmt(this); - } - - internal BoundMethodDeclStmt Update(SourceMethodSymbolBase method) - { - if (_method == method) - return this; - return new BoundMethodDeclStmt(method).WithSyntax(this.AquilaSyntax); - } - } -} - namespace Aquila.CodeAnalysis.Semantics { partial class BoundGlobalConstDeclStmt : BoundStatement @@ -584,6 +535,39 @@ public BoundForEachStmt Update(BoundReferenceEx item, BoundExpression collection } } +namespace Aquila.CodeAnalysis.Semantics +{ + partial class BoundBadStmt : BoundStatement + { + public BoundBadStmt() + { + OnCreateImpl(); + } + + partial void OnCreateImpl(); + public override OperationKind Kind => OperationKind.None; + public override BoundKind BoundKind => BoundKind.BadStmt; + partial void AcceptImpl(OperationVisitor visitor, TArg argument, ref TRes result); + partial void AcceptImpl(OperationVisitor visitor); + public override TRes Accept(OperationVisitor visitor, TArg argument) + { + TRes res = default; + AcceptImpl(visitor, argument, ref res); + return res; + } + + public override void Accept(OperationVisitor visitor) + { + AcceptImpl(visitor); + } + + public override TResult Accept(AquilaOperationVisitor visitor) + { + return visitor.VisitBadStmt(this); + } + } +} + namespace Aquila.CodeAnalysis.Semantics { partial class BoundHtmlMarkupStmt : BoundStatement @@ -1583,6 +1567,66 @@ internal BoundBadEx Update(ITypeSymbol resultType) } } +namespace Aquila.CodeAnalysis.Semantics +{ + partial class BoundFuncEx : BoundExpression + { + private TypeSymbol _holderSymbol; + private SourceLambdaSymbol _lambdaSymbol; + internal BoundFuncEx(TypeSymbol holderSymbol, SourceLambdaSymbol lambdaSymbol, ITypeSymbol resultType): base(resultType) + { + _holderSymbol = holderSymbol; + _lambdaSymbol = lambdaSymbol; + OnCreateImpl(holderSymbol, lambdaSymbol, resultType); + } + + partial void OnCreateImpl(TypeSymbol holderSymbol, SourceLambdaSymbol lambdaSymbol, ITypeSymbol resultType); + internal TypeSymbol HolderSymbol + { + get + { + return _holderSymbol; + } + } + + internal SourceLambdaSymbol LambdaSymbol + { + get + { + return _lambdaSymbol; + } + } + + public override OperationKind Kind => OperationKind.AnonymousFunction; + public override BoundKind BoundKind => BoundKind.FuncEx; + partial void AcceptImpl(OperationVisitor visitor, TArg argument, ref TRes result); + partial void AcceptImpl(OperationVisitor visitor); + public override TRes Accept(OperationVisitor visitor, TArg argument) + { + TRes res = default; + AcceptImpl(visitor, argument, ref res); + return res; + } + + public override void Accept(OperationVisitor visitor) + { + AcceptImpl(visitor); + } + + public override TResult Accept(AquilaOperationVisitor visitor) + { + return visitor.VisitFuncEx(this); + } + + internal BoundFuncEx Update(TypeSymbol holderSymbol, SourceLambdaSymbol lambdaSymbol, ITypeSymbol resultType) + { + if (_holderSymbol == holderSymbol && _lambdaSymbol == lambdaSymbol && ResultType == resultType) + return this; + return new BoundFuncEx(holderSymbol, lambdaSymbol, resultType).WithSyntax(this.AquilaSyntax); + } + } +} + namespace Aquila.CodeAnalysis.Semantics { partial class BoundCallEx : BoundExpression @@ -3027,12 +3071,12 @@ abstract partial class AquilaOperationVisitor public virtual TResult VisitBlock(BoundBlock x) => VisitDefault(x); public virtual TResult VisitDeclareStmt(BoundDeclareStmt x) => VisitDefault(x); public virtual TResult VisitExpressionStmt(BoundExpressionStmt x) => VisitDefault(x); - public virtual TResult VisitMethodDeclStmt(BoundMethodDeclStmt x) => VisitDefault(x); public virtual TResult VisitGlobalConstDeclStmt(BoundGlobalConstDeclStmt x) => VisitDefault(x); public virtual TResult VisitReturnStmt(BoundReturnStmt x) => VisitDefault(x); public virtual TResult VisitStaticVarStmt(BoundStaticVarStmt x) => VisitDefault(x); public virtual TResult VisitYieldStmt(BoundYieldStmt x) => VisitDefault(x); public virtual TResult VisitForEachStmt(BoundForEachStmt x) => VisitDefault(x); + public virtual TResult VisitBadStmt(BoundBadStmt x) => VisitDefault(x); public virtual TResult VisitHtmlMarkupStmt(BoundHtmlMarkupStmt x) => VisitDefault(x); public virtual TResult VisitHtmlOpenElementStmt(BoundHtmlOpenElementStmt x) => VisitDefault(x); public virtual TResult VisitHtmlCloseElementStmt(BoundHtmlCloseElementStmt x) => VisitDefault(x); @@ -3051,6 +3095,7 @@ abstract partial class AquilaOperationVisitor public virtual TResult VisitMatchEx(BoundMatchEx x) => VisitDefault(x); public virtual TResult VisitMatchArm(BoundMatchArm x) => VisitDefault(x); public virtual TResult VisitBadEx(BoundBadEx x) => VisitDefault(x); + public virtual TResult VisitFuncEx(BoundFuncEx x) => VisitDefault(x); public virtual TResult VisitCallEx(BoundCallEx x) => VisitDefault(x); public virtual TResult VisitNewEx(BoundNewEx x) => VisitDefault(x); public virtual TResult VisitThrowEx(BoundThrowEx x) => VisitDefault(x); diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs index 6255194f5..576c4a2ac 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs @@ -8,6 +8,7 @@ using Aquila.CodeAnalysis.FlowAnalysis; using Aquila.CodeAnalysis.Semantics.TypeRef; using Aquila.CodeAnalysis.Symbols; +using Aquila.CodeAnalysis.Symbols.Synthesized; using Aquila.CodeAnalysis.Syntax; using Aquila.CodeAnalysis.Utilities; using Aquila.Syntax.Ast; @@ -18,164 +19,6 @@ namespace Aquila.CodeAnalysis.Semantics { - public struct ForeachBindInfo - { - public IPropertySymbol CurrentMember; - public IMethodSymbol MoveNextMember; - public ITypeSymbol EnumeratorSymbol; - public IMethodSymbol GetEnumerator; - public IMethodSymbol DisposeMember; - - public BoundReferenceEx EnumeratorVar; - public BoundReferenceEx CurrentVar; - public BoundCallEx MoveNextEx; - public BoundAssignEx EnumeratorAssignmentEx; - public BoundCallEx DisposeCall; - } - - internal class InClrImportBinder : Binder - { - private readonly INamespaceOrTypeSymbol _container; - - public InClrImportBinder(INamespaceOrTypeSymbol container, Binder next) : base(next) - { - _container = container; - } - - protected override ITypeSymbol FindTypeByName(NameEx tref) - { - var qName = tref.GetUnqualifiedName().Identifier.Text; - - var typeMembers = Container.GetTypeMembers(qName, -1); - - if (typeMembers.Length == 1) - return typeMembers[0]; - - if (typeMembers.Length == 0) - { - return Next.BindType(tref); - } - - if (typeMembers.Length > 1) - { - Diagnostics.Add(GetLocation(tref), ErrorCode.WRN_UndefinedType, - $"Expression of type '{tref.GetType().Name}'"); - } - - return null; - } - - protected override void FindMethodsByName(string name, ArrayBuilder result) - { - var typesCandidate = _container.GetTypeMembers().Where(x => name.StartsWith(x.Name.ToSnakeCase())); - - foreach (var type in typesCandidate) - { - var typeSnake = type.Name.ToSnakeCase(); - - var resolvedMethods = type.GetMembers().Where(x => - x.DeclaredAccessibility == Accessibility.Public && x.IsStatic && - typeSnake + "_" + x.Name.ToSnakeCase() == name) - .OfType(); - - result.AddRange(resolvedMethods); - } - - base.FindMethodsByName(name, result); - } - } - - internal class InContainerBinder : Binder - { - private readonly INamespaceOrTypeSymbol _container; - - public InContainerBinder(INamespaceOrTypeSymbol container, Binder next) : base(next) - { - _container = container; - } - - public override NamespaceOrTypeSymbol Container => (NamespaceOrTypeSymbol)_container; - - - protected override ITypeSymbol FindTypeByName(NameEx tref) - { - TypeSymbol result = null; - - var qName = tref.GetUnqualifiedName().Identifier.Text; - - var typeMembers = Container.GetTypeMembers(qName, -1); - - if (typeMembers.Length == 1) - result = typeMembers[0]; - - if (typeMembers.Length == 0) - { - result = Next?.BindType(tref); - } - - if (typeMembers.Length > 1) - { - Diagnostics.Add(GetLocation(tref), ErrorCode.WRN_UndefinedType, - $"Expression of type '{tref.GetType().Name}'"); - } - - if (result == null) - { - result = new MissingMetadataTypeSymbol(qName, 0, true); - } - - if (result.IsErrorType()) - Diagnostics.Add(GetLocation(tref), ErrorCode.ERR_TypeNameCannotBeResolved, qName); - - return result; - } - } - - internal class InModuleBinder : Binder - { - public InModuleBinder(Binder next) : base(next) - { - } - } - - internal class InMethodBinder : Binder - { - private readonly SourceMethodSymbolBase _method; - - public InMethodBinder(MethodSymbol method, Binder next) : base(next) - { - if(method is null) - throw new ArgumentNullException(nameof(method)); - - if (method is not SourceMethodSymbolBase m) - throw new ArgumentException($@"The method must be {nameof(SourceMethodSymbolBase)} type", nameof(method)); - - _method = m; - } - - public override SourceMethodSymbolBase Method => _method; - - - public override NamespaceOrTypeSymbol Container => _method.ContainingType; - } - - internal class GlobalBinder : InContainerBinder - { - private readonly NamespaceOrTypeSymbol _ns; - - public GlobalBinder(INamespaceOrTypeSymbol ns, Binder next) : base(ns, next) - { - _ns = (NamespaceOrTypeSymbol)ns; - } - - public override NamespaceOrTypeSymbol Container => _ns; - - protected override void FindMethodsByName(string name, ArrayBuilder result) - { - result.AddRange(_ns.GetMembers(name).OfType()); - } - } - internal abstract class Binder { private int _tmpVariableIndex = 0; @@ -259,32 +102,24 @@ private BoundStatement BindTryStmt(TryStmt tryStmt) internal BoundStatement BindVarDecl(VariableDecl varDecl) { - var decl1 = varDecl; - - foreach (var decl in decl1.Variables) + Debug.Assert(varDecl.Variables.Count == 1); + + var decl = varDecl.Variables.First(); + + if (string.IsNullOrWhiteSpace(decl.Identifier.Text) || decl.Initializer == null) { - if (string.IsNullOrWhiteSpace(decl.Identifier.Text) || decl.Initializer == null) - { - Diagnostics.Add(GetLocation(varDecl), ErrorCode.ERR_MissingIdentifierSymbol); - return new BoundExpressionStmt( - new BoundBadEx(this.Compilation.GetSpecialType(SpecialType.System_Void))); - } - - var localVar = Method.LocalsTable.BindLocalVariable(new VariableName(decl.Identifier.Text), decl); - - var boundExpression = BindExpression(decl.Initializer.Value); + Diagnostics.Add(GetLocation(varDecl), ErrorCode.ERR_MissingIdentifierSymbol); + return new BoundExpressionStmt( + new BoundBadEx(this.Compilation.GetSpecialType(SpecialType.System_Void))); + } - return new BoundExpressionStmt(new BoundAssignEx( - new BoundVariableRef(decl.Identifier.Text, localVar.Type).WithAccess(BoundAccess.Write), - boundExpression, localVar.Type)); - break; + var localVar = Method.LocalsTable.BindLocalVariable(new VariableName(decl.Identifier.Text), decl); - //TODO: - //For not we support only one declarator. Need introduce Statements set for statements or change - //Result for IEnumerable - } + var boundExpression = BindExpression(decl.Initializer.Value); - throw new Exception(); + return new BoundExpressionStmt(new BoundAssignEx( + new BoundVariableRef(decl.Identifier.Text, localVar.Type).WithAccess(BoundAccess.Write), + boundExpression, localVar.Type)); } private BoundStatement BindVarDeclStmt(LocalDeclStmt varDecl) @@ -303,6 +138,9 @@ private BoundVariableRef BindVariable(IVariableReference localVar) return new BoundVariableRef(new BoundVariableName(localVar.Symbol.Name, localVar.Type), localVar.Type); } + private static BoundStatement BoundStatementError() + => new BoundBadStmt(); + private BoundStatement BindForeachStmt(ForEachStmt stmt) { var collection = BindExpression(stmt.Expression, BoundAccess.Read); @@ -310,62 +148,53 @@ private BoundStatement BindForeachStmt(ForEachStmt stmt) var getEnumMethod = colType.LookupMember(WellKnownMemberNames.GetEnumeratorMethodName); - if (getEnumMethod != null) - { - var enumeratorSymbol = getEnumMethod.ReturnType; - var currentMember = - enumeratorSymbol.LookupMember(WellKnownMemberNames.CurrentPropertyName); - var moveNextMember = enumeratorSymbol.LookupMember( - WellKnownMemberNames.MoveNextMethodName, m => !m.IsStatic && m.ParameterCount == 0); - var disposeMember = enumeratorSymbol.LookupMember(WellKnownMemberNames.DisposeMethodName, + if (getEnumMethod == null) + return BoundStatementError(); + + var enumeratorSymbol = getEnumMethod.ReturnType; + var currentMember = enumeratorSymbol + .LookupMember(WellKnownMemberNames.CurrentPropertyName); + var moveNextMember = + enumeratorSymbol.LookupMember(WellKnownMemberNames.MoveNextMethodName, m => !m.IsStatic && m.ParameterCount == 0); + var disposeMember = enumeratorSymbol.LookupMember(WellKnownMemberNames.DisposeMethodName, + m => !m.IsStatic && m.ParameterCount == 0); - if (currentMember != null && moveNextMember != null) - { - var variableType = currentMember.Type; + if (currentMember == null || moveNextMember == null) + return BoundStatementError(); + + var variableType = currentMember.Type; - var localVar = Method.LocalsTable.BindLocalVariable(new VariableName(stmt.Identifier.Text), - stmt.Identifier.Span, variableType); + var localVar = Method.LocalsTable.BindLocalVariable(new VariableName(stmt.Identifier.Text), + stmt.Identifier.Span, variableType); - var assign = CreateTmpAndAssign(enumeratorSymbol, - new BoundCallEx(getEnumMethod, ImmutableArray.Empty, - ImmutableArray.Empty, collection, enumeratorSymbol - ).WithAccess(BoundAccess.Read)); + var assign = CreateTmpAndAssign(enumeratorSymbol, + new BoundCallEx(getEnumMethod, ImmutableArray.Empty, + ImmutableArray.Empty, collection, enumeratorSymbol + ).WithAccess(BoundAccess.Read)); - //enumerator.MoveNext() expr - var moveNextCondition = new BoundCallEx(moveNextMember, - ImmutableArray.Empty, - ImmutableArray.Empty, assign.Target, moveNextMember.ReturnType); + //enumerator.MoveNext() expr + var moveNextCondition = new BoundCallEx(moveNextMember, + ImmutableArray.Empty, + ImmutableArray.Empty, assign.Target, moveNextMember.ReturnType); - var callDispose = new BoundCallEx(disposeMember, ImmutableArray.Empty, - ImmutableArray.Empty, assign.Target, Compilation.CoreTypes.Void.Symbol); + var callDispose = new BoundCallEx(disposeMember, ImmutableArray.Empty, + ImmutableArray.Empty, assign.Target, Compilation.CoreTypes.Void.Symbol); - var bindInfo = new ForeachBindInfo() - { - CurrentMember = currentMember, - EnumeratorSymbol = enumeratorSymbol, - GetEnumerator = getEnumMethod, - MoveNextMember = moveNextMember, - DisposeMember = disposeMember, - DisposeCall = callDispose, - EnumeratorVar = assign.Target, - EnumeratorAssignmentEx = assign, - MoveNextEx = moveNextCondition, - }; - - return new BoundForEachStmt(BindVariable(localVar), collection, bindInfo); - } - else - { - //Bound error - return new BoundExpressionStmt(new BoundBadEx(Compilation.CoreTypes.Void.Symbol)); - } - } - else + var bindInfo = new ForeachBindInfo() { - //Bound error - return new BoundExpressionStmt(new BoundBadEx(Compilation.CoreTypes.Void.Symbol)); - } + CurrentMember = currentMember, + EnumeratorSymbol = enumeratorSymbol, + GetEnumerator = getEnumMethod, + MoveNextMember = moveNextMember, + DisposeMember = disposeMember, + DisposeCall = callDispose, + EnumeratorVar = assign.Target, + EnumeratorAssignmentEx = assign, + MoveNextEx = moveNextCondition, + }; + + return new BoundForEachStmt(BindVariable(localVar), collection, bindInfo); } private BoundVariableRef BindVar(SyntaxToken identifier, TypeSymbol type) @@ -454,7 +283,7 @@ protected BoundStatement BindReturnStmt(ReturnStmt stmt) return new BoundReturnStmt(expr); } - public BoundStatement BindEmptyStmt(Microsoft.CodeAnalysis.Text.TextSpan span) + public BoundStatement BindEmptyStmt(TextSpan span) { return new BoundEmptyStmt(span); } @@ -472,27 +301,50 @@ protected BoundExpression BindExpressionCore(ExprSyntax expr, BoundAccess access { Debug.Assert(expr != null); - if (expr is LiteralEx) return BindLiteralEx((LiteralEx)expr).WithAccess(access); - if (expr is NameEx ne) return BindNameEx(ne, access); - - if (expr is BinaryEx bex) return BindBinaryEx(bex).WithAccess(access); - if (expr is AssignEx aex) return BindAssignEx(aex, access); - if (expr is InvocationEx ce) return BindCallEx(ce).WithAccess(access); - if (expr is MatchEx me) return BindMatchEx(me).WithAccess(access); - if (expr is MemberAccessEx mae) - return BindMemberAccessEx(mae, SyntaxFactory.ArgumentList(), false).WithAccess(access); - if (expr is ElementAccessEx eae) return BindIndexerEx(eae).WithAccess(access); - if (expr is PostfixUnaryEx pue) return BindPostfixUnaryEx(pue).WithAccess(access); - if (expr is PrefixUnaryEx prue) return BindPrefixUnaryEx(prue).WithAccess(access); - if (expr is ThrowEx throwEx) - return new BoundThrowEx(BindExpression(throwEx.Expression, BoundAccess.Read), null); - if (expr is AllocEx allocEx) return BindAllocEx(allocEx).WithAccess(access); - if (expr is ParenthesizedEx pe) return BindExpression(pe.Expression).WithAccess(access); - - Diagnostics.Add(GetLocation(expr), ErrorCode.ERR_NotYetImplemented, - $"Expression of type '{expr.GetType().Name}'"); - - return new BoundBadEx(this.Compilation.GetSpecialType(SpecialType.System_Void)); + switch (expr) + { + case LiteralEx ex: + return BindLiteralEx(ex).WithAccess(access); + case NameEx ne: + return BindNameEx(ne, access); + case BinaryEx bex: + return BindBinaryEx(bex).WithAccess(access); + case AssignEx aex: + return BindAssignEx(aex, access); + case InvocationEx ce: + return BindCallEx(ce).WithAccess(access); + case MatchEx me: + return BindMatchEx(me).WithAccess(access); + case MemberAccessEx mae: + return BindMemberAccessEx(mae, SyntaxFactory.ArgumentList(), false).WithAccess(access); + case ElementAccessEx eae: + return BindIndexerEx(eae).WithAccess(access); + case PostfixUnaryEx pue: + return BindPostfixUnaryEx(pue).WithAccess(access); + case PrefixUnaryEx prue: + return BindPrefixUnaryEx(prue).WithAccess(access); + case ThrowEx throwEx: + return new BoundThrowEx(BindExpression(throwEx.Expression, BoundAccess.Read), null); + case AllocEx allocEx: + return BindAllocEx(allocEx).WithAccess(access); + case ParenthesizedEx pe: + return BindExpression(pe.Expression).WithAccess(access); + case FuncEx fex: + return BindFuncEx(fex).WithAccess(BoundAccess.Read); + default: + Diagnostics.Add(GetLocation(expr), ErrorCode.ERR_NotYetImplemented, + $"Expression of type '{expr.GetType().Name}'"); + + return new BoundBadEx(this.Compilation.GetSpecialType(SpecialType.System_Void)); + } + } + + private BoundExpression BindFuncEx(FuncEx funcEx) + { + var nestedType = new SynthesizedTypeSymbol(this.Container, this.Compilation); + var lambda = new SourceLambdaSymbol(nestedType, funcEx); + SourceCompiler.BindAndAnalyze( lambda.ControlFlowGraph.) + return new BoundFuncEx(nestedType, lambda, lambda.ReturnType); } private BoundExpression BindAllocEx(AllocEx ex) diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/ForeachBindInfo.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/ForeachBindInfo.cs new file mode 100644 index 000000000..a7d0e59ee --- /dev/null +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/ForeachBindInfo.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis; + +namespace Aquila.CodeAnalysis.Semantics; + +public struct ForeachBindInfo +{ + public IPropertySymbol CurrentMember; + public IMethodSymbol MoveNextMember; + public ITypeSymbol EnumeratorSymbol; + public IMethodSymbol GetEnumerator; + public IMethodSymbol DisposeMember; + + public BoundReferenceEx EnumeratorVar; + public BoundReferenceEx CurrentVar; + public BoundCallEx MoveNextEx; + public BoundAssignEx EnumeratorAssignmentEx; + public BoundCallEx DisposeCall; +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/GlobalBinder.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/GlobalBinder.cs new file mode 100644 index 000000000..0a9ed2978 --- /dev/null +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/GlobalBinder.cs @@ -0,0 +1,22 @@ +using Aquila.CodeAnalysis.Symbols; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Aquila.CodeAnalysis.Semantics; + +internal class GlobalBinder : InContainerBinder +{ + private readonly NamespaceOrTypeSymbol _ns; + + public GlobalBinder(INamespaceOrTypeSymbol ns, Binder next) : base(ns, next) + { + _ns = (NamespaceOrTypeSymbol)ns; + } + + public override NamespaceOrTypeSymbol Container => _ns; + + protected override void FindMethodsByName(string name, ArrayBuilder result) + { + result.AddRange(_ns.GetMembers(name).OfType()); + } +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/InClrImportBinder.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/InClrImportBinder.cs new file mode 100644 index 000000000..a5b872cf5 --- /dev/null +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/InClrImportBinder.cs @@ -0,0 +1,61 @@ +using System.Linq; +using Aquila.CodeAnalysis.Errors; +using Aquila.CodeAnalysis.Symbols; +using Aquila.CodeAnalysis.Syntax; +using Aquila.CodeAnalysis.Utilities; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Aquila.CodeAnalysis.Semantics; + +internal class InClrImportBinder : Binder +{ + private readonly INamespaceOrTypeSymbol _container; + + public InClrImportBinder(INamespaceOrTypeSymbol container, Binder next) : base(next) + { + _container = container; + } + + protected override ITypeSymbol FindTypeByName(NameEx tref) + { + var qName = tref.GetUnqualifiedName().Identifier.Text; + + var typeMembers = Container.GetTypeMembers(qName, -1); + + if (typeMembers.Length == 1) + return typeMembers[0]; + + if (typeMembers.Length == 0) + { + return Next.BindType(tref); + } + + if (typeMembers.Length > 1) + { + Diagnostics.Add(GetLocation(tref), ErrorCode.WRN_UndefinedType, + $"Expression of type '{tref.GetType().Name}'"); + } + + return null; + } + + protected override void FindMethodsByName(string name, ArrayBuilder result) + { + var typesCandidate = _container.GetTypeMembers().Where(x => name.StartsWith(StringUtils.ToSnakeCase(x.Name))); + + foreach (var type in typesCandidate) + { + var typeSnake = type.Name.ToSnakeCase(); + + var resolvedMethods = type.GetMembers().Where(x => + x.DeclaredAccessibility == Accessibility.Public && x.IsStatic && + typeSnake + "_" + x.Name.ToSnakeCase() == name) + .OfType(); + + result.AddRange(resolvedMethods); + } + + base.FindMethodsByName(name, result); + } +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/InContainerBinder.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/InContainerBinder.cs new file mode 100644 index 000000000..6f50e0e89 --- /dev/null +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/InContainerBinder.cs @@ -0,0 +1,52 @@ +using Aquila.CodeAnalysis.Errors; +using Aquila.CodeAnalysis.Symbols; +using Aquila.CodeAnalysis.Syntax; +using Microsoft.CodeAnalysis; + +namespace Aquila.CodeAnalysis.Semantics; + +internal class InContainerBinder : Binder +{ + private readonly INamespaceOrTypeSymbol _container; + + public InContainerBinder(INamespaceOrTypeSymbol container, Binder next) : base(next) + { + _container = container; + } + + public override NamespaceOrTypeSymbol Container => (NamespaceOrTypeSymbol)_container; + + + protected override ITypeSymbol FindTypeByName(NameEx tref) + { + TypeSymbol result = null; + + var qName = tref.GetUnqualifiedName().Identifier.Text; + + var typeMembers = Container.GetTypeMembers(qName, -1); + + if (typeMembers.Length == 1) + result = typeMembers[0]; + + if (typeMembers.Length == 0) + { + result = Next?.BindType(tref); + } + + if (typeMembers.Length > 1) + { + Diagnostics.Add(GetLocation(tref), ErrorCode.WRN_UndefinedType, + $"Expression of type '{tref.GetType().Name}'"); + } + + if (result == null) + { + result = new MissingMetadataTypeSymbol(qName, 0, true); + } + + if (result.IsErrorType()) + Diagnostics.Add(GetLocation(tref), ErrorCode.ERR_TypeNameCannotBeResolved, qName); + + return result; + } +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/InMethodBinder.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/InMethodBinder.cs new file mode 100644 index 000000000..046e2fe9a --- /dev/null +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/InMethodBinder.cs @@ -0,0 +1,25 @@ +using System; +using Aquila.CodeAnalysis.Symbols; + +namespace Aquila.CodeAnalysis.Semantics; + +internal class InMethodBinder : Binder +{ + private readonly SourceMethodSymbolBase _method; + + public InMethodBinder(MethodSymbol method, Binder next) : base(next) + { + if(method is null) + throw new ArgumentNullException(nameof(method)); + + if (method is not SourceMethodSymbolBase m) + throw new ArgumentException($@"The method must be {nameof(SourceMethodSymbolBase)} type", nameof(method)); + + _method = m; + } + + public override SourceMethodSymbolBase Method => _method; + + + public override NamespaceOrTypeSymbol Container => _method.ContainingType; +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/InModuleBinder.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/InModuleBinder.cs new file mode 100644 index 000000000..e0e3630f1 --- /dev/null +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/InModuleBinder.cs @@ -0,0 +1,8 @@ +namespace Aquila.CodeAnalysis.Semantics; + +internal class InModuleBinder : Binder +{ + public InModuleBinder(Binder next) : base(next) + { + } +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Graph/ControlFlowGraph.cs b/src/Aquila.CodeAnalysis/Semantics/Graph/ControlFlowGraph.cs index 94309a3f4..4cbe9c387 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Graph/ControlFlowGraph.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Graph/ControlFlowGraph.cs @@ -132,18 +132,18 @@ readonly ImmutableArray #region Construction - internal ControlFlowGraph(IList statements, Binder binder) + internal ControlFlowGraph(IEnumerable statements, Binder binder) : this(GraphBuilder.Build(statements, binder)) { } - internal ControlFlowGraph(IReadOnlyList nodes, Binder binder) + internal ControlFlowGraph(IEnumerable nodes, Binder binder) : this(GraphBuilder.Build(nodes, binder)) { } private ControlFlowGraph(GraphBuilder builder) - : this(builder.Start, builder.Exit, builder.Declarations, /*builder.Exception*/null, builder.Labels, + : this(builder.Start, builder.Exit, builder.Declarations, exception: null, builder.Labels, builder.DeadBlocks) { } diff --git a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphBuilder.cs b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphBuilder.cs index 286529327..204970809 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphBuilder.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphBuilder.cs @@ -22,7 +22,7 @@ internal sealed class GraphBuilder : AquilaSyntaxWalker private Dictionary _labels; private List _breakTargets; private Stack _tryTargets; - private Stack _scopes = new Stack(1); + private Stack _scopes = new(1); private int _index = 0; private int _htmlInstructionIndex = 0; @@ -36,21 +36,16 @@ internal sealed class GraphBuilder : AquilaSyntaxWalker public List _declarations; - public BoundBlock Start { get; private set; } - public BoundBlock Exit { get; private set; } + public BoundBlock Start { get; } + public BoundBlock Exit { get; } /// /// Gets labels defined within the method. /// - public ImmutableArray Labels - { - get - { - return (_labels != null) - ? _labels.Values.ToImmutableArray() - : ImmutableArray.Empty; - } - } + public ImmutableArray Labels => + _labels != null + ? _labels.Values.ToImmutableArray() + : ImmutableArray.Empty; /// /// Blocks we know nothing is pointing to (right after jump, throw, etc.). @@ -69,7 +64,7 @@ private enum LocalScope Finally, } - private class LocalScopeInfo + private sealed class LocalScopeInfo { public BoundBlock FirstBlock { get; } public LocalScope Scope { get; } @@ -91,7 +86,7 @@ private void CloseScope() if (_scopes.Count == 0) throw new InvalidOperationException(); - _scopes.Pop(); + _scopes.Pop(); } #endregion @@ -178,7 +173,7 @@ private void CloseTryScope() private GraphBuilder(IEnumerable nodes, Binder binder) { - Contract.ThrowIfNull(nodes); + Contract.ThrowIfNull(nodes); Contract.ThrowIfNull(binder); _binder = binder; @@ -407,7 +402,7 @@ public override void VisitMethodDecl(MethodDecl x) public override void VisitBlockStmt(BlockStmt x) { - Add(_binder.BindEmptyStmt(new TextSpan(x.Span.Start, 1))); + Add(_binder.BindEmptyStmt(new TextSpan(x.Span.Start, 1))); base.VisitBlockStmt(x); // visit nested statements @@ -591,8 +586,7 @@ private void BuildVariableDecl(LocalDeclStmt varDecl) public override void VisitReturnStmt(ReturnStmt x) { _returnCounter++; - - // + Add(x); Connect(_current, this.Exit); _current = NewDeadBlock(); // anything after these statements is unreachable @@ -633,7 +627,7 @@ public override void VisitIfStmt(IfStmt x) public override void VisitMatchEx(MatchEx arg) { - var items = arg.Arms.OfType().ToArray(); + var items = arg.Arms.ToArray(); if (!items.Any()) return; @@ -642,18 +636,14 @@ public override void VisitMatchEx(MatchEx arg) var end = NewBlock(); - bool hasDefault = false; var arms = new List(items.Count()); for (int i = 0; i < items.Count(); i++) { var arm = new MatchArmBlock(_binder.BindExpression(items[i].PatternExpression, BoundAccess.Read)); arms.Add(arm); - - hasDefault |= arm.IsDefault; } - // SwitchEdge // Connects _current to cases var edge = new MatchEdge(matchValue, arms.ToImmutableArray(), end); _current = WithNewOrdinal(arms[0]); @@ -691,7 +681,7 @@ public override void VisitTryStmt(TryStmt x) // init catch blocks and finally block var catchBlocks = ImmutableArray.Empty; - if (x.Catches != null) + if (x.Catches is { Count: > 1 }) { var catchBuilder = ImmutableArray.CreateBuilder(x.Catches.Count); for (int i = 0; i < x.Catches.Count; i++) @@ -708,7 +698,7 @@ public override void VisitTryStmt(TryStmt x) var edge = new TryCatchEdge(body, catchBlocks, finallyBlock, end); _current.SetNextEdge(edge); - + // build try body OpenTryScope(edge); OpenScope(body, LocalScope.Try); diff --git a/src/Aquila.CodeAnalysis/Semantics/TypeRef/BoundTypeRef.cs b/src/Aquila.CodeAnalysis/Semantics/TypeRef/BoundTypeRef.cs index 47561b8ca..70e342435 100644 --- a/src/Aquila.CodeAnalysis/Semantics/TypeRef/BoundTypeRef.cs +++ b/src/Aquila.CodeAnalysis/Semantics/TypeRef/BoundTypeRef.cs @@ -17,7 +17,7 @@ namespace Aquila.CodeAnalysis.Semantics.TypeRef #region BoundPrimitiveTypeRef [DebuggerDisplay("BoundPrimitiveTypeRef ({_type})")] - public sealed partial class BoundPrimitiveTypeRef : BoundTypeRef + public sealed partial class BoundPrimitiveTypeRef { public AquilaTypeCode TypeCode => _type; diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs index 65bf3f2ad..3cffa38b7 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs @@ -15,11 +15,11 @@ public SourceLambdaSymbol(NamedTypeSymbol type, FuncEx functionExpr) : base(type _functionExpr = functionExpr; } - public override Accessibility DeclaredAccessibility { get; } + public override Accessibility DeclaredAccessibility => Accessibility.Internal; public override bool IsStatic => false; - - internal override ParameterListSyntax SyntaxSignature { get; } + + internal override ParameterListSyntax SyntaxSignature => _functionExpr.ParameterList; internal override TypeEx SyntaxReturnType => _functionExpr.ReturnType; @@ -27,8 +27,6 @@ public SourceLambdaSymbol(NamedTypeSymbol type, FuncEx functionExpr) : base(type internal override IEnumerable Statements => _functionExpr.Body?.Statements; - public override ControlFlowGraph ControlFlowGraph { get; internal set; } - protected override Binder GetMethodBinder() { return DeclaringCompilation.GetBinder(_functionExpr); @@ -36,6 +34,6 @@ protected override Binder GetMethodBinder() public override void GetDiagnostics(DiagnosticBag diagnostic) { - throw new System.NotImplementedException(); + } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs index 0407bc766..4793ded04 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/Web/SourceViewTypeSymbol.cs @@ -229,31 +229,6 @@ protected override ControlFlowGraph CreateControlFlowGraph() } - /// - public override ControlFlowGraph ControlFlowGraph - { - get - { - if (_cfg != null) - { - return _cfg; - } - - if (_htmlDecl.HtmlMarkup == null) - { - return null; - } - - - var binder = - var cfg = - Interlocked.CompareExchange(ref _cfg, cfg, null); - - return _cfg; - } - internal set => _cfg = value; - } - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) { return true; diff --git a/src/Aquila.SyntaxGenerator/BoundTree.xml b/src/Aquila.SyntaxGenerator/BoundTree.xml index 03925dbdd..194d442f1 100644 --- a/src/Aquila.SyntaxGenerator/BoundTree.xml +++ b/src/Aquila.SyntaxGenerator/BoundTree.xml @@ -24,12 +24,6 @@ - - - - - - @@ -52,6 +46,11 @@ + + + + + @@ -207,6 +206,14 @@ + + + + + + + From c5912308da898013a0f7e784304ce9bebb5d1ade Mon Sep 17 00:00:00 2001 From: cm4ker Date: Thu, 26 Jan 2023 09:10:27 +0600 Subject: [PATCH 06/16] fix add lambda function to the analysing pipeline --- src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs | 5 ----- src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs b/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs index 184e9e517..5de73cb6c 100644 --- a/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs +++ b/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs @@ -172,11 +172,6 @@ internal void AnalyzeMethods() void AnalyzeBlock(BoundBlock block) { block.Accept(AnalysisFactory()); - - foreach (var lambda in block.FlowState.FlowContext.Lambdas) - { - EnqueueMethod(lambda); - } } GraphVisitor AnalysisFactory() diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs index 86d53336a..5b933611a 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs @@ -601,7 +601,11 @@ public override T VisitCallEx(BoundCallEx arg) public override T VisitFuncEx(BoundFuncEx x) { + Debug.Assert(x.LambdaSymbol.ControlFlowGraph != null); + State.VisitFuncEx(x); + EnqueueBlock(x.LambdaSymbol.ControlFlowGraph.Start); + return default; } From 89ae79d26af68c65eb5990a46c8c51c0d8e0a340 Mon Sep 17 00:00:00 2001 From: cm4ker Date: Thu, 26 Jan 2023 09:19:07 +0600 Subject: [PATCH 07/16] fix compilation --- .../Semantics/Binder/Binder.cs | 3 +- .../Semantics/BoundStatement.cs | 29 ++++++------------- .../Semantics/Graph/GraphRewriter.cs | 7 ----- .../Semantics/Graph/GraphUpdater.cs | 5 ---- .../Semantics/Graph/GraphWalker.cs | 5 ---- 5 files changed, 10 insertions(+), 39 deletions(-) diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs index 576c4a2ac..e3a9c1f33 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs @@ -341,9 +341,8 @@ protected BoundExpression BindExpressionCore(ExprSyntax expr, BoundAccess access private BoundExpression BindFuncEx(FuncEx funcEx) { - var nestedType = new SynthesizedTypeSymbol(this.Container, this.Compilation); + var nestedType = new SynthesizedTypeSymbol(this.Container, this.Compilation); var lambda = new SourceLambdaSymbol(nestedType, funcEx); - SourceCompiler.BindAndAnalyze( lambda.ControlFlowGraph.) return new BoundFuncEx(nestedType, lambda, lambda.ReturnType); } diff --git a/src/Aquila.CodeAnalysis/Semantics/BoundStatement.cs b/src/Aquila.CodeAnalysis/Semantics/BoundStatement.cs index 62802026b..4e40914f1 100644 --- a/src/Aquila.CodeAnalysis/Semantics/BoundStatement.cs +++ b/src/Aquila.CodeAnalysis/Semantics/BoundStatement.cs @@ -59,26 +59,6 @@ partial void AcceptImpl(OperationVisitor visitor, TArg a } } -/// -/// Conditionally declared functions. -/// -public sealed partial class BoundMethodDeclStmt : IInvalidOperation -{ - internal MethodDecl FunctionDecl => (MethodDecl)AquilaSyntax; - - partial void OnCreateImpl(SourceMethodSymbolBase method) - { - this.AquilaSyntax = (MethodDecl)method.Syntax; - } - - partial void AcceptImpl(OperationVisitor visitor) => visitor.VisitInvalid(this); - - partial void AcceptImpl(OperationVisitor visitor, TArg argument, ref TRes result) - { - result = visitor.VisitInvalid(this, argument); - } -} - public sealed partial class BoundGlobalVariableStatement : BoundStatement, IVariableDeclarationOperation { ImmutableArray IVariableDeclarationOperation.IgnoredDimensions => ImmutableArray.Empty; @@ -283,4 +263,13 @@ public sealed partial class BoundHtmlOpenElementStmt public sealed partial class BoundHtmlAddAttributeStmt { +} + +public sealed partial class BoundBadStmt +{ +} + +public sealed partial class BoundFuncEx +{ + } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphRewriter.cs b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphRewriter.cs index 032897fb5..3cf195147 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphRewriter.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphRewriter.cs @@ -119,13 +119,6 @@ public override VoidStruct VisitYieldStmt(BoundYieldStmt boundYieldStmt) return base.VisitYieldStmt(boundYieldStmt); } - - public override VoidStruct VisitMethodDeclStmt(BoundMethodDeclStmt x) - { - _rewriter.OnUnreachableMethodFound(x.Method); - - return base.VisitMethodDeclStmt(x); - } } #endregion diff --git a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphUpdater.cs b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphUpdater.cs index 75d0874b6..764a5777d 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphUpdater.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphUpdater.cs @@ -486,11 +486,6 @@ public override object VisitReturnStmt(BoundReturnStmt x) return x.Update((BoundExpression)Accept(x.Returned)); } - public override object VisitMethodDeclStmt(BoundMethodDeclStmt x) - { - return x; - } - #endregion } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphWalker.cs b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphWalker.cs index 6474fe349..bb66d7fea 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphWalker.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphWalker.cs @@ -338,11 +338,6 @@ public override T VisitReturnStmt(BoundReturnStmt x) return default; } - public override T VisitMethodDeclStmt(BoundMethodDeclStmt x) - { - return default; - } - public override T VisitDeclareStmt(BoundDeclareStmt x) { return default; From 777eaff4734356c0ca6f291b45fed37c86cb49b4 Mon Sep 17 00:00:00 2001 From: cm4ker Date: Thu, 26 Jan 2023 09:41:20 +0600 Subject: [PATCH 08/16] fix docker tests --- src/Aquila.Test.Tools/Aquila.Test.Tools.csproj | 2 +- src/Aquila.Test.Tools/DatabaseFixture.cs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Aquila.Test.Tools/Aquila.Test.Tools.csproj b/src/Aquila.Test.Tools/Aquila.Test.Tools.csproj index 4e86073cf..b56fb4385 100644 --- a/src/Aquila.Test.Tools/Aquila.Test.Tools.csproj +++ b/src/Aquila.Test.Tools/Aquila.Test.Tools.csproj @@ -7,8 +7,8 @@ - + diff --git a/src/Aquila.Test.Tools/DatabaseFixture.cs b/src/Aquila.Test.Tools/DatabaseFixture.cs index 911403e45..26961b3ee 100644 --- a/src/Aquila.Test.Tools/DatabaseFixture.cs +++ b/src/Aquila.Test.Tools/DatabaseFixture.cs @@ -9,10 +9,9 @@ using Aquila.Initializer; using Aquila.Metadata; using Aquila.Runtime.Querying; -using DotNet.Testcontainers.Containers.Builders; -using DotNet.Testcontainers.Containers.Configurations.Databases; -using DotNet.Testcontainers.Containers.Modules.Abstractions; -using DotNet.Testcontainers.Containers.Modules.Databases; +using DotNet.Testcontainers.Builders; +using DotNet.Testcontainers.Configurations; +using DotNet.Testcontainers.Containers; using Microsoft.Extensions.DependencyInjection; using Xunit; From 0ec18b485b5c8a13edd6b67accb8516435a6ebab Mon Sep 17 00:00:00 2001 From: cm4ker Date: Fri, 27 Jan 2023 02:27:40 +0600 Subject: [PATCH 09/16] create bind name context for different name binding --- src/Aquila.CodeAnalysis/Errors/ErrorCode.cs | 186 +------------ .../Semantics/Binder/Binder.cs | 263 +++++++++--------- .../Semantics/Binder/InClrImportBinder.cs | 2 +- .../Semantics/LocalsTable.cs | 3 + .../AqContext.Script.cs | 16 +- 5 files changed, 146 insertions(+), 324 deletions(-) diff --git a/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs b/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs index 6e91782da..46eb95695 100644 --- a/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs +++ b/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs @@ -25,7 +25,6 @@ internal enum ErrorCode FTL_InvalidInputFileName = 3000, FTL_BadCodepage = 3016, - FTL_InternalCompilerError = 3017, #endregion @@ -162,132 +161,34 @@ internal enum ErrorCode ERR_ResourceInModule = 4118, ERR_ResourceNotUnique = 4119, ERR_TooManyUserStrings = 4120, - ERR_NotYetImplemented = 4121, // Used for all valid Aquila constructs - ERR_CircularBase = 4122, - ERR_TypeNameCannotBeResolved = 4123, - ERR_PositionalArgAfterUnpacking = 4124, // Cannot use positional argument after argument unpacking + ERR_NotYetImplemented = 4121, + ERR_TypeNameCannotBeResolved = 4123, // Cannot use positional argument after argument unpacking ERR_InvalidMetadataConsistance = 4125, - - /// Call to a member function {0} on {1} - ERR_MethodCalledOnNonObject = 4126, - - /// Value of type {0} cannot be passed by reference - ERR_ValueOfTypeCannotBeAliased = 4127, - - /// "Cannot instantiate {0} {1}", e.g. "interface", the type name ERR_CannotInstantiateType = 4128, - - /// "{0} cannot use {1} - it is not a trait" - ERR_CannotUseNonTrait = 4129, - - /// "Class {0} cannot extend from {1} {2}", e.g. from trait T - ERR_CannotExtendFrom = 4130, - - /// "{0} cannot implement {1} - it is not an interface" - ERR_CannotImplementNonInterface = 4131, - - /// Cannot re-assign $this ERR_CannotAssignToThis = 4132, - - /// {0}() cannot declare a return type - ERR_CannotDeclareReturnType = 4133, - - /// A void function must not return a value - ERR_VoidFunctionCannotReturnValue = 4134, - - /// {0} {1}() must take exactly {2} arguments - ERR_MustTakeArgs = 4135, - - /// Function name must be a string, {0} given - ERR_InvalidFunctionName = 4136, - - /// Cannot use the final modifier on an abstract class - ERR_FinalAbstractClassDeclared = 4137, - - /// Access level to {0}::${1} must be {2} (as in class {3}) or weaker - ERR_PropertyAccessibilityError = 4138, - - /// Use of primitive type '{0}' is misused ERR_PrimitiveTypeNameMisused = 4139, - - /// Missing value for '{0}' option ERR_SwitchNeedsValue = 4140, - - /// '{0}' not in the 'loop' or 'switch' context ERR_NeedsLoopOrSwitch = 4141, - - /// Provided source code kind is unsupported or invalid: '{0}' ERR_BadSourceCodeKind = 4142, - - /// Provided documentation mode is unsupported or invalid: '{0}'. ERR_BadDocumentationMode = 4143, - - /// Compilation options '{0}' and '{1}' can't both be specified at the same time. ERR_MutuallyExclusiveOptions = 4144, - - /// Invalid instrumentation kind: {0} ERR_InvalidInstrumentationKind = 4145, - - /// Invalid hash algorithm name: '{0}' ERR_InvalidHashAlgorithmName = 4146, - - /// Option '{0}' must be an absolute path. ERR_OptionMustBeAbsolutePath = 4147, - - /// Cannot emit debug information for a source text without encoding. ERR_EncodinglessSyntaxTree = 4148, - - /// An error occurred while writing the output file: {0}. ERR_PeWritingFailure = 4149, - - /// Failed to emit module '{0}'. ERR_ModuleEmitFailure = 4150, - - /// Cannot update '{0}'; attribute '{1}' is missing. ERR_EncUpdateFailedMissingAttribute = 4151, - - /// Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' ERR_InvalidDebugInfo = 4152, - - /// Invalid assembly name: {0} ERR_BadAssemblyName = 4153, - - /// /embed switch is only supported when emitting Portable PDB (/debug:portable or /debug:embedded). ERR_CannotEmbedWithoutPdb = 4154, - - /// No overload for method {0} can be called. - ERR_NoMatchingOverload = 4155, - - /// Default value for parameter ${0} with a {1} type can only be {1} or NULL, {2} given - ERR_DefaultParameterValueTypeMismatch = 4156, - - /// Constant expression contains invalid operations ERR_InvalidConstantExpression = 4157, - - /// Using $this when not in object context - ERR_ThisOutOfObjectContext = 4158, - - /// Cannot set read-only property {0}::${1} ERR_ReadOnlyPropertyWritten = 4159, - - /// Only the last parameter can be variadic - ERR_VariadicParameterNotLast = 4160, - ERR_CtorPropertyVariadic = 4161, - ERR_CtorPropertyAbstractCtor = 4162, - ERR_CtorPropertyNotCtor = 4163, - ERR_CtorPropertyStaticCtor = 4164, - - /// Property {0}::${1} cannot have type {2} - ERR_PropertyTypeNotAllowed = 4165, - - /// Multiple analyzer config files cannot be in the same directory ('{0}'). ERR_MultipleAnalyzerConfigsInSameDir = 4166, - - /// Method '{0}' not found for type {1}. ERR_MethodNotFound = 4167, - ERR_MissingIdentifierSymbol = 4168, + ERR_CantResolveSymbol = 4169, #endregion @@ -305,103 +206,22 @@ internal enum ErrorCode WRN_PdbLocalNameTooLong = 5004, WRN_PdbUsingNameTooLong = 5005, WRN_UnableToLoadAnalyzer = 5006, - WRN_UndefinedFunctionCall = 5007, WRN_UninitializedVariableUse = 5008, WRN_UndefinedType = 5009, - WRN_UndefinedMethodCall = 5010, - - /// The declaration of class, interface or trait is ambiguous since its base types cannot be resolved. - WRN_AmbiguousDeclaration = 5011, WRN_UnreachableCode = 5012, - WRN_NotYetImplementedIgnored = 5013, WRN_NoSourceFiles = 5014, - - /// {0}() expects {1} parameter(s), {2} given - WRN_TooManyArguments = 5015, - - /// {0}() expects at least {1} parameter(s), {2} given - WRN_MissingArguments = 5016, - - /// Assertion will always fail - WRN_AssertAlwaysFail = 5017, - - /// Using string as the assertion is deprecated - WRN_StringAssertionDeprecated = 5018, - - /// Deprecated: {0} '{1}' has been deprecated. {2} - WRN_SymbolDeprecated = 5019, - - /// The expression is not being read. Did you mean to assign it somewhere? - WRN_ExpressionNotRead = 5020, - - /// Assignment made to same variable; did you mean to assign something else? - WRN_AssigningSameVariable = 5021, - - /// Invalid array key type: {0}. - WRN_InvalidArrayKeyType = 5022, - - /// Duplicate array key: '{0}'. - WRN_DuplicateArrayKey = 5023, - - /// Cloning of non-object: {0}. - WRN_CloneNonObject = 5024, - - /// Using non-iterable type in foreach: {0}. - WRN_ForeachNonIterable = 5025, - - /// Call to '{0}()' expects {1} argument(s), {2} given. WRN_FormatStringWrongArgCount = 5026, - - /// Missing the call of parent::__construct from {0}::__construct. WRN_ParentCtorNotCalled = 5027, - - /// Method {0}::__toString() must return a string value - WRN_ToStringMustReturnString = 5028, - - /// Argument has no value, parameter will be always NULL - WRN_ArgumentVoid = 5029, - - /// PCRE pattern parse error: {0} at offset {1} - WRN_PCRE_Pattern_Error = 5030, - - /// {0} '{1}' is already defined - WRN_TypeNameInUse = 5031, - - /// Script file '{0}' could not be resolved, the script inclusion is unbound. - WRN_CannotIncludeFile = 5032, - - /// Called from the global scope - WRN_CalledFromGlobalScope = 5033, - - /// Generator '{0}' failed to initialize. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}' WRN_GeneratorFailedDuringInitialization = 5034, - - /// Generator '{0}' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type '{1}' with message '{2}' WRN_GeneratorFailedDuringGeneration = 5035, #endregion #region 6xxx Visible information - // - // Visible information - // INF_UnableToLoadSomeTypesInAnalyzer = 6000, - INF_EvalDiscouraged = 6001, - INF_RedundantCast = 6002, - - /// Name '{0}' does not match the expected name '{1}', letter casing mismatch. INF_TypeNameCaseMismatch = 6003, - /// - INF_DestructDiscouraged = 6004, - - /// Overriden function name '{0}' does not match it's parent name '{1}', letter casing mismatch. - INF_OverrideNameCaseMismatch = 6005, - - /// The symbol can not been resolved - INF_CantResolveSymbol = 6006 - #endregion } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs index e3a9c1f33..94f125f20 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs @@ -103,9 +103,9 @@ private BoundStatement BindTryStmt(TryStmt tryStmt) internal BoundStatement BindVarDecl(VariableDecl varDecl) { Debug.Assert(varDecl.Variables.Count == 1); - + var decl = varDecl.Variables.First(); - + if (string.IsNullOrWhiteSpace(decl.Identifier.Text) || decl.Initializer == null) { Diagnostics.Add(GetLocation(varDecl), ErrorCode.ERR_MissingIdentifierSymbol); @@ -140,7 +140,7 @@ private BoundVariableRef BindVariable(IVariableReference localVar) private static BoundStatement BoundStatementError() => new BoundBadStmt(); - + private BoundStatement BindForeachStmt(ForEachStmt stmt) { var collection = BindExpression(stmt.Expression, BoundAccess.Read); @@ -150,7 +150,7 @@ private BoundStatement BindForeachStmt(ForEachStmt stmt) if (getEnumMethod == null) return BoundStatementError(); - + var enumeratorSymbol = getEnumMethod.ReturnType; var currentMember = enumeratorSymbol .LookupMember(WellKnownMemberNames.CurrentPropertyName); @@ -162,7 +162,7 @@ private BoundStatement BindForeachStmt(ForEachStmt stmt) if (currentMember == null || moveNextMember == null) return BoundStatementError(); - + var variableType = currentMember.Type; var localVar = Method.LocalsTable.BindLocalVariable(new VariableName(stmt.Identifier.Text), @@ -316,7 +316,7 @@ protected BoundExpression BindExpressionCore(ExprSyntax expr, BoundAccess access case MatchEx me: return BindMatchEx(me).WithAccess(access); case MemberAccessEx mae: - return BindMemberAccessEx(mae, SyntaxFactory.ArgumentList(), false).WithAccess(access); + return BindMemberAccessEx(mae, new NameBindingContext()).WithAccess(access); case ElementAccessEx eae: return BindIndexerEx(eae).WithAccess(access); case PostfixUnaryEx pue: @@ -341,7 +341,7 @@ protected BoundExpression BindExpressionCore(ExprSyntax expr, BoundAccess access private BoundExpression BindFuncEx(FuncEx funcEx) { - var nestedType = new SynthesizedTypeSymbol(this.Container, this.Compilation); + var nestedType = new SynthesizedTypeSymbol(this.Container, this.Compilation); var lambda = new SourceLambdaSymbol(nestedType, funcEx); return new BoundFuncEx(nestedType, lambda, lambda.ReturnType); } @@ -684,7 +684,7 @@ protected BoundExpression BindAssignEx(AssignEx expr, BoundAccess access) var boundExpr = BindExpression(expr.Left, BoundAccess.Write); - if (!(boundExpr is BoundReferenceEx target)) + if (boundExpr is not BoundReferenceEx target) { Diagnostics.Add(GetLocation(expr), ErrorCode.ERR_TypeNameCannotBeResolved, $"Can't assign to not reference expression"); @@ -698,7 +698,7 @@ protected BoundExpression BindAssignEx(AssignEx expr, BoundAccess access) var op = ToOp(expr.Kind()); - if (op == Operations.AssignValue || op == Operations.AssignRef) + if (op is Operations.AssignValue or Operations.AssignRef) { return new BoundAssignEx(target, value, value.ResultType).WithAccess(access); } @@ -770,23 +770,19 @@ protected BoundExpression BindPrefixUnaryEx(PrefixUnaryEx expr) private BoundExpression BindCallEx(InvocationEx expr) { - return BindMethodGroup(expr.Expression, expr.ArgumentList, true); + + return BindMethod(expr.Expression, new NameBindingContext(expr.ArgumentList)); } - private BoundExpression BindMethodGroup(ExprSyntax expr, ArgumentListSyntax args, bool invoked) + private BoundExpression BindMethod(ExprSyntax expr, NameBindingContext context) { - switch (expr.Kind()) + return expr.Kind() switch { - case SyntaxKind.IdentifierEx: - return BindName((SimpleNameEx)expr, args, invoked); - case SyntaxKind.SimpleMemberAccessExpression: - return BindMemberAccessEx((MemberAccessEx)expr, args, invoked); - case SyntaxKind.GenericName: - return BindName((GenericEx)expr, args, invoked); - - default: - throw new NotImplementedException(); - } + SyntaxKind.IdentifierEx => BindName((SimpleNameEx)expr, context), + SyntaxKind.SimpleMemberAccessExpression => BindMemberAccessEx((MemberAccessEx)expr, context), + SyntaxKind.GenericName => BindName((GenericEx)expr, context), + _ => throw new NotImplementedException() + }; } MethodSymbol ConstructSingle(MethodSymbol method, ImmutableArray typeArgs) @@ -816,7 +812,7 @@ ImmutableArray Construct(ImmutableArray methods, { var result = new List(); - for (int i = 0; i < methods.Length; i++) + for (var i = 0; i < methods.Length; i++) { if (methods[i].Arity == typeArgs.Length) // TODO: check the type argument is assignable { @@ -828,123 +824,122 @@ ImmutableArray Construct(ImmutableArray methods, } } - protected virtual BoundExpression BindName(SimpleNameEx expr, ArgumentListSyntax argumentList, bool invocation) - { - Debug.Assert(Method != null); - - var arglist = argumentList.Arguments - .Select(x => BoundArgument.Create(BindExpression(x.Expression))) - .ToImmutableArray(); - var typeArgs = ImmutableArray.Empty; + protected class NameBindingContext + { + private ImmutableArray _boundedArguments; - if (expr.Kind() == SyntaxKind.GenericName) + public NameBindingContext() { - typeArgs = ((GenericEx)expr).TypeArgumentList.Arguments.Select(BindType).OfType() - .ToImmutableArray(); } - var nameId = expr.Identifier.Text; + public NameBindingContext(ArgumentListSyntax argumentList) + { + Arguments = argumentList.Arguments; + IsInvocation = true; + } - //try find local first - var containerMembers = Container.GetMembers(nameId).ToImmutableArray(); + public bool IsInvocation { get; } - var qualifiedName = new QualifiedName(new Name(nameId)); + public SeparatedSyntaxList Arguments { get; } - if (containerMembers.Count() == 1) + public ImmutableArray BindArguments(Binder binder) { - var member = containerMembers[0]; - if (invocation) + if (!IsInvocation) + return ImmutableArray.Empty; + + if (_boundedArguments.IsDefault) { - if (member is MethodSymbol ms) - { - ms = ConstructSingle(ms, typeArgs); + _boundedArguments = + Arguments + .Select(x => BoundArgument.Create(binder.BindExpression(x.Expression))) + .ToImmutableArray(); + } - var th = (ms.IsStatic) - ? null - : new BoundVariableRef(QualifiedName.This.Name.Value, Container as ITypeSymbol); + return _boundedArguments; + } + } - return new BoundCallEx(ms, arglist, typeArgs, th, ms.ReturnType); - } - } - else - { - if (member is MethodSymbol ms) - { - //... BoundMethod - } - if (member is FieldSymbol fs) - { - // ld_fld - } + protected virtual BoundExpression BindName(SimpleNameEx expr, NameBindingContext context) + { + Debug.Assert(Method != null); + Debug.Assert(!string.IsNullOrEmpty(expr.Identifier.Text)); - if (member is PropertySymbol ps) - { - // call _get method - } - } - } + var name = expr.Identifier.Text; - if (containerMembers.Count() > 1 && invocation) + BoundExpression CantResolve() { - //Resolve overload - var overload = ResolveOverload(containerMembers.OfType().ToImmutableArray(), arglist); + Diagnostics.Add(GetLocation(expr), ErrorCode.ERR_CantResolveSymbol, name); + return new BoundBadEx(this.Compilation.GetSpecialType(SpecialType.System_Void)); } - //Go to global members + var typeArgs = ImmutableArray.Empty; + if (expr is GenericEx genEx) { - var methods = new ArrayBuilder(); - FindMethodsByName(nameId, methods); - - var globalMembers = methods.OfType().Where(x => x.Arity == typeArgs.Count()) + typeArgs = genEx + .TypeArgumentList + .Arguments + .Select(BindType) + .OfType() .ToImmutableArray(); + } - globalMembers = Construct(globalMembers, typeArgs); - - var overload = ResolveOverload(globalMembers, arglist); + - if (overload == null) + if (context.IsInvocation) + { + if (Locals.TryGetVariable(name, out var variable)) { - Diagnostics.Add(GetLocation(expr), ErrorCode.ERR_TypeNameCannotBeResolved, nameId); - - //error can't resolve overload for this parameters - return new BoundBadEx(this.Compilation.GetSpecialType(SpecialType.System_Void)); + throw new NotImplementedException(); } - else + + var containerMembers = Container.GetMembers(name).ToImmutableArray(); + if (containerMembers.Any()) { - if (invocation) + var args = context.BindArguments(this); + var methods = containerMembers.OfType().ToImmutableArray(); + var resolved = methods switch { - if (overload is MethodSymbol ms) - { - if (ms.IsStatic) - { - return new BoundCallEx(ms, arglist, typeArgs, null, ms.ReturnType); - } - else - { - //Extension method can't be instance - } - } + { Length: 1 } => methods[0], + { Length: > 1 } => (MethodSymbol)ResolveOverload( + containerMembers.OfType().ToImmutableArray(), args) + }; + + if (resolved is null) + { + return CantResolve(); } + + resolved = ConstructSingle(resolved, typeArgs); + var thisPlace = resolved.HasThis + ? new BoundVariableRef(QualifiedName.This.Name.Value, Container as ITypeSymbol) + : null; + return new BoundCallEx(resolved, context.BindArguments(this), typeArgs, thisPlace, resolved.ReturnType); } } - if (!Enumerable.Any(containerMembers)) - Diagnostics.Add(GetLocation(expr), ErrorCode.INF_CantResolveSymbol); + if (!context.IsInvocation) + return new BoundPropertyRef(new MissingPropertySymbol(name), null); - BoundExpression result; + var argList = context.BindArguments(this); - if (invocation) - { - result = new BoundCallEx(new MissingMethodSymbol(nameId), arglist, typeArgs, null, null); - } - else + var foundMethods = new ArrayBuilder(); + FindMethodsByName(name, foundMethods); + + var globalMembers = foundMethods.OfType().Where(x => x.Arity == typeArgs.Count()) + .ToImmutableArray(); + + globalMembers = Construct(globalMembers, typeArgs); + + var overload = (MethodSymbol)ResolveOverload(globalMembers, argList); + + if (overload == null || overload.HasThis) { - result = new BoundPropertyRef(new MissingPropertySymbol(nameId), null); + return CantResolve(); } - return result; + return new BoundCallEx(overload, argList, typeArgs, null, overload.ReturnType); } private IMethodSymbol ResolveOverload(ImmutableArray overloads, @@ -1001,23 +996,16 @@ private IMethodSymbol ResolveOverload(ImmutableArray overloads, candidates[methodSymbol] = cost; } - if (candidates.Any()) - //minimize cost - return candidates.MinBy(x => x.Value).Key; - - return null; + return candidates.Any() ? candidates.MinBy(x => x.Value).Key : null; } - private BoundExpression BindMemberAccessEx(MemberAccessEx expr, ArgumentListSyntax args, bool invoke) + private BoundExpression BindMemberAccessEx(MemberAccessEx expr, NameBindingContext context) { var boundLeft = BindExpression(expr.Expression).WithAccess(BoundAccess.Invoke); var leftType = boundLeft.Type; var identifierText = expr.Name.GetUnqualifiedName().Identifier.Text; - var qualifiedName = QualifiedName.Parse(identifierText, true); - - //TODO: transform members names var members = leftType.GetMembers(identifierText); var typeArgs = ImmutableArray.Empty; @@ -1027,35 +1015,46 @@ private BoundExpression BindMemberAccessEx(MemberAccessEx expr, ArgumentListSynt .ToImmutableArray(); } - foreach (var member in members) + ISymbol member = members switch { - if (invoke) - { - if (member is MethodSymbol ms) - { - var arglist = args.Arguments.Select(x => BoundArgument.Create(BindExpression(x.Expression))) - .ToImmutableArray(); + { Length: 1 } => members[0], + { Length: > 1 } => ResolveOverload(members.OfType().ToImmutableArray(), + context.BindArguments(this)), + _ => null + }; - ms = ConstructSingle(ms, typeArgs); + if (member is null) + { + Diagnostics.Add(GetLocation(expr.Name), ErrorCode.ERR_MethodNotFound, identifierText, leftType.Name); + return new BoundBadEx(this.Compilation.GetSpecialType(SpecialType.System_Void)); + } - return new BoundCallEx(ms, arglist, typeArgs, (ms.IsStatic) ? null : boundLeft, - ms.ReturnType); - } + if (context.IsInvocation) + { + if (member is MethodSymbol ms) + { + ms = ConstructSingle(ms, typeArgs); + return new BoundCallEx(ms, context.BindArguments(this), typeArgs, + (ms.IsStatic) ? null : boundLeft, ms.ReturnType); } - else + + Diagnostics.Add(GetLocation(expr.Name), ErrorCode.ERR_MethodNotFound, identifierText, leftType.Name); + } + else + { + switch (member) { - if (member is PropertySymbol ps) - { + case PropertySymbol ps: return new BoundPropertyRef(ps, boundLeft); - } - else if (member is FieldSymbol fs) + case FieldSymbol fs: return new BoundFieldRef(fs, boundLeft); } } + - Diagnostics.Add(GetLocation(expr.Name), ErrorCode.ERR_MethodNotFound, identifierText, leftType.Name); + - return new BoundLiteral(0, Compilation.CoreTypes.Int32.Symbol); + return new BoundBadEx(this.Compilation.GetSpecialType(SpecialType.System_Void)); } protected BoundExpression BindCopyValue(BoundExpression expr) diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/InClrImportBinder.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/InClrImportBinder.cs index a5b872cf5..4c75be7aa 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Binder/InClrImportBinder.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/InClrImportBinder.cs @@ -42,7 +42,7 @@ protected override ITypeSymbol FindTypeByName(NameEx tref) protected override void FindMethodsByName(string name, ArrayBuilder result) { - var typesCandidate = _container.GetTypeMembers().Where(x => name.StartsWith(StringUtils.ToSnakeCase(x.Name))); + var typesCandidate = _container.GetTypeMembers().Where(x => name.StartsWith(x.Name.ToSnakeCase())); foreach (var type in typesCandidate) { diff --git a/src/Aquila.CodeAnalysis/Semantics/LocalsTable.cs b/src/Aquila.CodeAnalysis/Semantics/LocalsTable.cs index 87f64a027..19af07187 100644 --- a/src/Aquila.CodeAnalysis/Semantics/LocalsTable.cs +++ b/src/Aquila.CodeAnalysis/Semantics/LocalsTable.cs @@ -98,6 +98,9 @@ LocalVariableReference CreateLocal(VariableName name, VariableKind kind, TypeSym #region Public methods + public bool TryGetVariable(string name, out LocalVariableReference variable) => + _dict.TryGetValue(new VariableName(name), out variable); + public bool TryGetVariable(VariableName varname, out LocalVariableReference variable) => _dict.TryGetValue(varname, out variable); diff --git a/src/Aquila.Library.Scripting/AqContext.Script.cs b/src/Aquila.Library.Scripting/AqContext.Script.cs index eaea4a09b..fa5da24f5 100644 --- a/src/Aquila.Library.Scripting/AqContext.Script.cs +++ b/src/Aquila.Library.Scripting/AqContext.Script.cs @@ -24,7 +24,7 @@ sealed class Script : AqContext.IScript { private const string MainModuleName = "main"; private const string EntryPointMethodName = "main"; - + #region Fields & Properties /// @@ -59,7 +59,7 @@ sealed class Script : AqContext.IScript /// References to scripts that precedes this one. /// Current script requires these to be evaluated first. /// - public IReadOnlyList