diff --git a/src/Aquila.CodeAnalysis/CodeGen/Graph/BoundExpression.cs b/src/Aquila.CodeAnalysis/CodeGen/Graph/BoundExpression.cs index f517659bd..1480ab259 100644 --- a/src/Aquila.CodeAnalysis/CodeGen/Graph/BoundExpression.cs +++ b/src/Aquila.CodeAnalysis/CodeGen/Graph/BoundExpression.cs @@ -214,6 +214,25 @@ internal override TypeSymbol Emit(CodeGenerator cg) return Place().EmitLoad(cg.Builder); } } + + public partial class BoundPropertyRef + { + internal override IVariableReference BindPlace(CodeGenerator cg) + { + return new PropertyReference(this._instance, (PropertySymbol)_property); + } + + internal override IPlace Place() + { + return new PropertyPlace(null, (PropertySymbol)_property); + } + + internal override TypeSymbol Emit(CodeGenerator cg) + { + return cg.EmitCall(ILOpCode.Call, (MethodSymbol)Property.GetMethod, this.Instance, + ImmutableArray.Empty); + } + } partial class BoundBinaryEx { @@ -795,25 +814,6 @@ internal override TypeSymbol Emit(CodeGenerator cg) } } - public partial class BoundPropertyRef - { - internal override IVariableReference BindPlace(CodeGenerator cg) - { - return new PropertyReference(this._instance, (PropertySymbol)_property); - } - - internal override IPlace Place() - { - return new PropertyPlace(null, (PropertySymbol)_property); - } - - internal override TypeSymbol Emit(CodeGenerator cg) - { - return cg.EmitCall(ILOpCode.Call, (MethodSymbol)Property.GetMethod, this.Instance, - ImmutableArray.Empty); - } - } - partial class BoundThrowEx { internal override TypeSymbol Emit(CodeGenerator cg) diff --git a/src/Aquila.CodeAnalysis/CodeGen/Symbols/SourceMethodSymbolBase.cs b/src/Aquila.CodeAnalysis/CodeGen/Symbols/SourceMethodSymbolBase.cs index 0fb7f97ab..c3d619265 100644 --- a/src/Aquila.CodeAnalysis/CodeGen/Symbols/SourceMethodSymbolBase.cs +++ b/src/Aquila.CodeAnalysis/CodeGen/Symbols/SourceMethodSymbolBase.cs @@ -65,10 +65,7 @@ internal IPlace GetThisPlace() /// List of additional overloads. internal virtual IList SynthesizeStubs(PEModuleBuilder module, DiagnosticBag diagnostic) { - // EmitParametersDefaultValue(module, diagnostic); - - // TODO: resolve this already in SourceTypeSymbol.GetMembers(), now it does not get overloaded properly return SynthesizeOverloadsWithOptionalParameters(module, diagnostic); } diff --git a/src/Aquila.CodeAnalysis/CodeGen/VariableReference.cs b/src/Aquila.CodeAnalysis/CodeGen/VariableReference.cs index 4ce6cc428..270b1b5d0 100644 --- a/src/Aquila.CodeAnalysis/CodeGen/VariableReference.cs +++ b/src/Aquila.CodeAnalysis/CodeGen/VariableReference.cs @@ -253,7 +253,6 @@ public static LhsStack EmitReceiver(ILBuilder il, IPlace receiver) /// /// An object specifying a reference to a variable, a field, a property, an array item (a value in general). - /// Used by . /// interface IVariableReference { @@ -267,7 +266,7 @@ interface IVariableReference /// Gets native type of the variable. /// TypeSymbol Type { get; } - + /// /// Gets value indicating the native value can be accessed by address (ref). /// @@ -778,6 +777,6 @@ public TypeSymbol EmitLoadAddress(CodeGenerator cg, ref LhsStack lhsStack) throw ExceptionUtilities.Unreachable; } } - + #endregion } \ No newline at end of file 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..831ccd1da 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); @@ -986,15 +991,12 @@ internal override bool CompileMethods(CommonPEModuleBuilder moduleBuilder, bool throw new NotImplementedException(); } - if (emittingPdb) + if (emittingPdb && !CreateDebugDocuments( + moduleBeingBuilt.DebugDocumentsBuilder, + moduleBeingBuilt.EmbeddedTexts.Concat(CollectAdditionalEmbeddedTexts()), + diagnostics)) { - if (!CreateDebugDocuments( - moduleBeingBuilt.DebugDocumentsBuilder, - moduleBeingBuilt.EmbeddedTexts.Concat(CollectAdditionalEmbeddedTexts()), - diagnostics)) - { - return false; - } + return false; } // Use a temporary bag so we don't have to refilter pre-existing diagnostics. @@ -1016,12 +1018,8 @@ internal override bool CompileMethods(CommonPEModuleBuilder moduleBuilder, bool bool hasMethodBodyErrorOrWarningAsError = !FilterAndAppendAndFreeDiagnostics(diagnostics, ref methodBodyDiagnosticBag, cancellationToken); - if (hasDeclarationErrors || hasMethodBodyErrorOrWarningAsError) - { - return false; - } - - return true; + var hasErrors = hasDeclarationErrors || hasMethodBodyErrorOrWarningAsError; + return !hasErrors; } catch (Exception ex) { diff --git a/src/Aquila.CodeAnalysis/Compilation/CompilationState.cs b/src/Aquila.CodeAnalysis/Compilation/CompilationState.cs new file mode 100644 index 000000000..69cdb6f40 --- /dev/null +++ b/src/Aquila.CodeAnalysis/Compilation/CompilationState.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Aquila.CodeAnalysis.Symbols; + +namespace Aquila.CodeAnalysis; + + +/// +/// Compilation state. +/// +internal sealed class CompilationState +{ + private readonly List _methodsToEmit = new(); + + public IEnumerable MethodsToEmit => _methodsToEmit; + + public void RegisterMethodToEmit(SourceMethodSymbolBase method) + { + _methodsToEmit.Add(method); + } +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs b/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs index d6263b010..1b159b640 100644 --- a/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs +++ b/src/Aquila.CodeAnalysis/Compilation/SourceCompiler.cs @@ -2,7 +2,6 @@ using Aquila.CodeAnalysis.Symbols; using Aquila.CodeAnalysis.Utilities; using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -19,7 +18,6 @@ using Aquila.CodeAnalysis.Semantics.Graph; using Aquila.CodeAnalysis.Symbols.Source; using Aquila.CodeAnalysis.Symbols.Synthesized; -using SourceMethodSymbol = Aquila.CodeAnalysis.Symbols.SourceMethodSymbol; namespace Aquila.CodeAnalysis { @@ -33,8 +31,9 @@ internal class SourceCompiler readonly bool _emittingPdb; readonly DiagnosticBag _diagnostics; readonly CancellationToken _cancellationToken; - - readonly Worklist _worklist; + readonly CompilationState _compilationState = new(); + + private readonly Worklist _worklist; /// /// Number of control flow graph transformation cycles to do at most. @@ -51,6 +50,8 @@ private SourceCompiler(AquilaCompilation compilation, PEModuleBuilder moduleBuil Contract.ThrowIfNull(diagnostics); _compilation = compilation; + _compilation.EnsureSourceAssembly(); + _moduleBuilder = moduleBuilder; _emittingPdb = emittingPdb; _diagnostics = diagnostics; @@ -63,10 +64,11 @@ private SourceCompiler(AquilaCompilation compilation, PEModuleBuilder moduleBuil void WalkSourceMethods(Action action, bool allowParallel = false) { var methods = _compilation.SourceSymbolCollection.GetSourceMethods(); - var viewMethods = _compilation.SourceSymbolCollection.GetViewTypes().SelectMany(x=>x.GetMembers().OfType()); + var viewMethods = _compilation.SourceSymbolCollection.GetViewTypes().SelectMany(x => + x.GetMembers().OfType()); + + methods = methods.Union(viewMethods).Union(_compilationState.MethodsToEmit); - methods = methods.Union(viewMethods); - if (ConcurrentBuild && allowParallel) { Parallel.ForEach(methods, action); @@ -90,7 +92,7 @@ void WalkSynthesizedMethods(Action action, bool allowPa var viewMethods = _compilation.SourceSymbolCollection.GetViewTypes() .SelectMany(x => x.GetMembers().OfType()); - + var methods = platformSynth.Union(moduleMethods).Union(moduleNestedTypesMethods).Union(viewMethods); if (ConcurrentBuild && allowParallel) @@ -106,7 +108,7 @@ void WalkSynthesizedMethods(Action action, bool allowPa void WalkTypes(Action action, bool allowParallel = false) { var types = _compilation.SourceSymbolCollection.GetModuleTypes(); - + if (ConcurrentBuild && allowParallel) { Parallel.ForEach(types, action); @@ -126,10 +128,9 @@ 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 => { @@ -146,7 +147,7 @@ void EnqueueMethod(SourceMethodSymbolBase method) void EnqueueExpression(BoundExpression expression) { Contract.ThrowIfNull(expression); - + var dummy = new BoundBlock() { FlowState = new FlowState(new FlowContext(null)), @@ -157,100 +158,22 @@ void EnqueueExpression(BoundExpression expression) _worklist.Enqueue(dummy); } - internal void ReanalyzeMethods() - { - this.WalkSourceMethods(method => _worklist.Enqueue(method.ControlFlowGraph.Start)); - } - internal void AnalyzeMethods() { // analyse blocks _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.FlowState)); + block.Accept(AnalysisFactory()); } - GraphVisitor AnalysisFactory(FlowState state) + GraphVisitor AnalysisFactory() { return new ExpressionAnalysis(_worklist, _compilation.GlobalSemantics); } - #region Nested class: LateStaticCallsLookup - - /// - /// Lookups self:: and parent:: static method calls. - /// - class LateStaticCallsLookup : GraphExplorer - { - List _lazyStaticCalls; - - public static IList GetSelfStaticCalls(BoundBlock block) - { - var visitor = new LateStaticCallsLookup(); - visitor.Accept(block); - return (IList)visitor._lazyStaticCalls ?? Array.Empty(); - } - } - - #endregion - - /// - /// Walks static methods that don't use late static binding and checks if it should forward the late static type; - /// hence it must know the late static as well. - /// - void ForwardLateStaticBindings() - { - var calls = new ConcurrentBag>(); - - // collect self:: or parent:: static calls - this.WalkSourceMethods(method => - { - if (method is SourceMethodSymbol caller && caller.IsStatic && - (caller.Flags & MethodFlags.UsesLateStatic) == 0) - { - var cfg = caller.ControlFlowGraph; - if (cfg == null) - { - return; - } - - // has self:: or parent:: call to a method? - var selfcalls = LateStaticCallsLookup.GetSelfStaticCalls(cfg.Start); - if (selfcalls.Count == 0) - { - return; - } - - foreach (var callee in selfcalls) - { - calls.Add(new KeyValuePair(caller, callee)); - } - } - }, allowParallel: ConcurrentBuild); - - // process edges between caller and calles until we forward all the late static calls - int forwarded; - do - { - forwarded = 0; - Parallel.ForEach(calls, edge => - { - if ((edge.Key.Flags & MethodFlags.UsesLateStatic) == 0) - { - edge.Key.Flags |= MethodFlags.UsesLateStatic; - Interlocked.Increment(ref forwarded); - } - }); - } while (forwarded != 0); - } - internal void DiagnoseMethods() { this.WalkSourceMethods(DiagnoseMethod, allowParallel: true); @@ -267,13 +190,13 @@ private void DiagnoseTypes() { this.WalkTypes(DiagnoseType, allowParallel: true); } - + private void DiagnoseType(SourceModuleTypeSymbol type) { type.GetDiagnostics(_diagnostics); } - bool TransformMethods(bool allowParallel) + private bool TransformMethods(bool allowParallel) { bool anyTransforms = false; var delayedTrn = new DelayedTransformations(); @@ -314,14 +237,14 @@ void EmitMethodBody(SourceMethodSymbolBase method) { Contract.ThrowIfNull(method); - if (method.ControlFlowGraph != null) // non-abstract method - { - Debug.Assert(method.ControlFlowGraph.Start.FlowState != null); + var cfg = method.ControlFlowGraph; + if (cfg == null) return; - var body = MethodGenerator.GenerateMethodBody(_moduleBuilder, method, 0, null, _diagnostics, - _emittingPdb); - _moduleBuilder.SetMethodBody(method, body); - } + Debug.Assert(cfg.Start.FlowState != null); + + var body = MethodGenerator.GenerateMethodBody(_moduleBuilder, method, 0, null, _diagnostics, + _emittingPdb); + _moduleBuilder.SetMethodBody(method, body); } void CompileEntryPoint() @@ -344,7 +267,6 @@ bool MakeLoweringTransformMethods(bool allowParallel) bool anyTransforms = false; this.WalkSourceMethods(m => { - // Cannot be simplified due to multithreading ('=' is atomic unlike '|=') if (LocalRewriter.TryTransform(m)) anyTransforms = true; }, @@ -354,16 +276,17 @@ bool MakeLoweringTransformMethods(bool allowParallel) } + private void InvalidateAndEnqueue(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(InvalidateAndEnqueue, allowParallel: true); } } @@ -371,32 +294,20 @@ bool RewriteMethods() { using (_compilation.StartMetric("transform")) { - if (TransformMethods(ConcurrentBuild)) - { - WalkSourceMethods(m => - { - m.ControlFlowGraph?.FlowContext?.InvalidateAnalysis(); - EnqueueMethod(m); - }, - allowParallel: true); - } - else + if (!TransformMethods(ConcurrentBuild)) { - // No changes performed => no need to repeat the analysis return false; } + + WalkSourceMethods(InvalidateAndEnqueue, allowParallel: true); } - // 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); @@ -428,20 +339,6 @@ public static IEnumerable BindAndAnalyze(AquilaCompilation compilati // Analyze Operations compiler.AnalyzeMethods(); } - - using (compilation.StartMetric("lowering")) - { - // Lowering methods - compiler.LoweringMethods(); - } - - using (compilation.StartMetric(nameof(ForwardLateStaticBindings))) - { - // Forward the late static type if needed - compiler.ForwardLateStaticBindings(); - } - - // Transform Semantic Trees for Runtime Optimization } while ( transformation++ < compiler.MaxTransformCount // limit number of lowering cycles && !cancellationToken.IsCancellationRequested // user canceled ? @@ -493,24 +390,31 @@ public static void CompileSources( diagnostics.AddRange(declarationDiagnostics); // cancel the operation if there are errors - if (hasDeclarationErrors || declarationDiagnostics.HasAnyErrors() || cancellationToken.IsCancellationRequested) + if (hasDeclarationErrors || declarationDiagnostics.HasAnyErrors() || + cancellationToken.IsCancellationRequested) { return; } } - // var compiler = new SourceCompiler(compilation, moduleBuilder, emittingPdb, diagnostics, cancellationToken); + using (compilation.StartMetric("lowering")) + { + // Lowering methods + compiler.LoweringMethods(); + } + + using (compilation.StartMetric("lowering-rewrite")) + { + compiler.WalkSourceMethods(m => { LambdaRewriter.Transform(m, moduleBuilder, compiler._compilationState); }, allowParallel: false); + } + using (compilation.StartMetric("emit")) { - // Emit method bodies - // a. declared methods - // b. synthesized symbols compiler.EmitMethodBodies(); compiler.EmitSynthesized(); - // Entry Point (.exe) compiler.CompileEntryPoint(); } } diff --git a/src/Aquila.CodeAnalysis/Compilation/SynthesizedManager.cs b/src/Aquila.CodeAnalysis/Compilation/SynthesizedManager.cs index 434b2c9aa..29a30b01f 100644 --- a/src/Aquila.CodeAnalysis/Compilation/SynthesizedManager.cs +++ b/src/Aquila.CodeAnalysis/Compilation/SynthesizedManager.cs @@ -20,14 +20,9 @@ namespace Aquila.CodeAnalysis.Emit /// internal class SynthesizedManager { - readonly PEModuleBuilder _module; - - private List _namespaces = new List(); - - public AquilaCompilation DeclaringCompilation => _module.Compilation; - - readonly ConcurrentDictionary> _membersByType = - new ConcurrentDictionary>(); + private readonly List _namespaces = new(); + private readonly PEModuleBuilder _module; + private readonly ConcurrentDictionary> _membersByType = new(); public SynthesizedManager(PEModuleBuilder module) { @@ -36,6 +31,8 @@ public SynthesizedManager(PEModuleBuilder module) _module = module; } + public AquilaCompilation DeclaringCompilation => _module.Compilation; + public ImmutableArray Namespaces => _namespaces.ToImmutableArray().CastArray(); @@ -46,9 +43,16 @@ public SynthesizedTypeSymbol SynthesizeType(NamespaceOrTypeSymbol container, str var type = new SynthesizedTypeSymbol(container, DeclaringCompilation); type.SetName(name); - if (container is SynthesizedNamespaceSymbol ns) + switch (container) { - ns.AddType(type); + case SynthesizedNamespaceSymbol ns: + ns.AddType(type); + break; + case NamedTypeSymbol typeContainer: + AddMemberCore(typeContainer, type); + break; + default: + throw new InvalidOperationException(); } return type; @@ -63,14 +67,63 @@ public SynthesizedNamespaceSymbol SynthesizeNamespace(INamespaceSymbol container public SynthesizedMethodSymbol SynthesizeMethod(NamedTypeSymbol container) { - var method = new SynthesizedMethodSymbol(container); - return method; + return AddMemberCore(container, new SynthesizedMethodSymbol(container)); } public SynthesizedCtorSymbol SynthesizeConstructor(NamedTypeSymbol container) { - var ctor = new SynthesizedCtorSymbol(container); - return ctor; + return AddMemberCore(container, new SynthesizedCtorSymbol(container)); + } + + public SynthesizedFieldSymbol SynthesizeField(NamedTypeSymbol container) + { + return AddMemberCore(container, new SynthesizedFieldSymbol(container)); + } + + public void AddMembers(NamedTypeSymbol container, IEnumerable members) + { + foreach (var member in members) + { + if (member is not (SynthesizedMethodSymbol or SynthesizedCtorSymbol or SynthesizedFieldSymbol + or SynthesizedTypeSymbol)) + { + throw new InvalidOperationException(); + } + + AddMemberCore(container, member); + } + } + + public T GetOrCreate(NamedTypeSymbol container, string name) where T : Symbol + { + Symbol Factory() + { + return typeof(T) switch + { + var t when t == typeof(SynthesizedMethodSymbol) => this.SynthesizeMethod(container).SetName(name), + var t when t == typeof(SynthesizedCtorSymbol) => this.SynthesizeConstructor(container), + var t when t == typeof(SynthesizedFieldSymbol) => this.SynthesizeField(container).SetName(name), + var t when t == typeof(SynthesizedTypeSymbol) => this.SynthesizeType(container, name), + _ => throw new InvalidOperationException() + }; + } + + var list = EnsureList(container); + var member = list.OfType().FirstOrDefault(x => x.Name == name); + return member ?? (T)Factory(); + } + + private List EnsureList(Cci.ITypeDefinition type) + { + return _membersByType.GetOrAdd(type, (_) => new List()); + } + + private T AddMemberCore(Cci.ITypeDefinition container, T member) where T : Symbol + { + var list = EnsureList(container); + list.Add(member); + + return member; } /// @@ -85,8 +138,7 @@ public SynthesizedCtorSymbol SynthesizeConstructor(NamedTypeSymbol container) /// Enumeration of synthesized type members. public IEnumerable GetMembers(Cci.ITypeDefinition container) where T : ISymbol { - List list; - if (_membersByType.TryGetValue(container, out list) && list.Count != 0) + if (_membersByType.TryGetValue(container, out var list) && list.Count != 0) { return list.OfType(); } diff --git a/src/Aquila.CodeAnalysis/DocumentationComments/DocumentationCommentCompiler.cs b/src/Aquila.CodeAnalysis/DocumentationComments/DocumentationCommentCompiler.cs index 1466cef5d..1d9e7e7c1 100644 --- a/src/Aquila.CodeAnalysis/DocumentationComments/DocumentationCommentCompiler.cs +++ b/src/Aquila.CodeAnalysis/DocumentationComments/DocumentationCommentCompiler.cs @@ -175,12 +175,5 @@ void WriteMethod(string id, SourceMethodSymbolBase method) _writer.WriteLine(""); } - - void WriteMethod(SourceMethodSymbolBase method) - { - if (method.IsGlobalScope) return; // global code have no XML annotation - - WriteMethod(CommentIdResolver.GetId(method), method); - } } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Emitter/Model/PhpRootModuleType.cs b/src/Aquila.CodeAnalysis/Emitter/Model/AquilaRootModuleType.cs similarity index 97% rename from src/Aquila.CodeAnalysis/Emitter/Model/PhpRootModuleType.cs rename to src/Aquila.CodeAnalysis/Emitter/Model/AquilaRootModuleType.cs index acf277d85..08ff68c56 100644 --- a/src/Aquila.CodeAnalysis/Emitter/Model/PhpRootModuleType.cs +++ b/src/Aquila.CodeAnalysis/Emitter/Model/AquilaRootModuleType.cs @@ -1,6 +1,4 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -#nullable enable +#nullable enable using System; using System.Collections.Generic; diff --git a/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs b/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs index ddea11c9b..e2f5eb824 100644 --- a/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs +++ b/src/Aquila.CodeAnalysis/Errors/ErrorCode.cs @@ -21,375 +21,210 @@ 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 - // - - //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, - - //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, - - /// Call to a member function {0} on {1} - ERR_MethodCalledOnNonObject, - - /// Value of type {0} cannot be passed by reference - ERR_ValueOfTypeCannotBeAliased, - - /// "Cannot instantiate {0} {1}", e.g. "interface", the type name - ERR_CannotInstantiateType, - - /// "{0} cannot use {1} - it is not a trait" - ERR_CannotUseNonTrait, - - /// "Class {0} cannot extend from {1} {2}", e.g. from trait T - ERR_CannotExtendFrom, - - /// "{0} cannot implement {1} - it is not an interface" - ERR_CannotImplementNonInterface, - - /// Cannot re-assign $this - ERR_CannotAssignToThis, - - /// {0}() cannot declare a return type - ERR_CannotDeclareReturnType, - - /// A void function must not return a value - ERR_VoidFunctionCannotReturnValue, - - /// {0} {1}() must take exactly {2} arguments - ERR_MustTakeArgs, - - /// Function name must be a string, {0} given - ERR_InvalidFunctionName, - - /// Cannot use the final modifier on an abstract class - ERR_FinalAbstractClassDeclared, - - /// Access level to {0}::${1} must be {2} (as in class {3}) or weaker - ERR_PropertyAccessibilityError, - - /// Use of primitive type '{0}' is misused - ERR_PrimitiveTypeNameMisused, - - /// Missing value for '{0}' option - ERR_SwitchNeedsValue, - - /// '{0}' not in the 'loop' or 'switch' context - ERR_NeedsLoopOrSwitch, - - /// Provided source code kind is unsupported or invalid: '{0}' - ERR_BadSourceCodeKind, - - /// Provided documentation mode is unsupported or invalid: '{0}'. - ERR_BadDocumentationMode, - - /// Compilation options '{0}' and '{1}' can't both be specified at the same time. - ERR_MutuallyExclusiveOptions, - - /// Invalid instrumentation kind: {0} - ERR_InvalidInstrumentationKind, - - /// Invalid hash algorithm name: '{0}' - ERR_InvalidHashAlgorithmName, - - /// Option '{0}' must be an absolute path. - ERR_OptionMustBeAbsolutePath, - - /// Cannot emit debug information for a source text without encoding. - ERR_EncodinglessSyntaxTree, - - /// An error occurred while writing the output file: {0}. - ERR_PeWritingFailure, - - /// Failed to emit module '{0}'. - ERR_ModuleEmitFailure, - - /// Cannot update '{0}'; attribute '{1}' is missing. - ERR_EncUpdateFailedMissingAttribute, - /// Unable to read debug information of method '{0}' (token 0x{1:X8}) from assembly '{2}' - ERR_InvalidDebugInfo, + #endregion - /// Invalid assembly name: {0} - ERR_BadAssemblyName, + #region 4xxx Errors - /// /embed switch is only supported when emitting Portable PDB (/debug:portable or /debug:embedded). - ERR_CannotEmbedWithoutPdb, + #region Syntax - /// No overload for method {0} can be called. - ERR_NoMatchingOverload, - - /// Default value for parameter ${0} with a {1} type can only be {1} or NULL, {2} given - ERR_DefaultParameterValueTypeMismatch, - - /// Constant expression contains invalid operations - ERR_InvalidConstantExpression, - - /// Using $this when not in object context - ERR_ThisOutOfObjectContext, - - /// Cannot set read-only property {0}::${1} - ERR_ReadOnlyPropertyWritten, - - /// Only the last parameter can be variadic - ERR_VariadicParameterNotLast, - ERR_CtorPropertyVariadic, - ERR_CtorPropertyAbstractCtor, - ERR_CtorPropertyNotCtor, - ERR_CtorPropertyStaticCtor, - - /// Property {0}::${1} cannot have type {2} - ERR_PropertyTypeNotAllowed, - - /// Multiple analyzer config files cannot be in the same directory ('{0}'). - ERR_MultipleAnalyzerConfigsInSameDir, - - /// Method '{0}' not found for type {1}. - ERR_MethodNotFound, - - ERR_MissingIdentifierSymbol, + 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, + ERR_TypeNameCannotBeResolved = 4123, // Cannot use positional argument after argument unpacking + + ERR_InvalidMetadataConsistance = 4125, + ERR_CannotInstantiateType = 4128, + ERR_CannotAssignToThis = 4132, + ERR_PrimitiveTypeNameMisused = 4139, + ERR_SwitchNeedsValue = 4140, + ERR_NeedsLoopOrSwitch = 4141, + ERR_BadSourceCodeKind = 4142, + ERR_BadDocumentationMode = 4143, + ERR_MutuallyExclusiveOptions = 4144, + ERR_InvalidInstrumentationKind = 4145, + ERR_InvalidHashAlgorithmName = 4146, + ERR_OptionMustBeAbsolutePath = 4147, + ERR_EncodinglessSyntaxTree = 4148, + ERR_PeWritingFailure = 4149, + ERR_ModuleEmitFailure = 4150, + ERR_EncUpdateFailedMissingAttribute = 4151, + ERR_InvalidDebugInfo = 4152, + ERR_BadAssemblyName = 4153, + ERR_CannotEmbedWithoutPdb = 4154, + ERR_InvalidConstantExpression = 4157, + ERR_ReadOnlyPropertyWritten = 4159, + ERR_MultipleAnalyzerConfigsInSameDir = 4166, + ERR_MethodNotFound = 4167, + ERR_MissingIdentifierSymbol = 4168, + ERR_CantResolveSymbol = 4169, + ERR_AmbiguousName = 4170, + ERR_UndefinedLocal = 4171, + ERR_UndefinedIdentifier = 4172, + ERR_BadArity = 4173, + #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, - - /// The declaration of class, interface or trait is ambiguous since its base types cannot be resolved. - WRN_AmbiguousDeclaration, - WRN_UnreachableCode, - WRN_NotYetImplementedIgnored, - WRN_NoSourceFiles, - - /// {0}() expects {1} parameter(s), {2} given - WRN_TooManyArguments, - - /// {0}() expects at least {1} parameter(s), {2} given - WRN_MissingArguments, - - /// Assertion will always fail - WRN_AssertAlwaysFail, - - /// Using string as the assertion is deprecated - WRN_StringAssertionDeprecated, - - /// Deprecated: {0} '{1}' has been deprecated. {2} - WRN_SymbolDeprecated, - - /// The expression is not being read. Did you mean to assign it somewhere? - WRN_ExpressionNotRead, + WRN_AnalyzerCannotBeCreated = 5001, + WRN_NoAnalyzerInAssembly = 5002, + WRN_NoConfigNotOnCommandLine = 5003, + WRN_PdbLocalNameTooLong = 5004, + WRN_PdbUsingNameTooLong = 5005, + WRN_UnableToLoadAnalyzer = 5006, + WRN_UninitializedVariableUse = 5008, + WRN_UndefinedType = 5009, + WRN_UnreachableCode = 5012, + WRN_NoSourceFiles = 5014, + WRN_FormatStringWrongArgCount = 5026, + WRN_ParentCtorNotCalled = 5027, + WRN_GeneratorFailedDuringInitialization = 5034, + WRN_GeneratorFailedDuringGeneration = 5035, + + #endregion + + #region 6xxx Visible information - /// Assignment made to same variable; did you mean to assign something else? - WRN_AssigningSameVariable, - - /// Invalid array key type: {0}. - WRN_InvalidArrayKeyType, - - /// Duplicate array key: '{0}'. - WRN_DuplicateArrayKey, - - /// Cloning of non-object: {0}. - WRN_CloneNonObject, - - /// Using non-iterable type in foreach: {0}. - WRN_ForeachNonIterable, - - /// Call to '{0}()' expects {1} argument(s), {2} given. - WRN_FormatStringWrongArgCount, - - /// Missing the call of parent::__construct from {0}::__construct. - WRN_ParentCtorNotCalled, - - /// Method {0}::__toString() must return a string value - WRN_ToStringMustReturnString, - - /// Argument has no value, parameter will be always NULL - WRN_ArgumentVoid, - - /// PCRE pattern parse error: {0} at offset {1} - WRN_PCRE_Pattern_Error, - - /// {0} '{1}' is already defined - WRN_TypeNameInUse, - - /// Script file '{0}' could not be resolved, the script inclusion is unbound. - WRN_CannotIncludeFile, - - /// Called from the global scope - WRN_CalledFromGlobalScope, - - /// 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, - - /// 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, - - // - // Visible information - // INF_UnableToLoadSomeTypesInAnalyzer = 6000, - INF_EvalDiscouraged, - INF_RedundantCast, - - /// Name '{0}' does not match the expected name '{1}', letter casing mismatch. - INF_TypeNameCaseMismatch, - - /// - INF_DestructDiscouraged, - - /// Overriden function name '{0}' does not match it's parent name '{1}', letter casing mismatch. - INF_OverrideNameCaseMismatch, + INF_TypeNameCaseMismatch = 6003, - /// The symbol can not been resolved - INF_CantResolveSymbol + #endregion } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs index e2d6c2af3..e4af66821 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/ExpressionAnalysis.cs @@ -40,42 +40,6 @@ readonly ISymbolProvider #endregion - #region Helpers - - /// - /// In case of a local variable or parameter, gets its name. - /// - VariableName AsVariableName(BoundReferenceEx r) - { - if (r is BoundVariableRef vr) - { - return vr.Name.NameValue; - } - - return default; - } - - /// - /// Gets current visibility scope. - /// - protected OverloadsList.VisibilityScope VisibilityScope => new(Method.ContainingType, Method); - - protected void PingSubscribers(ExitBlock exit) - { - if (exit != null) - { - var wasNotAnalysed = false; - - if (Method != null && !Method.IsReturnAnalysed) - { - Method.IsReturnAnalysed = true; - wasNotAnalysed = true; - } - } - } - - #endregion - #region Construction /// @@ -105,7 +69,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); @@ -134,7 +98,7 @@ public override T VisitStaticVarStmt(BoundStaticVarStmt x) var v = x.Declaration; var local = State.GetLocalHandle(new VariableName(v.Name)); - var oldtype = State.GetLocalType(local); + var oldType = State.GetLocalType(local); // set var if (v.InitialValue != null) @@ -146,18 +110,18 @@ public override T VisitStaticVarStmt(BoundStaticVarStmt x) State.SetLessThanLongMax(local, isInt && intVal < long.MaxValue); State.SetGreaterThanLongMin(local, isInt && intVal > long.MinValue); - State.SetLocalType(local, oldtype); + State.SetLocalType(local, oldType); } else { State.SetLessThanLongMax(local, false); State.SetGreaterThanLongMin(local, false); - State.SetLocalType(local, oldtype); - // TODO: explicitly State.SetLocalUninitialized() ? + State.SetLocalType(local, oldType); } return default; } + #endregion #region Visit Literals @@ -211,52 +175,28 @@ public override T VisitCompoundAssignEx(BoundCompoundAssignEx x) return default; } - protected virtual void VisitSuperglobalVariableRef(BoundVariableRef x) - { - } - protected virtual void VisitLocalVariableRef(BoundVariableRef x, VariableHandle local) { Debug.Assert(local.IsValid); if (Method == null) { - // invalid use of variable: return; } - var previoustype = State.GetLocalType(local); // type of the variable in the previous state - - - // bind variable place - if (x.Variable == null) + if (!Method.LocalsTable.TryGetVariable(local.Name, out var localVar)) { - if (Method.LocalsTable.TryGetVariable(local.Name, out var localVar)) - x.Variable = localVar; + return; } + + FlowState.VisitLocal(local); - // - State.VisitLocal(local); + x.Variable ??= localVar; } public override T VisitVariableRef(BoundVariableRef x) { - if (x.Name.IsDirect) - { - // direct variable access: - if (x.Name.NameValue.IsAutoGlobal) - { - VisitSuperglobalVariableRef(x); - } - else - { - VisitLocalVariableRef(x, State.GetLocalHandle(x.Name.NameValue)); - } - } - else - { - } - + VisitLocalVariableRef(x, State.GetLocalHandle(x.Name.NameValue)); return default; } @@ -572,6 +512,7 @@ public override T VisitConversionEx(BoundConversionEx x) break; } } + return default; } @@ -591,8 +532,6 @@ public override T VisitTypeRef(BoundTypeRef tref) #endregion - #region Visit Function Call - public override T VisitCallEx(BoundCallEx arg) { if (arg.Instance != null) @@ -603,7 +542,12 @@ public override T VisitCallEx(BoundCallEx arg) return base.VisitCallEx(arg); } - #endregion + public override T VisitFuncEx(BoundFuncEx x) + { + Debug.Assert(x.LambdaSymbol.ControlFlowGraph != null); + EnqueueBlock(x.LambdaSymbol.ControlFlowGraph.Start); + return default; + } #region Visit FieldRef @@ -643,10 +587,6 @@ public override T VisitArrayItemOrdEx(BoundArrayItemOrdEx x) #endregion - #region VisitLambda - - #endregion - #region VisitYield public override T VisitYieldStmt(BoundYieldStmt x) @@ -702,14 +642,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..4accb6172 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; @@ -13,104 +13,61 @@ namespace Aquila.CodeAnalysis.FlowAnalysis /// public class FlowContext { - internal class TypeRefInfo + internal class VariableInfo { - private readonly TypeSymbol _symbol; - /// - /// Type was passed by reference + /// Variable passed by reference /// private bool _byReference; - public TypeRefInfo(TypeSymbol symbol) - { - _symbol = symbol; - } - public bool ByRef => _byReference; internal void SetByRef(bool value) => _byReference = value; } - #region Constants + private int _version; + private readonly SourceMethodSymbolBase _method; + private VariableInfo[] _varsInfo = Array.Empty(); + + internal FlowContext(SourceMethodSymbolBase method) + { + _method = method; + _varsIndex = new Dictionary(); + } /// /// Size of ulong bit array (64). /// internal const int BitsCount = sizeof(ulong) * 8; - #endregion - - #region Fields & Properties - - /// - /// Associated type context. - /// - public TypeRefContext TypeRefContext => _typeCtx; - - readonly TypeRefContext - _typeCtx; - /// /// 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 VariableInfo[] VarsInfo => _varsInfo; /// /// 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 < _varsInfo.Length) + { + _varsInfo[varIndex] = new VariableInfo(); + } } - #endregion - - #region Public Methods - /// /// Gets index of variable within the context. /// @@ -118,93 +75,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 = _varsInfo.Length; + Array.Resize(ref _varsInfo, 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 < _varsInfo.Length) { - Slot = pair.Value, - Name = pair.Key, - }); - } - - public void SetReference(int varindex) - { - if (varindex >= 0 && varindex < _varsType.Length) - { - _varsType[varindex].SetByRef(true); + _varsInfo[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); - } - } - - 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; + return varIndex < 0 || varIndex >= _varsInfo.Length || _varsInfo[varIndex].ByRef; } - - 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 +121,16 @@ public void InvalidateAnalysis() _version++; // Reset internal structures to prevent possible bugs in re-analysis - _usedMask = 0; _varsIndex.Clear(); - _varsType = Array.Empty(); + _varsInfo = Array.Empty(); - // 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..bd9630aae 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/FlowState.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/FlowState.cs @@ -25,7 +25,7 @@ internal class FlowState : IEquatable /// /// Types of variables in this state. /// - TypeSymbol[] _varsType = new TypeSymbol[0]; + private TypeSymbol[] _varsType = Array.Empty(); /// /// Mask of initialized variables in this state. @@ -81,7 +81,7 @@ internal FlowState(FlowContext flowCtx) // initial size of the array var countHint = (flowCtx.Method != null) - ? flowCtx.VarsType.Length + ? flowCtx.VarsInfo.Length : 0; _varsType = new TypeSymbol[countHint]; @@ -176,15 +176,14 @@ public VariableHandle GetLocalHandle(VariableName varname) public TypeSymbol GetLocalType(VariableHandle handle) { - return null; + return _varsType[handle]; } /// /// Sets variable type in this state. /// /// Variable handle. - /// Variable type. If uninitialized, the variable is set as not initialized in this state. - public void SetLocalType(VariableHandle handle, TypeSymbol tmask) + public void SetLocalType(VariableHandle handle, TypeSymbol type) { handle.ThrowIfInvalid(); @@ -193,52 +192,20 @@ public void SetLocalType(VariableHandle handle, TypeSymbol tmask) Array.Resize(ref _varsType, handle + 1); } - _varsType[handle] = tmask; + _varsType[handle] = type; - this.FlowContext.AddVarType(handle, tmask); // TODO: collect merged type information at the end of analysis + this.FlowContext.AddVarType(handle, type); // update the _initializedMask SetVarInitialized(handle); } - /// - /// 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. - /// - public void MarkLocalByRef(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) - { - handle.ThrowIfInvalid(); - FlowContext.SetUsed(handle); - } - - /// - /// Gets value indicating the variable may be set in some code paths. - /// Gets also true if we don't known. - /// - public bool IsLocalSet(VariableHandle handle) + public static void VisitLocal(VariableHandle handle) { handle.ThrowIfInvalid(); - return handle.Slot >= FlowContext.BitsCount || (_initializedMask & (1ul << handle)) != 0; } public void SetVarInitialized(VariableHandle handle) 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/Passes/DiagnosticWalker.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/DiagnosticWalker.cs index 415817174..0d00fdb82 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/DiagnosticWalker.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/DiagnosticWalker.cs @@ -194,14 +194,6 @@ public override T VisitVariableRef(BoundVariableRef x) return base.VisitVariableRef(x); } - public override T VisitTemporalVariableRef(BoundTemporalVariableRef x) - { - // do not make diagnostics on syntesized variables - return default; - } - - - public override T VisitUnaryEx(BoundUnaryEx x) { base.VisitUnaryEx(x); diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.CopyAnalysis.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.CopyAnalysis.cs index e069ee17d..74446dbd1 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.CopyAnalysis.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.CopyAnalysis.cs @@ -135,7 +135,7 @@ private class CopyAnalysis : AnalysisWalker private BitMask64 _neededCopies; - private int VariableCount => _flowContext.VarsType.Length; + private int VariableCount => _flowContext.VarsInfo.Length; private Dictionary _blockToStateMap = new Dictionary(); @@ -228,16 +228,13 @@ private VariableHandle ProcessAssignment(BoundAssignEx assign) { bool CheckVariable(BoundVariableRef varRef, out VariableHandle handle) { - if (varRef.Name.IsDirect && !varRef.Name.NameValue.IsAutoGlobal - && !_flowContext.IsReference(handle = _flowContext.GetVarIndex(varRef.Name.NameValue))) + if (!_flowContext.IsReference(handle = _flowContext.GetVarIndex(varRef.Name.NameValue))) { return true; } - else - { - handle = default; - return false; - } + + handle = default; + return false; } bool MatchSourceVarOrNestedAssignment(BoundExpression expr, out VariableHandle handle, out bool isCopied) @@ -297,56 +294,6 @@ bool MatchSourceVarOrNestedAssignment(BoundExpression expr, out VariableHandle h return default; } - public override VoidStruct VisitVariableRef(BoundVariableRef x) - { - void MarkAllKnownAssignments() - { - for (int i = 0; i < State.VariableCount; i++) - { - _neededCopies |= State.GetValue(i); - } - } - - base.VisitVariableRef(x); - - // If a variable is modified, disable the deletion of all its current assignments - if (x.Access.MightChange) - { - if (!x.Name.IsDirect) - { - MarkAllKnownAssignments(); - } - else if (!x.Name.NameValue.IsAutoGlobal) - { - var varindex = _flowContext.GetVarIndex(x.Name.NameValue); - if (!_flowContext.IsReference(varindex)) - { - _neededCopies |= State.GetValue(varindex); - } - else - { - // TODO: Mark only those that can be referenced - MarkAllKnownAssignments(); - } - } - } - - return default; - } - - public override VoidStruct VisitReturnStmt(BoundReturnStmt x) - { - if (x.Returned is BoundCopyValue copy && copy.Expression is BoundVariableRef varRef && - - !varRef.Name.NameValue.IsAutoGlobal && - varRef.Name.IsDirect) - { - Add(ref _lazyReturnCopies, copy); - } - - return base.VisitReturnStmt(x); - } - public override VoidStruct VisitCFGExitBlock(ExitBlock x) { base.VisitCFGExitBlock(x); diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.ParameterAnalysis.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.ParameterAnalysis.cs index b3e88bd93..7f68d05c0 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.ParameterAnalysis.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.ParameterAnalysis.cs @@ -122,8 +122,7 @@ public override VoidStruct VisitArgument(BoundArgument x) if (State != ParameterAnalysisState.Dirty && x.Value is BoundVariableRef varRef - && varRef.Name.IsDirect - && !_flowContext.IsReference(varindex = _flowContext.GetVarIndex(varRef.Name.NameValue)) + && !_flowContext.IsReference(_flowContext.GetVarIndex(varRef.Name.NameValue)) && !varRef.Access.MightChange) { // Passing a parameter as an argument by value to another method is a safe use which does not @@ -138,27 +137,19 @@ public override VoidStruct VisitArgument(BoundArgument x) public override VoidStruct VisitVariableRef(BoundVariableRef x) { - // Other usage than being passed as an argument to another function requires a parameter to be deeply copied - if (!x.Name.IsDirect) + var varindex = _flowContext.GetVarIndex(x.Name.NameValue); + if (!_flowContext.IsReference(varindex)) { - // In the worst case, any variable can be targeted - _needPassValueParams.SetAll(); + // Mark only the specific variable as possibly being changed + _needPassValueParams.Set(varindex); } else { - var varindex = _flowContext.GetVarIndex(x.Name.NameValue); - if (!_flowContext.IsReference(varindex)) - { - // Mark only the specific variable as possibly being changed - _needPassValueParams.Set(varindex); - } - else - { - // TODO: Mark only those that can be referenced - _needPassValueParams.SetAll(); - } + // TODO: Mark only those that can be referenced + _needPassValueParams.SetAll(); } + return base.VisitVariableRef(x); } diff --git a/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.cs b/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.cs index 0f8f8015d..090b8e846 100644 --- a/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.cs +++ b/src/Aquila.CodeAnalysis/FlowAnalysis/Passes/TransformationRewriter.cs @@ -39,16 +39,14 @@ public static bool TryTransform(DelayedTransformations delayedTransformations, S // var rewriter = new TransformationRewriter(delayedTransformations, method); - var currentCFG = method.ControlFlowGraph; - var updatedCFG = (ControlFlowGraph)rewriter.VisitCFG(currentCFG); - + var currentCfg = method.ControlFlowGraph; + var updatedCfg = (ControlFlowGraph)rewriter.VisitCFG(currentCfg); + rewriter.TryTransformParameters(); - method.ControlFlowGraph = updatedCFG; + method.ControlFlowGraph = updatedCfg; - Debug.Assert(updatedCFG == currentCFG || - rewriter.TransformationCount != - 0); // cfg updated => transformations (not <= due to parameter transformations) - return updatedCFG != currentCFG; + Debug.Assert(updatedCfg == currentCfg || rewriter.TransformationCount != 0); + return updatedCfg != currentCfg; } private TransformationRewriter() @@ -88,7 +86,7 @@ protected override void OnVisitCFG(ControlFlowGraph x) Debug.Assert(_method.ControlFlowGraph == x); } - private protected override void OnUnreachableMethodFound(SourceMethodSymbolBase method) + private protected virtual void OnUnreachableMethodFound(SourceMethodSymbolBase method) { _delayedTransformations.UnreachableMethods.Add(method); } 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..9441b0681 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, @@ -49,7 +50,7 @@ public enum BoundKind FieldRef, ListEx, VariableRef, - TemporalVariableRef, + MethodRef, PropertyRef, Argument, MethodName, @@ -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,24 +1567,72 @@ internal BoundBadEx Update(ITypeSymbol resultType) } } +namespace Aquila.CodeAnalysis.Semantics +{ + partial class BoundFuncEx : BoundExpression + { + private SourceLambdaSymbol _lambdaSymbol; + internal BoundFuncEx(SourceLambdaSymbol lambdaSymbol, ITypeSymbol resultType): base(resultType) + { + _lambdaSymbol = lambdaSymbol; + OnCreateImpl(lambdaSymbol, resultType); + } + + partial void OnCreateImpl(SourceLambdaSymbol lambdaSymbol, ITypeSymbol resultType); + 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(SourceLambdaSymbol lambdaSymbol, ITypeSymbol resultType) + { + if (_lambdaSymbol == lambdaSymbol && ResultType == resultType) + return this; + return new BoundFuncEx(lambdaSymbol, resultType).WithSyntax(this.AquilaSyntax); + } + } +} + namespace Aquila.CodeAnalysis.Semantics { partial class BoundCallEx : BoundExpression { private MethodSymbol _methodSymbol; private ImmutableArray _arguments; - private ImmutableArray _typeArguments; private BoundExpression _instance; - internal BoundCallEx(MethodSymbol methodSymbol, ImmutableArray arguments, ImmutableArray typeArguments, BoundExpression instance, ITypeSymbol resultType): base(resultType) + internal BoundCallEx(MethodSymbol methodSymbol, ImmutableArray arguments, BoundExpression instance, ITypeSymbol resultType): base(resultType) { _methodSymbol = methodSymbol; _arguments = arguments; - _typeArguments = typeArguments; _instance = instance; - OnCreateImpl(methodSymbol, arguments, typeArguments, instance, resultType); + OnCreateImpl(methodSymbol, arguments, instance, resultType); } - partial void OnCreateImpl(MethodSymbol methodSymbol, ImmutableArray arguments, ImmutableArray typeArguments, BoundExpression instance, ITypeSymbol resultType); + partial void OnCreateImpl(MethodSymbol methodSymbol, ImmutableArray arguments, BoundExpression instance, ITypeSymbol resultType); internal MethodSymbol MethodSymbol { get @@ -1617,14 +1649,6 @@ public ImmutableArray Arguments } } - public ImmutableArray TypeArguments - { - get - { - return _typeArguments; - } - } - public BoundExpression Instance { get @@ -1654,11 +1678,11 @@ public override TResult Accept(AquilaOperationVisitor visitor) return visitor.VisitCallEx(this); } - internal BoundCallEx Update(MethodSymbol methodSymbol, ImmutableArray arguments, ImmutableArray typeArguments, BoundExpression instance, ITypeSymbol resultType) + internal BoundCallEx Update(MethodSymbol methodSymbol, ImmutableArray arguments, BoundExpression instance, ITypeSymbol resultType) { - if (_methodSymbol == methodSymbol && _arguments == arguments && _typeArguments == typeArguments && _instance == instance && ResultType == resultType) + if (_methodSymbol == methodSymbol && _arguments == arguments && _instance == instance && ResultType == resultType) return this; - return new BoundCallEx(methodSymbol, arguments, typeArguments, instance, resultType).WithSyntax(this.AquilaSyntax); + return new BoundCallEx(methodSymbol, arguments, instance, resultType).WithSyntax(this.AquilaSyntax); } } } @@ -1670,17 +1694,15 @@ partial class BoundNewEx : BoundExpression private MethodSymbol _methodSymbol; private ITypeSymbol _typeRef; private ImmutableArray _arguments; - private ImmutableArray _typeArguments; - internal BoundNewEx(MethodSymbol methodSymbol, ITypeSymbol typeRef, ImmutableArray arguments, ImmutableArray typeArguments, ITypeSymbol resultType): base(resultType) + internal BoundNewEx(MethodSymbol methodSymbol, ITypeSymbol typeRef, ImmutableArray arguments): base(typeRef) { _methodSymbol = methodSymbol; _typeRef = typeRef; _arguments = arguments; - _typeArguments = typeArguments; - OnCreateImpl(methodSymbol, typeRef, arguments, typeArguments, resultType); + OnCreateImpl(methodSymbol, typeRef, arguments); } - partial void OnCreateImpl(MethodSymbol methodSymbol, ITypeSymbol typeRef, ImmutableArray arguments, ImmutableArray typeArguments, ITypeSymbol resultType); + partial void OnCreateImpl(MethodSymbol methodSymbol, ITypeSymbol typeRef, ImmutableArray arguments); internal MethodSymbol MethodSymbol { get @@ -1705,14 +1727,6 @@ public ImmutableArray Arguments } } - public ImmutableArray TypeArguments - { - get - { - return _typeArguments; - } - } - public override OperationKind Kind => OperationKind.ObjectCreation; public override BoundKind BoundKind => BoundKind.NewEx; partial void AcceptImpl(OperationVisitor visitor, TArg argument, ref TRes result); @@ -1733,13 +1747,6 @@ public override TResult Accept(AquilaOperationVisitor visitor) { return visitor.VisitNewEx(this); } - - internal BoundNewEx Update(ITypeSymbol resultType) - { - if (ResultType == resultType) - return this; - return new BoundNewEx(this.MethodSymbol, this.TypeRef, this.Arguments, this.TypeArguments, resultType).WithSyntax(this.AquilaSyntax); - } } } @@ -2250,15 +2257,36 @@ internal BoundVariableRef Update(BoundVariableName name, ITypeSymbol resultType) namespace Aquila.CodeAnalysis.Semantics { - partial class BoundTemporalVariableRef : BoundVariableRef + partial class BoundMethodRef : BoundReferenceEx { - internal BoundTemporalVariableRef(BoundVariableName name, ITypeSymbol resultType): base(name, resultType) + private IMethodSymbol _method; + private BoundExpression _instance; + internal BoundMethodRef(IMethodSymbol method, BoundExpression instance, ITypeSymbol resultType): base(resultType) { - OnCreateImpl(name, resultType); + _method = method; + _instance = instance; + OnCreateImpl(method, instance, resultType); } - partial void OnCreateImpl(BoundVariableName name, ITypeSymbol resultType); - public override BoundKind BoundKind => BoundKind.TemporalVariableRef; + partial void OnCreateImpl(IMethodSymbol method, BoundExpression instance, ITypeSymbol resultType); + public IMethodSymbol Method + { + get + { + return _method; + } + } + + public BoundExpression Instance + { + get + { + return _instance; + } + } + + public override OperationKind Kind => OperationKind.None; + public override BoundKind BoundKind => BoundKind.MethodRef; partial void AcceptImpl(OperationVisitor visitor, TArg argument, ref TRes result); partial void AcceptImpl(OperationVisitor visitor); public override TRes Accept(OperationVisitor visitor, TArg argument) @@ -2275,14 +2303,14 @@ public override void Accept(OperationVisitor visitor) public override TResult Accept(AquilaOperationVisitor visitor) { - return visitor.VisitTemporalVariableRef(this); + return visitor.VisitMethodRef(this); } - internal BoundTemporalVariableRef Update(BoundVariableName name, ITypeSymbol resultType) + internal BoundMethodRef Update(ITypeSymbol resultType) { - if (Name == name && ResultType == resultType) + if (ResultType == resultType) return this; - return new BoundTemporalVariableRef(name, resultType).WithSyntax(this.AquilaSyntax); + return new BoundMethodRef(this.Method, this.Instance, resultType).WithSyntax(this.AquilaSyntax); } } } @@ -3027,12 +3055,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 +3079,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); @@ -3063,7 +3092,7 @@ abstract partial class AquilaOperationVisitor public virtual TResult VisitFieldRef(BoundFieldRef x) => VisitDefault(x); public virtual TResult VisitListEx(BoundListEx x) => VisitDefault(x); public virtual TResult VisitVariableRef(BoundVariableRef x) => VisitDefault(x); - public virtual TResult VisitTemporalVariableRef(BoundTemporalVariableRef x) => VisitDefault(x); + public virtual TResult VisitMethodRef(BoundMethodRef x) => VisitDefault(x); public virtual TResult VisitPropertyRef(BoundPropertyRef x) => VisitDefault(x); public virtual TResult VisitArgument(BoundArgument x) => VisitDefault(x); public virtual TResult VisitMethodName(BoundMethodName x) => VisitDefault(x); 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/Lowering/LambdaRewriter.cs b/src/Aquila.CodeAnalysis/Lowering/LambdaRewriter.cs new file mode 100644 index 000000000..ba8bff170 --- /dev/null +++ b/src/Aquila.CodeAnalysis/Lowering/LambdaRewriter.cs @@ -0,0 +1,104 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Aquila.CodeAnalysis.Emit; +using Aquila.CodeAnalysis.Semantics; +using Aquila.CodeAnalysis.Semantics.Graph; +using Aquila.CodeAnalysis.Symbols; +using Aquila.CodeAnalysis.Symbols.Source; +using Aquila.CodeAnalysis.Symbols.Synthesized; +using Aquila.CodeAnalysis.Syntax; +using Microsoft.CodeAnalysis; + +namespace Aquila.CodeAnalysis.Lowering; + +internal class LambdaRewriter : GraphRewriter +{ + private readonly SourceMethodSymbolBase _method; + private readonly PEModuleBuilder _moduleBuilder; + private readonly CompilationState _compilationState; + + private readonly NamedTypeSymbol _containingType; + private readonly CoreTypes _ct; + + private LambdaRewriter(SourceMethodSymbolBase method, PEModuleBuilder moduleBuilder, + CompilationState compilationState) + { + _method = method; + _moduleBuilder = moduleBuilder; + _compilationState = compilationState; + _containingType = _method.ContainingType; + _ct = moduleBuilder.Compilation.CoreTypes; + } + + public override object VisitFuncEx(BoundFuncEx x) + { + /* + 1. Create a new type-container for the lambda + Remark: For container we need decide we need Context as a argument of method or we need context + as a field of the type-container and pass it to the constructor of the type-container + 2. Create required fields in type-container + 3. Create a constructor for the type-container + 4. Create a method for the lambda and transform it (replace all variables with fields) + 5. Return a new BoundCallEx represents the constructor of the type-container + */ + var container = + _moduleBuilder.SynthesizedManager.GetOrCreate(_containingType, "LambdaContainer"); + + ImmutableArray.Builder builder = ImmutableArray.CreateBuilder(); + SourceTypeSymbolHelper.AddDefaultInstanceTypeSymbolMembers(container, builder); + var members = builder.ToImmutable(); + members.ForEach(container.AddMember); + var ctor = members.OfType().First(); + var translatedSymbol = new TranslatedLambdaMethodSymbol(container, _method, x.LambdaSymbol); + container.AddMember(translatedSymbol); + _compilationState.RegisterMethodToEmit(translatedSymbol); + _moduleBuilder.SetMethodBody(ctor, ctor.CreateMethodBody(_moduleBuilder, DiagnosticBag.GetInstance())); + + + var instance = new BoundNewEx(ctor, container, ImmutableArray.Empty); + + return new BoundMethodRef(translatedSymbol, instance, _method.GetTypeOrReturnType().GetDelegateType()); + } + + public static void Transform(SourceMethodSymbolBase sourceMethodSymbolBase, PEModuleBuilder moduleBuilder, + CompilationState state) + { + var rewriter = new LambdaRewriter(sourceMethodSymbolBase, moduleBuilder, state); + var currentCFG = sourceMethodSymbolBase.ControlFlowGraph; + var updatedCFG = (ControlFlowGraph)rewriter.VisitCFG(currentCFG); + + sourceMethodSymbolBase.ControlFlowGraph = updatedCFG; + } +} + +internal class TranslatedLambdaMethodSymbol : SourceMethodSymbolBase +{ + private readonly SourceMethodSymbolBase _lambda; + + public TranslatedLambdaMethodSymbol(Symbol containingSymbol, SourceMethodSymbolBase topLevelMethod, + SourceMethodSymbolBase lambda) : base(containingSymbol) + { + _lambda = lambda; + } + + public override Accessibility DeclaredAccessibility => Accessibility.Internal; + + public override bool IsStatic => false; + + internal override ParameterListSyntax SyntaxSignature => _lambda.SyntaxSignature; + + internal override TypeEx SyntaxReturnType => _lambda.SyntaxReturnType; + + internal override AquilaSyntaxNode Syntax => _lambda.Syntax; + + internal override IEnumerable Statements => _lambda.Statements; + + public override ControlFlowGraph ControlFlowGraph => _lambda.ControlFlowGraph; + + public override TypeSymbol ReturnType => this.DeclaringCompilation.CoreTypes.Int32.Symbol; + + public override void GetDiagnostics(DiagnosticBag diagnostic) + { + } +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Lowering/Lowering.cs b/src/Aquila.CodeAnalysis/Lowering/LocalRewriter.cs similarity index 91% rename from src/Aquila.CodeAnalysis/Lowering/Lowering.cs rename to src/Aquila.CodeAnalysis/Lowering/LocalRewriter.cs index bd840c710..6dba412fe 100644 --- a/src/Aquila.CodeAnalysis/Lowering/Lowering.cs +++ b/src/Aquila.CodeAnalysis/Lowering/LocalRewriter.cs @@ -5,7 +5,6 @@ using Aquila.CodeAnalysis.Semantics; using Aquila.CodeAnalysis.Symbols; using Aquila.CodeAnalysis.Semantics.Graph; -using Aquila.CodeAnalysis.Syntax; using Aquila.Syntax.Ast; using Microsoft.CodeAnalysis; @@ -18,18 +17,13 @@ internal class LocalRewriter : GraphRewriter protected AquilaCompilation DeclaringCompilation => _method.DeclaringCompilation; protected PrimitiveBoundTypeRefs PrimitiveBoundTypeRefs => DeclaringCompilation.TypeRefs; - private CoreTypes _ct; - private CoreMethods _cm; + private readonly CoreTypes _ct; + private readonly CoreMethods _cm; private int _tmpVariableIndex = 0; protected string NextTmpVariableName() => "'" + _tmpVariableIndex++; - private LocalRewriter() - { - } - private LocalRewriter(SourceMethodSymbolBase method) - : this() { _method = method; _ct = DeclaringCompilation.CoreTypes; @@ -64,9 +58,8 @@ public override object VisitBinaryEx(BoundBinaryEx x) var transRight = BoundArgument.Create((BoundExpression)VisitExpression(x.Right)); var args = new[] { transLeft, transRight }.ToImmutableArray(); - var typeArgs = ImmutableArray.Empty; - return new BoundCallEx(_cm.Operators.Concat_String_String, args, typeArgs, null, _ct.String.Symbol) + return new BoundCallEx(_cm.Operators.Concat_String_String, args, null, _ct.String.Symbol) .WithAccess(x); } @@ -80,8 +73,7 @@ public override object VisitAllocEx(BoundAllocEx x) var exprs = new List(); - var instance = new BoundNewEx(ctor, type, ImmutableArray.Empty, - ImmutableArray.Empty, type); + var instance = new BoundNewEx(ctor, type, ImmutableArray.Empty); var name = new VariableName(NextTmpVariableName()); var variable = _method.LocalsTable.BindTemporalVariable(name, type); @@ -120,7 +112,6 @@ public override object VisitAllocEx(BoundAllocEx x) public override object VisitMatchEx(BoundMatchEx x) { - //TODO: maybe transform it into the more simple operations? var updated = (BoundMatchEx)base.VisitMatchEx(x); var updatedArms = new List(); diff --git a/src/Aquila.CodeAnalysis/Metadata/MetadataSymbolProvider.Tables.cs b/src/Aquila.CodeAnalysis/Metadata/MetadataSymbolProvider.Tables.cs index 35a03f45e..aa6037ad7 100644 --- a/src/Aquila.CodeAnalysis/Metadata/MetadataSymbolProvider.Tables.cs +++ b/src/Aquila.CodeAnalysis/Metadata/MetadataSymbolProvider.Tables.cs @@ -752,7 +752,7 @@ private void PopulateTableObjectType(SMEntity md, SMTable table) else { var managerType = - _ps.GetType(QualifiedName.Parse( + _ps.TryGetType(QualifiedName.Parse( $"{Namespace}.{type.type.GetSemantic().Name}{ManagerPostfix}", true)); var typeIDField = managerType.GetMembers("TypeId").OfType() @@ -766,7 +766,7 @@ private void PopulateTableObjectType(SMEntity md, SMTable table) if (type.type.IsReference) { - var linkType = _ps.GetType(QualifiedName.Parse( + var linkType = _ps.TryGetType(QualifiedName.Parse( $"{Namespace}.{type.type.GetSemantic().Name}{LinkPostfix}", true)); var linkCtor = linkType.Ctor(_ct.AqContext, _ct.Guid); @@ -866,7 +866,7 @@ private void PopulateTableObjectType(SMEntity md, SMTable table) else { var managerType = - _ps.GetType(QualifiedName.Parse( + _ps.TryGetType(QualifiedName.Parse( $"{Namespace}.{typeInfo.type.GetSemantic().Name}{ManagerPostfix}", true)); var typeIDField = managerType.GetMembers("TypeId").OfType() @@ -991,7 +991,7 @@ private void PopulateTableLinkType(SMEntity md, SMTable table) _ps.GetSynthesizedType(QualifiedName.Parse($"{Namespace}.{md.Name}{table.Name}{TableRowLinkPostfix}", false)); var rowDtoType = - _ps.GetType(QualifiedName.Parse($"{Namespace}.{md.Name}{table.Name}{TableRowDtoPostfix}", true)); + _ps.TryGetType(QualifiedName.Parse($"{Namespace}.{md.Name}{table.Name}{TableRowDtoPostfix}", true)); var idField = _ps.SynthesizeField(rowLinkType) @@ -1111,7 +1111,7 @@ private void PopulateTableLinkType(SMEntity md, SMTable table) else { var managerType = - _ps.GetType(QualifiedName.Parse( + _ps.TryGetType(QualifiedName.Parse( $"{Namespace}.{type.type.GetSemantic().Name}{ManagerPostfix}", true)); var typeIDField = managerType.GetMembers("TypeId").OfType() @@ -1125,7 +1125,7 @@ private void PopulateTableLinkType(SMEntity md, SMTable table) if (type.type.IsReference) { - var linkType = _ps.GetType(QualifiedName.Parse( + var linkType = _ps.TryGetType(QualifiedName.Parse( $"{Namespace}.{type.type.GetSemantic().Name}{LinkPostfix}", true)); var linkCtor = linkType.Ctor(_ct.AqContext, _ct.Guid); diff --git a/src/Aquila.CodeAnalysis/Metadata/MetadataSymbolProvider.cs b/src/Aquila.CodeAnalysis/Metadata/MetadataSymbolProvider.cs index 5eeef2ab5..a7e7a6429 100644 --- a/src/Aquila.CodeAnalysis/Metadata/MetadataSymbolProvider.cs +++ b/src/Aquila.CodeAnalysis/Metadata/MetadataSymbolProvider.cs @@ -498,7 +498,7 @@ private NamedTypeSymbol PopulateObjectType(SMEntity md, NamedTypeSymbol dtoType) else { var managerType = - _ps.GetType(QualifiedName.Parse( + _ps.TryGetType(QualifiedName.Parse( $"{Namespace}.{type.type.GetSemantic().Name}{ManagerPostfix}", true)); var typeIDField = managerType.GetMembers("TypeId").OfType() @@ -512,7 +512,7 @@ private NamedTypeSymbol PopulateObjectType(SMEntity md, NamedTypeSymbol dtoType) if (type.type.IsReference) { - var linkType = _ps.GetType(QualifiedName.Parse( + var linkType = _ps.TryGetType(QualifiedName.Parse( $"{Namespace}.{type.type.GetSemantic().Name}{LinkPostfix}", true)); var linkCtor = linkType.Ctor(_ct.AqContext, _ct.Guid); @@ -612,7 +612,7 @@ private NamedTypeSymbol PopulateObjectType(SMEntity md, NamedTypeSymbol dtoType) else { var managerType = - _ps.GetType(QualifiedName.Parse( + _ps.TryGetType(QualifiedName.Parse( $"{Namespace}.{typeInfo.type.GetSemantic().Name}{ManagerPostfix}", true)); var typeIDField = managerType.GetMembers("TypeId").OfType() @@ -725,7 +725,7 @@ private NamedTypeSymbol PopulateObjectType(SMEntity md, NamedTypeSymbol dtoType) return (il) => { var managerType = - _ps.GetType(QualifiedName.Parse($"{Namespace}.{md.Name}{ManagerPostfix}", true)); + _ps.TryGetType(QualifiedName.Parse($"{Namespace}.{md.Name}{ManagerPostfix}", true)); var mrgSave = managerType.GetMembers("save_dto").OfType().FirstOrDefault() ?? throw new Exception("Method save_dto not found in manager type"); @@ -779,7 +779,7 @@ private NamedTypeSymbol PopulateObjectType(SMEntity md, NamedTypeSymbol dtoType) return (il) => { var managerType = - _ps.GetType(QualifiedName.Parse($"{Namespace}.{md.Name}{ManagerPostfix}", true)); + _ps.TryGetType(QualifiedName.Parse($"{Namespace}.{md.Name}{ManagerPostfix}", true)); var mrgDelete = managerType.GetMembers("delete").OfType().FirstOrDefault() ?? throw new Exception("Method save not found in manager type"); @@ -814,8 +814,8 @@ private NamedTypeSymbol PopulateObjectType(SMEntity md, NamedTypeSymbol dtoType) private NamedTypeSymbol PopulateLinkType(SMEntity md) { var linkType = _ps.GetSynthesizedType(QualifiedName.Parse($"{Namespace}.{md.Name}{LinkPostfix}", false)); - var managerType = _ps.GetType(QualifiedName.Parse($"{Namespace}.{md.Name}{ManagerPostfix}", true)); - var dtoType = _ps.GetType(QualifiedName.Parse($"{Namespace}.{md.Name}{DtoPostfix}", true)); + var managerType = _ps.TryGetType(QualifiedName.Parse($"{Namespace}.{md.Name}{ManagerPostfix}", true)); + var dtoType = _ps.TryGetType(QualifiedName.Parse($"{Namespace}.{md.Name}{DtoPostfix}", true)); var idField = _ps.SynthesizeField(linkType) .SetName("id") @@ -995,7 +995,7 @@ private NamedTypeSymbol PopulateLinkType(SMEntity md) else { var managerType = - _ps.GetType(QualifiedName.Parse( + _ps.TryGetType(QualifiedName.Parse( $"{Namespace}.{type.type.GetSemantic().Name}{ManagerPostfix}", true)); var typeIDField = managerType.GetMembers("TypeId").OfType() @@ -1009,7 +1009,7 @@ private NamedTypeSymbol PopulateLinkType(SMEntity md) if (type.type.IsReference) { - var linkType = _ps.GetType(QualifiedName.Parse( + var linkType = _ps.TryGetType(QualifiedName.Parse( $"{Namespace}.{type.type.GetSemantic().Name}{LinkPostfix}", true)); var linkCtor = linkType.Ctor(_ct.AqContext, _ct.Guid); diff --git a/src/Aquila.CodeAnalysis/Metadata/MetadataTypeProvider.cs b/src/Aquila.CodeAnalysis/Metadata/MetadataTypeProvider.cs index 640038d05..b8e343af3 100644 --- a/src/Aquila.CodeAnalysis/Metadata/MetadataTypeProvider.cs +++ b/src/Aquila.CodeAnalysis/Metadata/MetadataTypeProvider.cs @@ -23,7 +23,7 @@ public static TypeSymbol Resolve(AquilaCompilation compilation, SMType typeName) SMTypeKind.Decimal => ct.Decimal, SMTypeKind.Guid => ct.Guid, SMTypeKind.DateTime => ct.DateTime, - SMTypeKind.Reference => compilation.PlatformSymbolCollection.GetType( + SMTypeKind.Reference => compilation.PlatformSymbolCollection.TryGetType( QualifiedName.Parse(typeName.GetSemantic().ReferenceName, true)), SMTypeKind.Unknown => ct.Object, _ => throw new NotImplementedException("Unknown metadata type") diff --git a/src/Aquila.CodeAnalysis/Parser/LanguageParser.cs b/src/Aquila.CodeAnalysis/Parser/LanguageParser.cs index 223c36bfb..a82aa4118 100644 --- a/src/Aquila.CodeAnalysis/Parser/LanguageParser.cs +++ b/src/Aquila.CodeAnalysis/Parser/LanguageParser.cs @@ -8,13 +8,10 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading; -using Aquila.CodeAnalysis.CodeGen; using Aquila.CodeAnalysis.Errors; -using Aquila.Syntax.Ast; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; -using YamlDotNet.Serialization.NodeTypeResolvers; namespace Aquila.CodeAnalysis.Syntax.InternalSyntax { @@ -2629,7 +2626,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 +5894,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 +6146,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 +6388,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/Semantics/Binder/Binder.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs index 6255194f5..42b0894d5 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/Binder.cs @@ -5,177 +5,20 @@ using System.Linq; using System.Reflection; using Aquila.CodeAnalysis.Errors; -using Aquila.CodeAnalysis.FlowAnalysis; using Aquila.CodeAnalysis.Semantics.TypeRef; using Aquila.CodeAnalysis.Symbols; using Aquila.CodeAnalysis.Syntax; using Aquila.CodeAnalysis.Utilities; +using Aquila.Core.Querying.Model; using Aquila.Syntax.Ast; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; using SpecialTypeExtensions = Aquila.CodeAnalysis.Symbols.SpecialTypeExtensions; 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; @@ -184,14 +27,12 @@ internal abstract class Binder private string NextMatchVariableName() => "'" + _tmpVariableIndex++; - - internal Binder(AquilaCompilation compilation) + protected Binder(AquilaCompilation compilation) { Compilation = compilation; } - - public Binder(Binder next) + protected Binder(Binder next) { Next = next; Compilation = next.Compilation; @@ -215,10 +56,15 @@ public virtual Binder GetBinder(AquilaSyntaxNode syntax) public virtual NamespaceOrTypeSymbol Container { get; } + public virtual Symbol ContainingSymbol { get; } + public LocalsTable Locals => Method.LocalsTable; public virtual ImmutableArray DeclaredTypes => ImmutableArray.Empty; + public virtual bool IsInLambda => false; + + #region Bind statements public virtual BoundStatement BindStatement(StmtSyntax stmt) => BindStatementCore(stmt).WithSyntax(stmt); @@ -227,31 +73,35 @@ BoundStatement BindStatementCore(StmtSyntax stmt) { Debug.Assert(stmt != null); - if (stmt is ExpressionStmt exprStm) - return new BoundExpressionStmt(BindExpression(exprStm.Expression, BoundAccess.None)); - if (stmt is ReturnStmt jmpStm) - return BindReturnStmt(jmpStm); - if (stmt is LocalDeclStmt varDecl) - return BindVarDeclStmt(varDecl); - if (stmt is ForEachStmt frch) - return BindForeachStmt(frch); - if (stmt is TryStmt tryStmt) - return BindTryStmt(tryStmt); - - Diagnostics.Add(GetLocation(stmt), ErrorCode.ERR_NotYetImplemented, - $"Statement of type '{stmt.GetType().Name}'"); - return new BoundEmptyStmt(stmt.Span); + switch (stmt) + { + case ExpressionStmt exprStm: + return new BoundExpressionStmt(BindExpression(exprStm.Expression, BoundAccess.None)); + case ReturnStmt jmpStm: + return BindReturnStmt(jmpStm); + case LocalDeclStmt varDecl: + return BindVarDeclStmt(varDecl); + case ForEachStmt foreachStmt: + return BindForeachStmt(foreachStmt); + case TryStmt tryStmt: + return BindTryStmt(tryStmt); + default: + Diagnostics.Add(GetLocation(stmt), ErrorCode.ERR_NotYetImplemented, + $"Statement of type '{stmt.GetType().Name}'"); + return new BoundEmptyStmt(stmt.Span); + } } private BoundStatement BindTryStmt(TryStmt tryStmt) { - foreach (var c in tryStmt.Catches) + foreach (var catchStmt in tryStmt.Catches) { - if (c.Declaration != null) - { - var type = BindType(c.Declaration.Type); - var v = BindVar(c.Declaration.Identifier, type); - } + var decl = catchStmt.Declaration; + + if (decl == null) continue; + + var type = TryResolveTypeSymbol(decl.Type); + BindVar(decl.Identifier, type); } throw new NotImplementedException(); @@ -259,32 +109,24 @@ private BoundStatement BindTryStmt(TryStmt tryStmt) internal BoundStatement BindVarDecl(VariableDecl varDecl) { - var decl1 = varDecl; + Debug.Assert(varDecl.Variables.Count == 1); - foreach (var decl in decl1.Variables) - { - 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 decl = varDecl.Variables.First(); - var localVar = Method.LocalsTable.BindLocalVariable(new VariableName(decl.Identifier.Text), decl); - - var boundExpression = BindExpression(decl.Initializer.Value); + 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))); + } - return new BoundExpressionStmt(new BoundAssignEx( - new BoundVariableRef(decl.Identifier.Text, localVar.Type).WithAccess(BoundAccess.Write), - boundExpression, localVar.Type)); - break; + var localVar = Locals.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) @@ -292,17 +134,14 @@ private BoundStatement BindVarDeclStmt(LocalDeclStmt varDecl) return BindVarDecl(varDecl.Declaration); } - private BoundVariableRef BindVariable(VariableName varName, TextSpan span, TypeSymbol type) - { - var localVar = Method.LocalsTable.BindLocalVariable(varName, span, type); - return BindVariable(localVar); - } - 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 +149,51 @@ 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 localVar = Method.LocalsTable.BindLocalVariable(new VariableName(stmt.Identifier.Text), - stmt.Identifier.Span, variableType); + var variableType = currentMember.Type; - var assign = CreateTmpAndAssign(enumeratorSymbol, - new BoundCallEx(getEnumMethod, ImmutableArray.Empty, - ImmutableArray.Empty, collection, enumeratorSymbol - ).WithAccess(BoundAccess.Read)); + var localVar = Method.LocalsTable.BindLocalVariable(new VariableName(stmt.Identifier.Text), + stmt.Identifier.Span, variableType); - //enumerator.MoveNext() expr - var moveNextCondition = new BoundCallEx(moveNextMember, - ImmutableArray.Empty, - ImmutableArray.Empty, assign.Target, moveNextMember.ReturnType); + var assign = CreateTmpAndAssign(enumeratorSymbol, + new BoundCallEx(getEnumMethod, ImmutableArray.Empty, collection, enumeratorSymbol + ).WithAccess(BoundAccess.Read)); - var callDispose = new BoundCallEx(disposeMember, ImmutableArray.Empty, - ImmutableArray.Empty, assign.Target, Compilation.CoreTypes.Void.Symbol); + //enumerator.MoveNext() expr + var moveNextCondition = new BoundCallEx(moveNextMember, + ImmutableArray.Empty, assign.Target, moveNextMember.ReturnType); - var bindInfo = new ForeachBindInfo() - { - CurrentMember = currentMember, - EnumeratorSymbol = enumeratorSymbol, - GetEnumerator = getEnumMethod, - MoveNextMember = moveNextMember, - DisposeMember = disposeMember, - DisposeCall = callDispose, - EnumeratorVar = assign.Target, - EnumeratorAssignmentEx = assign, - MoveNextEx = moveNextCondition, - }; + var callDispose = new BoundCallEx(disposeMember, ImmutableArray.Empty, assign.Target, + Compilation.CoreTypes.Void.Symbol); - 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) @@ -382,54 +210,76 @@ private BoundAssignEx CreateTmpAndAssign(TypeSymbol type, BoundExpression expr) return new BoundAssignEx(boundVar, expr).WithAccess(BoundAccess.ReadAndWrite); } - public TypeSymbol BindType(TypeEx tref) + public TypeSymbol? TryResolveTypeSymbol(TypeEx typeEx) { var trf = Compilation.CoreTypes; - if (tref is PredefinedTypeEx pt) + switch (typeEx) { - switch (pt.Keyword.Kind()) + case PredefinedTypeEx pt: + return pt.Keyword.Kind() switch + { + SyntaxKind.IntKeyword => trf.Int32, + SyntaxKind.LongKeyword => trf.Int64, + SyntaxKind.VoidKeyword => trf.Void, + SyntaxKind.ObjectKeyword => trf.Object, + SyntaxKind.StringKeyword => trf.String, + SyntaxKind.BoolKeyword => trf.Boolean, + SyntaxKind.DatetimeKeyword => trf.DateTime, + _ => throw ExceptionUtilities.UnexpectedValue(pt.Kind()) + }; + case NameEx named: { - case SyntaxKind.IntKeyword: return trf.Int32; - case SyntaxKind.LongKeyword: return trf.Int64; - case SyntaxKind.VoidKeyword: return trf.Void; - case SyntaxKind.ObjectKeyword: return trf.Object; - case SyntaxKind.StringKeyword: return trf.String; - case SyntaxKind.BoolKeyword: return trf.Boolean; - case SyntaxKind.DatetimeKeyword: return trf.DateTime; - - default: throw ExceptionUtilities.UnexpectedValue(pt.Kind()); + TryResolveSymbol(named, BoundAccess.None, new[] { SymbolKind.NamedType }, out var result); + return result.Symbol as TypeSymbol; } - } - else if (tref is NameEx named) - { - var typeSymbol = FindTypeByName(named); - return (TypeSymbol)typeSymbol; - } - else if (tref is UnionTypeEx union) - { - var listSym = new List(); - foreach (var type in union.Types) + case UnionTypeEx union: { - var symbol = BindType(type); - listSym.Add(symbol); + var listSym = union.Types.Select(TryResolveTypeSymbol).ToList(); + var tsym = Compilation.PlatformSymbolCollection.SynthesizeUnionType( + Compilation.SourceModule.GlobalNamespace, listSym); + + return tsym; } + default: + Diagnostics.Add(GetLocation(typeEx), ErrorCode.ERR_NotYetImplemented, + $"Expression of type '{typeEx.GetType().Name}'"); + throw new NotImplementedException(); + } + } - //TODO: create Union type symbol - var tsym = Compilation.PlatformSymbolCollection.SynthesizeUnionType( - (NamespaceSymbol)Compilation.SourceModule.GlobalNamespace, listSym); + private ImmutableArray> FindSymbolByName(string name, params SymbolKind[] kinds) + { + var foundSymbolsBuilder = new ArrayBuilder>(); + FindSymbolByName(name, foundSymbolsBuilder, new FilterCriteria { SymbolKinds = kinds }); + return foundSymbolsBuilder.ToImmutableAndFree(); + } - return tsym; - } - else + protected virtual void FindSymbolByName(string name, ArrayBuilder> result, + FilterCriteria filterCriteria) + { + Next?.FindSymbolByName(name, result, filterCriteria); + } + + protected void FindSymbolByNameHandler(IEnumerable symbols, ArrayBuilder> result, + FilterCriteria criteria, Action continueSearch) + { + if (criteria.SymbolKinds.Any()) { - Diagnostics.Add(GetLocation(tref), ErrorCode.ERR_NotYetImplemented, - $"Expression of type '{tref.GetType().Name}'"); + symbols = symbols.Where(s => criteria.SymbolKinds.Contains(s.Kind)); + } - throw new NotImplementedException(); + var symbolsArray = symbols.ToImmutableArray(); + + result.Add(symbolsArray); + + if (!symbolsArray.Any()) + { + continueSearch(); } } + protected virtual ITypeSymbol FindTypeByName(NameEx tref) { return Next?.FindTypeByName(tref); @@ -454,7 +304,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,66 +322,91 @@ 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, 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 lambda = Locals.BindLambda(funcEx); + return new BoundFuncEx(lambda, lambda.ReturnType); } private BoundExpression BindAllocEx(AllocEx ex) { - var type = (NamedTypeSymbol)BindType(ex.Name); + var type = (NamedTypeSymbol)TryResolveTypeSymbol(ex.Name); var inits = new List(); - if (ex.Initializer.Expressions.Any()) - switch (ex.Initializer.Kind()) - { - case SyntaxKind.ObjectInitializerExpression: - foreach (var iex in ex.Initializer.Expressions) - { - var ae = iex as AssignEx; + if (!ex.Initializer.Expressions.Any()) return new BoundAllocEx(type, inits, type); - var left = (ae.Left as IdentifierEx); - var right = BindExpression(ae.Right); + switch (ex.Initializer.Kind()) + { + case SyntaxKind.ObjectInitializerExpression: + foreach (var iex in ex.Initializer.Expressions) + { + var ae = iex as AssignEx; - var mems = type.GetMembers(left.Identifier.Text) - .Where(x => !x.IsStatic && ((x.Kind & SymbolKind.Property) > 0 - || (x.Kind & SymbolKind.Field) > 0)) - .ToImmutableArray(); - if (mems.Length > 1) - { + var left = (ae.Left as IdentifierEx); + var right = BindExpression(ae.Right); + + var mems = type.GetMembers(left.Identifier.Text) + .Where(x => !x.IsStatic && ((x.Kind & SymbolKind.Property) > 0 + || (x.Kind & SymbolKind.Field) > 0)) + .ToImmutableArray(); + switch (mems.Length) + { + case > 1: //ambiguity - } - else if (mems.Length == 1) + break; + case 1: { var item = mems[0]; inits.Add(new BoundAllocExAssign(item, right)); + break; } } + } - break; + break; - default: - throw new NotImplementedException(); - } + default: + throw new NotImplementedException(); + } return new BoundAllocEx(type, inits, type); } @@ -542,8 +417,6 @@ private BoundExpression BindMatchEx(MatchEx me) TypeSymbol resultType = null; var arms = new List(); - bool takeTypeFromNext = false; - foreach (var arm in me.Arms) { var boundArm = BindMatchArm(arm); @@ -552,30 +425,27 @@ private BoundExpression BindMatchEx(MatchEx me) var armType = (TypeSymbol)(boundArm.ResultType); - if (armType != null) + if (armType == null) continue; + // then we try to calc result type + + if (resultType != null) { - // then we try to calc result type + if (resultType == armType) continue; - if (resultType != null) + if (resultType.IsEqualToOrDerivedFrom(armType)) { - if (resultType != armType) - { - if (resultType.IsEqualToOrDerivedFrom(armType)) - { - //error - } - - if (armType.IsEqualToOrDerivedFrom(resultType)) - { - //cast - } - } + //error } - else + + if (armType.IsEqualToOrDerivedFrom(resultType)) { - resultType = armType; + //cast } } + else + { + resultType = armType; + } } if (resultType == null) @@ -597,20 +467,17 @@ private BoundMatchArm BindMatchArm(MatchArm arm) private BoundExpression BindIndexerEx(ElementAccessEx ie) { - var array = BindExpression(ie.Expression); + var array = BindExpression(ie.Expression).WithAccess(BoundAccess.Read); - //TODO: make arity for element accsessex var indexer = BindExpression(ie.ArgumentList.Arguments.First().Expression); - var accessIndexMethod = array.Type.GetMembers("get_Item").OfType() - .FirstOrDefault(x => x.ParameterCount == 1 && x.Parameters[0].Type == indexer.Type); + .FirstOrDefault(x => x.ParameterCount == 1 && x.Parameters[0].Type == (TypeSymbol)indexer.Type); if (accessIndexMethod != null) return new BoundArrayItemEx(Compilation, array, indexer, accessIndexMethod.ReturnType); - - throw new NotImplementedException(); + throw ExceptionUtilities.Unreachable; } @@ -673,37 +540,104 @@ protected virtual BoundExpression BindNameEx(NameEx expr, BoundAccess access) return new BoundWildcardEx(Compilation.CoreTypes.Void.Symbol).WithSyntax(expr); } - var bounded = BindSimpleVarUse(expr, access); + if (!TryResolveSymbol(expr, access, out var result)) + { + return BadEx; + } + + var resultSymbol = result.Symbol; + switch (resultSymbol.Kind) + { + case SymbolKind.Local: + case SymbolKind.Parameter: + return new BoundVariableRef(resultSymbol.Name, resultSymbol.GetTypeOrReturnType()).WithAccess(access); + case SymbolKind.Field: + return new BoundFieldRef(resultSymbol as IFieldSymbol, ThisEx).WithAccess(access); + case SymbolKind.Property: + return new BoundPropertyRef(resultSymbol as IPropertySymbol, ThisEx).WithAccess(access); + case SymbolKind.NamedType: + return new BoundClassTypeRef(QualifiedName.Object, Method, resultSymbol as ITypeSymbol).WithAccess(access); + case SymbolKind.Method: + return BindMethodSymbol(resultSymbol as MethodSymbol, ThisEx, access).WithAccess(access); + } - // local variable hide the members - if (bounded != null) - return bounded; + return BadEx; + } + private BoundExpression BindMethodSymbol(MethodSymbol methodSymbol, BoundExpression instanceEx, + BoundAccess access) + { + if (!access.IsInvoke) + return new BoundMethodRef(methodSymbol, instanceEx, methodSymbol.GetTypeOrReturnType()); + return new BoundCallEx(methodSymbol, access.Arguments, methodSymbol.IsStatic ? null : instanceEx, + methodSymbol.GetTypeOrReturnType()); + } - //try to find property - //TODO: add scan fields - var result = Container.GetMembers(identifier).OfType().FirstOrDefault(); - if (result != null) - { - var type = Container as ITypeSymbol; - var th = new BoundVariableRef("this", type); + private BoundExpression BadEx => new BoundBadEx(Compilation.CoreTypes.Void.Symbol); + + private BoundVariableRef ThisEx => + new BoundVariableRef("this", Container as ITypeSymbol).WithAccess(BoundAccess.Read); - return new BoundPropertyRef(result, th).WithAccess(access); + private bool TryResolveSymbol(NameEx nameEx, BoundAccess access, out (Symbol Symbol, bool IsCaptured) result) + { + return TryResolveSymbol(nameEx, access, Array.Empty(), out result); + } + + private bool TryResolveSymbol(NameEx nameEx, BoundAccess access, SymbolKind[] kinds, + out (Symbol Symbol, bool IsCaptured) result) + { + var name = nameEx.GetUnqualifiedName().Identifier.Text; + + var foundSymbolsByBinders = FindSymbolByName(name, kinds); + + if (!foundSymbolsByBinders.Any()) + { + Diagnostics.Add(GetLocation(nameEx), ErrorCode.ERR_UndefinedIdentifier, name); + result = (null, false); + return false; } - //try to find type name - var foundedType = BindType(expr); + for (var index = 0; index < foundSymbolsByBinders.Length; index++) + { + var binderSymbols = foundSymbolsByBinders[index]; + var isCaptured = index != 0 && IsInLambda; - return new BoundClassTypeRef(QualifiedName.Object, Method, foundedType); + switch (binderSymbols) + { + case { Length: 0 }: continue; + case { Length: 1 }: + var resolvedSymbol = binderSymbols[0]; + if (resolvedSymbol is MethodSymbol method) + { + resolvedSymbol = ConstructSingle(nameEx, method, BindTypeArguments(nameEx)); + } + + result = (resolvedSymbol, isCaptured); + return true; + case { Length: > 1 } when binderSymbols.All(x => x is MethodSymbol) && access.IsInvoke: + var methods = binderSymbols.Cast().ToImmutableArray(); + var constructedMethods = Construct(methods, BindTypeArguments(nameEx)); + var resolved1 = (MethodSymbol)ResolveOverload(constructedMethods, access.Arguments); + result = (resolved1, isCaptured); + return true; + case { Length: > 1 }: + Diagnostics.Add(GetLocation(nameEx), ErrorCode.ERR_AmbiguousName, name); + result = (null, false); + return false; + } + } + + Diagnostics.Add(nameEx.GetLocation(), ErrorCode.ERR_CantResolveSymbol, name); + result = (null, false); + return false; } protected BoundExpression BindSimpleVarUse(NameEx expr, BoundAccess access) { - var varname = BindVariableName(expr); + var varName = BindVariableName(expr); // variable not found - if (varname is null) return null; - + if (varName is null) return null; if (Method == null) { @@ -711,32 +645,22 @@ protected BoundExpression BindSimpleVarUse(NameEx expr, BoundAccess access) Diagnostics.Add(GetLocation(expr), ErrorCode.ERR_InvalidConstantExpression); } - if (varname.IsDirect) - { - if (varname.NameValue.IsThisVariableName) - { - // $this is read-only - if (access.IsEnsure) - access = BoundAccess.Read; + if (!varName.NameValue.IsThisVariableName) + return new BoundVariableRef(varName, varName.Type).WithAccess(access); - if (access.IsWrite || access.IsUnset) - Diagnostics.Add(GetLocation(expr), ErrorCode.ERR_CannotAssignToThis); + if (access.IsEnsure) + access = BoundAccess.Read; - // $this is only valid in global code and instance methods: - if (Method != null && Method.IsStatic && !Method.IsGlobalScope) - { - //TODO: Add diagnostics - throw new NotImplementedException(); - } - } - } - else + if (access.IsWrite || access.IsUnset) + Diagnostics.Add(GetLocation(expr), ErrorCode.ERR_CannotAssignToThis); + + if (Method != null && Method.IsStatic && !Method.IsGlobalScope) { - if (Method != null) - Method.Flags |= MethodFlags.HasIndirectVar; + //TODO: Add diagnostics + throw new NotImplementedException(); } - return new BoundVariableRef(varname, varname.Type).WithAccess(access); + return new BoundVariableRef(varName, varName.Type).WithAccess(access); } protected BoundVariableName BindVariableName(NameEx nameEx) @@ -750,8 +674,7 @@ protected BoundVariableName BindVariableName(string varName, AquilaSyntaxNode sy Debug.Assert(varName != null); Debug.Assert(Method != null); - Method.LocalsTable.TryGetVariable(new VariableName(varName), out var localVar); - if (localVar is null) + if (!Locals.TryGetVariable(new VariableName(varName), out var localVar)) return null; var type = localVar.Type; @@ -833,7 +756,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"); @@ -847,7 +770,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); } @@ -917,28 +840,21 @@ protected BoundExpression BindPrefixUnaryEx(PrefixUnaryEx expr) } } - private BoundExpression BindCallEx(InvocationEx expr) + private BoundExpression BindCallEx(InvocationEx call) { - return BindMethodGroup(expr.Expression, expr.ArgumentList, true); - } - - private BoundExpression BindMethodGroup(ExprSyntax expr, ArgumentListSyntax args, bool invoked) - { - switch (expr.Kind()) + var method = call.Expression; + var boundArguments = BindArguments(call.ArgumentList); + var access = BoundAccess.Invoke.WithArguments(boundArguments); + return method.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 => BindNameEx((NameEx)method, access), + SyntaxKind.SimpleMemberAccessExpression => BindMemberAccessEx((MemberAccessEx)method, access), + SyntaxKind.GenericName => BindNameEx((GenericEx)method, access), + _ => throw new NotImplementedException() + }; } - MethodSymbol ConstructSingle(MethodSymbol method, ImmutableArray typeArgs) + MethodSymbol ConstructSingle(SyntaxNode node, MethodSymbol method, ImmutableArray typeArgs) { if (typeArgs.IsDefaultOrEmpty) { @@ -950,7 +866,8 @@ MethodSymbol ConstructSingle(MethodSymbol method, ImmutableArray ty return method.Construct(typeArgs.ToArray()); } - throw new InvalidOperationException("TODO: generic types different arity"); + Diagnostics.Add(node.GetLocation(), ErrorCode.ERR_BadArity, method.Name, method.Arity); + return new MissingMethodSymbol(""); } // helper @@ -965,7 +882,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 { @@ -977,249 +894,104 @@ ImmutableArray Construct(ImmutableArray methods, } } - protected virtual BoundExpression BindName(SimpleNameEx expr, ArgumentListSyntax argumentList, bool invocation) + public ImmutableArray BindTypeArguments(NameEx nameExpr) { - Debug.Assert(Method != null); + if (nameExpr is not GenericEx genEx) + return ImmutableArray.Empty; + return genEx + .TypeArgumentList + .Arguments + .Select(TryResolveTypeSymbol) + .OfType() + .ToImmutableArray(); + } - var arglist = argumentList.Arguments + public ImmutableArray BindArguments(ArgumentListSyntax argumentListSyntax) + { + return argumentListSyntax.Arguments .Select(x => BoundArgument.Create(BindExpression(x.Expression))) .ToImmutableArray(); + } - var typeArgs = ImmutableArray.Empty; - - if (expr.Kind() == SyntaxKind.GenericName) - { - typeArgs = ((GenericEx)expr).TypeArgumentList.Arguments.Select(BindType).OfType() - .ToImmutableArray(); - } - - var nameId = expr.Identifier.Text; - - //try find local first - var containerMembers = Container.GetMembers(nameId).ToImmutableArray(); - - var qualifiedName = new QualifiedName(new Name(nameId)); - - if (containerMembers.Count() == 1) - { - var member = containerMembers[0]; - if (invocation) - { - if (member is MethodSymbol ms) - { - ms = ConstructSingle(ms, typeArgs); - - var th = (ms.IsStatic) - ? null - : new BoundVariableRef(QualifiedName.This.Name.Value, Container as ITypeSymbol); - - return new BoundCallEx(ms, arglist, typeArgs, th, ms.ReturnType); - } - } - else - { - if (member is MethodSymbol ms) - { - //... BoundMethod - } - - if (member is FieldSymbol fs) - { - // ld_fld - } + private static IMethodSymbol ResolveOverload(ImmutableArray overloads, + ImmutableArray argsList) + { + var types = argsList.Select(x => x.Type).ToImmutableArray(); - if (member is PropertySymbol ps) - { - // call _get method - } - } - } + Dictionary candidates = new(); - if (containerMembers.Count() > 1 && invocation) - { - //Resolve overload - var overload = ResolveOverload(containerMembers.OfType().ToImmutableArray(), arglist); - } + if (overloads.Length <= 0) return candidates.Any() ? candidates.MinBy(x => x.Value).Key : null; - //Go to global members + foreach (var methodSymbol in overloads) { - var methods = new ArrayBuilder(); - FindMethodsByName(nameId, methods); - - var globalMembers = methods.OfType().Where(x => x.Arity == typeArgs.Count()) - .ToImmutableArray(); + var cost = 0; - globalMembers = Construct(globalMembers, typeArgs); + var parameters = methodSymbol.Parameters; - var overload = ResolveOverload(globalMembers, arglist); + var paramPlace = 0; - if (overload == null) + if (methodSymbol.HasParamPlatformContext) { - 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)); - } - else - { - if (invocation) - { - if (overload is MethodSymbol ms) - { - if (ms.IsStatic) - { - return new BoundCallEx(ms, arglist, typeArgs, null, ms.ReturnType); - } - else - { - //Extension method can't be instance - } - } - } + paramPlace = 1; } - } - if (!Enumerable.Any(containerMembers)) - Diagnostics.Add(GetLocation(expr), ErrorCode.INF_CantResolveSymbol); + if (types.Length != parameters.Length - paramPlace) + continue; - BoundExpression result; + var isCandidate = true; - if (invocation) - { - result = new BoundCallEx(new MissingMethodSymbol(nameId), arglist, typeArgs, null, null); - } - else - { - result = new BoundPropertyRef(new MissingPropertySymbol(nameId), null); - } - - return result; - } - - private IMethodSymbol ResolveOverload(ImmutableArray overloads, - ImmutableArray argsList) - { - var types = argsList.Select(x => x.Type).ToImmutableArray(); - - Dictionary candidates = new(); - - if (overloads.Length > 0) - - foreach (var methodSymbol in overloads) + for (int i = 0; i < types.Length; i++) { - var cost = 0; + var leftType = types[i]; + var rightType = parameters[i + paramPlace].Type; - var parametars = methodSymbol.Parameters; - - var paramPlace = 0; - if (methodSymbol.HasParamPlatformContext) + if (!leftType.IsEqualOrDerivedFrom(rightType)) { - paramPlace = 1; - } - - if (types.Length != parametars.Length - paramPlace) - continue; - - var isCandidate = true; - - for (int i = 0; i < types.Length; i++) - { - var leftType = types[i]; - var rightType = parametars[i + paramPlace].Type; - - if (!leftType.IsEqualOrDerivedFrom(rightType)) - { - isCandidate = false; - break; - } - else - { - if (leftType.Equals(rightType)) - { - cost += 1; - } - else - { - //need box type - cost += 2; - } - } + isCandidate = false; + break; } - if (isCandidate) - candidates[methodSymbol] = cost; + // if types not equal, then we need use boxing - it expensive + cost += SymbolEqualityComparer.Default.Equals(leftType, rightType) ? 1 : 2; } - if (candidates.Any()) - //minimize cost - return candidates.MinBy(x => x.Value).Key; + if (isCandidate) + candidates[methodSymbol] = cost; + } - 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, BoundAccess access) { - var boundLeft = BindExpression(expr.Expression).WithAccess(BoundAccess.Invoke); + var boundLeft = BindExpression(expr.Expression); 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; + var binder = new InContainerBinder(leftType, new BuckStopsHereBinder(Compilation)); - if (expr.Name.Kind() == SyntaxKind.GenericName) - { - typeArgs = ((GenericEx)expr.Name).TypeArgumentList.Arguments.Select(BindType).OfType() - .ToImmutableArray(); - } + if (!binder.TryResolveSymbol(expr.Name, access, out var result)) + return BadEx; - foreach (var member in members) - { - if (invoke) - { - if (member is MethodSymbol ms) - { - var arglist = args.Arguments.Select(x => BoundArgument.Create(BindExpression(x.Expression))) - .ToImmutableArray(); + var (symbol, _) = result; - ms = ConstructSingle(ms, typeArgs); + if (!SymbolEqualityComparer.Default.Equals(leftType, symbol.ContainingType)) + return BadEx; - return new BoundCallEx(ms, arglist, typeArgs, (ms.IsStatic) ? null : boundLeft, - ms.ReturnType); - } - } - else - { - if (member is PropertySymbol ps) - { - return new BoundPropertyRef(ps, boundLeft); - } - else if (member is 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); - } - - protected BoundExpression BindCopyValue(BoundExpression expr) - { - if (expr.IsDeeplyCopied) - { - return new BoundCopyValue(expr).WithAccess(BoundAccess.Read); - } - else + return symbol switch { - // value does not have to be copied - return expr; - } + PropertySymbol ps => new BoundPropertyRef(ps, boundLeft).WithAccess(access), + FieldSymbol fs => new BoundFieldRef(fs, boundLeft).WithAccess(access), + MethodSymbol ms => BindMethodSymbol(ms, boundLeft, access).WithAccess(access), + _ => BadEx + }; } #endregion } + + internal sealed class FilterCriteria + { + public SymbolKind[] SymbolKinds { get; init; } + } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Aquila.CodeAnalysis/Semantics/Binder/BinderFactory.BinderFactoryVisitor.cs index df8dcd6e5..52e8071e7 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Binder/BinderFactory.BinderFactoryVisitor.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/BinderFactory.BinderFactoryVisitor.cs @@ -129,40 +129,36 @@ private Binder CreateBinder(AquilaSyntaxNode element) .Single(x => x.AquilaSyntax.SyntaxTree.FilePath == htmlDecl.SyntaxTree.FilePath); return new InContainerBinder(type, next); } + case FuncEx funcEx: + { + return new InLambdaBinder(next.Locals.BindLambda(funcEx), next); + } case ImportDecl import: break; case FuncDecl fd: { NamespaceOrTypeSymbol container; - //TODO: visibility - if (fd.FuncOwner != null) { - //check we need describe above the part type of this type - - var hasDeclaredType = ((CompilationUnitSyntax)fd.Parent).Types.Any(x => - x.Name.GetUnqualifiedName().Identifier.Text == fd.FuncOwner.OwnerType.ToString()); - - container = next.BindType(fd.FuncOwner.OwnerType); + container = next.TryResolveTypeSymbol(fd.FuncOwner.OwnerType); } else if (fd.IsGlobal) container = next.Container; else container = next.Container; - var methods = container.GetMembers(fd.Identifier.Text).OfType(); + var methods = container.GetMembers(fd.Identifier.Text).OfType().ToArray(); MethodSymbol candidate = null; if (!methods.Any()) { - candidate = new MissingMethodSymbol(name: fd.Identifier.Text); return next; } - else - //TODO: resolution overloads - candidate = methods.First(); + + //TODO: resolution overloads + candidate = methods.First(); return new InMethodBinder(candidate, next); ; @@ -206,7 +202,7 @@ public Binder VisitImportDecl(ImportDecl arg, Binder next) { return new InClrImportBinder(ns.First(), next); } - + return new InContainerBinder(ns.First(), next); } @@ -230,7 +226,8 @@ public Binder VisitImportDecl(ImportDecl arg, Binder next) var module = node.Module; if (module == null) - module = SyntaxFactory.ModuleDecl(SyntaxFactory.IdentifierName(WellKnownAquilaNames.MainModuleName)); + module = SyntaxFactory.ModuleDecl( + SyntaxFactory.IdentifierName(WellKnownAquilaNames.MainModuleName)); result = VisitModuleDecl(module, result); binderCache.TryAdd(key, result); 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..e4276a0c9 --- /dev/null +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/GlobalBinder.cs @@ -0,0 +1,33 @@ +using System.Collections.Immutable; +using System.Linq; +using Aquila.CodeAnalysis.Symbols; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Aquila.CodeAnalysis.Semantics; + +internal class GlobalBinder : InContainerBinder +{ + private readonly NamespaceOrTypeSymbol _container; + + public GlobalBinder(INamespaceOrTypeSymbol ns, Binder next) : base(ns, next) + { + _container = (NamespaceOrTypeSymbol)ns; + } + + public override NamespaceOrTypeSymbol Container => _container; + + protected override void FindMethodsByName(string name, ArrayBuilder result) + { + result.AddRange(_container.GetMembers(name).OfType()); + } + + protected override void FindSymbolByName(string name, ArrayBuilder> result, + FilterCriteria filterCriteria) + { + FindSymbolByNameHandler( + _container.GetMembers(name) + .Union(_container.GetTypeMembers(name, -1), SymbolEqualityComparer.Default).Cast(), + result, filterCriteria, () => { }); + } +} \ 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..e1052f38c --- /dev/null +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/InClrImportBinder.cs @@ -0,0 +1,77 @@ +using System.Collections.Immutable; +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 NamespaceOrTypeSymbol _container; + + public override Symbol ContainingSymbol => _container.ContainingSymbol; + + public InClrImportBinder(INamespaceOrTypeSymbol container, Binder next) : base(next) + { + Contract.ThrowIfNull(container); + _container = (NamespaceOrTypeSymbol)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.TryResolveTypeSymbol(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); + } + + protected override void FindSymbolByName(string name, ArrayBuilder> result, + FilterCriteria filterCriteria) + { + ArrayBuilder methods = new ArrayBuilder(); + FindMethodsByName(name, methods); + FindSymbolByNameHandler( + _container.GetMembers(name) + .Union(_container.GetTypeMembers(name, -1), SymbolEqualityComparer.Default) + .Union(methods, SymbolEqualityComparer.Default).Cast(), result, + filterCriteria, () => base.FindSymbolByName(name, result, filterCriteria)); + } +} \ 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..11f91f3d4 --- /dev/null +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/InContainerBinder.cs @@ -0,0 +1,65 @@ +using System.Collections.Immutable; +using System.Linq; +using Aquila.CodeAnalysis.Errors; +using Aquila.CodeAnalysis.Symbols; +using Aquila.CodeAnalysis.Syntax; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Aquila.CodeAnalysis.Semantics; + +internal class InContainerBinder : Binder +{ + private readonly NamespaceOrTypeSymbol _container; + + public InContainerBinder(INamespaceOrTypeSymbol container, Binder next) : base(next) + { + _container = (NamespaceOrTypeSymbol)container; + } + + public override NamespaceOrTypeSymbol Container => _container; + public override Symbol ContainingSymbol => _container.ContainingSymbol; + + + 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?.TryResolveTypeSymbol(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; + } + + protected override void FindSymbolByName(string name, ArrayBuilder> result, + FilterCriteria filterCriteria) + { + FindSymbolByNameHandler( + _container.GetMembers(name) + .Union(_container.GetTypeMembers(name, -1), SymbolEqualityComparer.Default).Cast(), + result, filterCriteria, () => base.FindSymbolByName(name, result, filterCriteria)); + } +} \ 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..a108120de --- /dev/null +++ b/src/Aquila.CodeAnalysis/Semantics/Binder/InMethodBinder.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Immutable; +using System.Linq; +using Aquila.CodeAnalysis.Symbols; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Aquila.CodeAnalysis.Semantics; + +internal sealed class InLambdaBinder : InMethodBinder +{ + public InLambdaBinder(SourceLambdaSymbol lambda, Binder next) : base(lambda, next) + { + } + + public override bool IsInLambda => true; +} + +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; + + public override Symbol ContainingSymbol => _method.ContainingSymbol; + + protected override void FindSymbolByName(string name, ArrayBuilder> result, + FilterCriteria filterCriteria) + { + FindSymbolByNameHandler(Locals + .Variables + .Where(x => x.Name == name) + .Select(x => x.Symbol) + .WhereNotNull(), result, filterCriteria, + () => base.FindSymbolByName(name, result, filterCriteria)); + ; + } +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/BoundExpression.cs b/src/Aquila.CodeAnalysis/Semantics/BoundExpression.cs index c57039321..e5646efd3 100644 --- a/src/Aquila.CodeAnalysis/Semantics/BoundExpression.cs +++ b/src/Aquila.CodeAnalysis/Semantics/BoundExpression.cs @@ -8,6 +8,7 @@ using System.Data; using System.Diagnostics; using Aquila.CodeAnalysis; +using Aquila.CodeAnalysis.CodeGen; using Aquila.CodeAnalysis.FlowAnalysis; using Aquila.Compiler.Utilities; using Aquila.Syntax; @@ -31,13 +32,15 @@ public struct BoundAccess /// /// The expression access kind - read, write, ensured. /// - AccessMask _flags; + readonly AccessMask _flags; /// /// Optional. Type the expression will be converted to. /// - TypeSymbol _targetType; + readonly TypeSymbol _targetType; + ImmutableArray _arguments = ImmutableArray.Empty; + #region Properties /// @@ -78,6 +81,11 @@ public struct BoundAccess /// public AccessMask Flags => _flags; + /// + /// Arguments of Access context + /// + public ImmutableArray Arguments => _arguments; + /// /// The variable will be aliased and read. /// @@ -209,6 +217,11 @@ public BoundAccess WithRefFlag(bool mightBeRef) return new BoundAccess(newflags, _targetType); } + public BoundAccess WithArguments(ImmutableArray arguments) + { + return new BoundAccess(_flags, _targetType) { _arguments = arguments }; + } + /// /// Simple read access. /// @@ -535,7 +548,7 @@ public partial class BoundLambda : BoundExpression, IAnonymousFunctionOperation ImmutableArray _usevars; - public IBlockOperation Body => null; + public IBlockOperation Body => null; public IMethodSymbol Signature => null; IMethodSymbol IAnonymousFunctionOperation.Symbol => null; @@ -594,6 +607,7 @@ public BoundEvalEx Update(BoundExpression code) return new BoundEvalEx(code).WithContext(this); } } + public override void Accept(OperationVisitor visitor) => visitor.DefaultVisit(this); public override TResult Accept(OperationVisitor visitor, @@ -657,7 +671,7 @@ public BoundCopyValue(BoundExpression expression) : base(null) public override TResult Accept(OperationVisitor visitor, TArgument argument) => visitor.DefaultVisit(this, argument); - + internal BoundCopyValue Update(BoundExpression expression) { return expression == Expression ? this : new BoundCopyValue(expression).WithAccess(this.Access); @@ -1042,12 +1056,7 @@ public partial class BoundVariableName : BoundOperation, IAquilaOperation public override int GetHashCode() => NameValue.GetHashCode() ^ (NameExpression != null ? NameExpression.GetHashCode() : 0); - string DebugView - { - get { return IsDirect ? NameValue.ToString() : "{indirect}"; } - } - - public bool IsDirect => NameExpression == null; + string DebugView => NameValue.ToString(); public AquilaSyntaxNode AquilaSyntax { get; set; } @@ -1061,11 +1070,6 @@ public BoundVariableName(string name, ITypeSymbol type) { } - public BoundVariableName(BoundExpression nameExpr, ITypeSymbol type) - : this(default, nameExpr, type) - { - } - public BoundVariableName Update(VariableName name, BoundExpression nameExpr) { if (name.NameEquals(NameValue) && nameExpr == NameExpression) @@ -1104,6 +1108,11 @@ public BoundVariableRef(string name, ITypeSymbol type) : this( /// internal IVariableReference Variable { get; set; } + /// + /// Indicates the variable is captured in a closure. + /// + internal bool IsCaptured { get; set; } + /// /// Local in case of the variable is resolved local variable. /// @@ -1122,21 +1131,18 @@ partial void AcceptImpl(OperationVisitor visitor, TArg a } } - /// - /// A non-source synthesized variable reference that can be read or written to. - /// - /// - /// Inheriting from BoundVariableRef is just a temporary measure. Do NOT take dependencies on anything but IReferenceExpression. - /// - public partial class BoundTemporalVariableRef + public partial class BoundMethodRef { - private string _name; + internal override IVariableReference BindPlace(CodeGenerator cg) + { + throw new NotImplementedException(); + } - partial void OnCreateImpl(BoundVariableName name, ITypeSymbol typeSymbol) + internal override IPlace Place() { - + throw new NotImplementedException(); } - } + } #endregion @@ -1589,6 +1595,7 @@ public BoundOffsetExists Update(BoundExpression receiver, BoundExpression index) return new BoundOffsetExists(receiver, index).WithContext(this); } } + public override void Accept(OperationVisitor visitor) => visitor.DefaultVisit(this); @@ -1676,5 +1683,4 @@ public partial class BoundGroupedEx public partial class BoundBadEx { } - } \ No newline at end of file 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/ExpressionsExtension.cs b/src/Aquila.CodeAnalysis/Semantics/ExpressionsExtension.cs index 92550cf0f..6642aa8cc 100644 --- a/src/Aquila.CodeAnalysis/Semantics/ExpressionsExtension.cs +++ b/src/Aquila.CodeAnalysis/Semantics/ExpressionsExtension.cs @@ -36,25 +36,15 @@ public static T WithContext(this T expr, BoundExpression other) where T : Bou /// public static bool IsEmptyStringValue(object value) { - if (value == null) - return true; - - if (value is string str && str.Length == 0) - return true; - - if (value is bool b && b == false) - return true; - - return false; + switch (value) + { + case null: + case string { Length: 0 }: + case false: + return true; + default: + return false; + } } - - /// - /// Returns whether the expression can possibly have any side effects. - /// - public static bool CanHaveSideEffects(this BoundExpression expr) => - // TODO: Make more precise and less defensive - !(expr.ConstantValue.HasValue - || expr is BoundVariableRef varExpr && varExpr.Name.IsDirect - || expr is BoundLiteral); } } \ 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..a72406a3f 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Graph/ControlFlowGraph.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Graph/ControlFlowGraph.cs @@ -11,8 +11,6 @@ namespace Aquila.CodeAnalysis.Semantics.Graph /// public sealed partial class ControlFlowGraph { - #region LabelBlockFlags, LabelBlockInfo - /// /// Found label reference (definition or target) information. /// @@ -66,84 +64,57 @@ public sealed class LabelBlockState public LabelBlockFlags Flags; } - #endregion + private readonly BoundBlock _start; + private readonly ImmutableArray _unreachable; + private readonly ImmutableArray _yields; + private readonly ImmutableArray _labels; + private readonly BoundBlock _exit; - #region Fields & Properties + /// + /// Last "tag" color used. Used internally for graph algorithms. + /// + private int _lastColor = 0; /// /// Gets the control flow start block. Cannot be null. /// - public BoundBlock Start - { - get { return _start; } - } - - readonly BoundBlock - _start; + public BoundBlock Start => _start; /// /// Gets the control flow exit block. Cannot be null. /// - public BoundBlock Exit - { - get { return _exit; } - } - - readonly BoundBlock - _exit; + public BoundBlock Exit => _exit; /// /// Array of labels within method. Can be null. /// - public ImmutableArray Labels - { - get { return _labels; } - } + public ImmutableArray Labels => _labels; - readonly ImmutableArray _labels; /// /// Array of yield statements within method. Can be null. /// - public ImmutableArray Yields - { - get => _yields; - } + public ImmutableArray Yields => _yields; - readonly ImmutableArray _yields; /// /// List of blocks that are unreachable syntactically (statements after JumpStmt etc.). /// - public ImmutableArray UnreachableBlocks - { - get { return _unreachable; } - } - - readonly ImmutableArray - _unreachable; + public ImmutableArray UnreachableBlocks => _unreachable; - /// - /// Last "tag" color used. Used internally for graph algorithms. - /// - int _lastcolor = 0; - #endregion - - #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) { } @@ -170,25 +141,21 @@ internal ControlFlowGraph Update(BoundBlock start, BoundBlock exit, ImmutableArr { return this; } - else + + return new ControlFlowGraph(start, exit, ImmutableArray.Empty, null, labels, + unreachable) { - return new ControlFlowGraph(start, exit, ImmutableArray.Empty, null, labels, - unreachable) - { - _lastcolor = this._lastcolor - }; - } + _lastColor = this._lastColor + }; } - #endregion - /// /// Gets new (unique) color for use by graph algorithms. /// /// New color index. public int NewColor() { - return unchecked(++_lastcolor); + return unchecked(++_lastColor); } /// diff --git a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphBuilder.cs b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphBuilder.cs index 286529327..9502a531a 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/Graph/GraphRewriter.cs b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphRewriter.cs index 032897fb5..afa92d804 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphRewriter.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphRewriter.cs @@ -3,10 +3,6 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using System.Text; -using Aquila.CodeAnalysis.FlowAnalysis; -using Aquila.CodeAnalysis.Symbols; -using Aquila.CodeAnalysis.Symbols.Source; using Aquila.CodeAnalysis.Utilities; namespace Aquila.CodeAnalysis.Semantics.Graph @@ -43,7 +39,7 @@ public class GraphRewriter : GraphUpdater /// Clones unmodified blocks and fixes the edges between them so that no edge targets /// a block from the previous version of the graph. /// - private class GraphRepairer : GraphUpdater + private sealed class GraphRepairer : GraphUpdater { private readonly GraphRewriter _rewriter; @@ -81,15 +77,15 @@ private BoundBlock Repair(BoundBlock block) return block; } - public sealed override object VisitCFGBlock(BoundBlock x) => Repair(x); + public override object VisitCFGBlock(BoundBlock x) => Repair(x); - public sealed override object VisitCFGStartBlock(StartBlock x) => Repair(x); + public override object VisitCFGStartBlock(StartBlock x) => Repair(x); - public sealed override object VisitCFGExitBlock(ExitBlock x) => Repair(x); + public override object VisitCFGExitBlock(ExitBlock x) => Repair(x); - public sealed override object VisitCFGCatchBlock(CatchBlock x) => Repair(x); + public override object VisitCFGCatchBlock(CatchBlock x) => Repair(x); - public sealed override object VisitCFGCaseBlock(MatchArmBlock x) => Repair(x); + public override object VisitCFGCaseBlock(MatchArmBlock x) => Repair(x); } /// @@ -97,7 +93,7 @@ private BoundBlock Repair(BoundBlock block) /// of the original graph. Marks all declarations as unreachable. The blocks encountered along the way are /// coloured as a side effect. /// - private class UnreachableProcessor : GraphExplorer + private sealed class UnreachableProcessor : GraphExplorer { private readonly GraphRewriter _rewriter; @@ -119,13 +115,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 @@ -205,40 +194,47 @@ public sealed override object VisitCFG(ControlFlowGraph x) var unreachableBlocks = x.UnreachableBlocks; // Fix the structure of the graph if any changes were performed - if (_updatedBlocks != null) + if (_updatedBlocks == null) + return x.Update( + updatedStart, + updatedExit, + x.Labels, // Keep all the labels, they are here only for the diagnostic purposes + yields, + unreachableBlocks); + + Debug.Assert(updatedStart != x.Start); + + // Rescan and repair nodes and edges if any blocks were modified + var repairer = new GraphRepairer(this); + updatedStart = (StartBlock)updatedStart.Accept(repairer); + updatedExit = TryGetNewVersion(x.Exit); + + // Handle newly unreachable blocks + var newlyUnreachableBlocks = + _possiblyUnreachableBlocks?.Where(b => !IsExplored(b)).ToList() // Confirm that they are unexplored + ?? Enumerable.Empty(); + var boundBlocks = newlyUnreachableBlocks.ToList(); + + if (boundBlocks.Any()) { - Debug.Assert(updatedStart != x.Start); - - // Rescan and repair nodes and edges if any blocks were modified - var repairer = new GraphRepairer(this); - updatedStart = (StartBlock)updatedStart.Accept(repairer); - updatedExit = TryGetNewVersion(x.Exit); - - // Handle newly unreachable blocks - var newlyUnreachableBlocks = - _possiblyUnreachableBlocks?.Where(b => !IsExplored(b)).ToList() // Confirm that they are unexplored - ?? Enumerable.Empty(); - if (newlyUnreachableBlocks.Any()) - { - // Scan all the newly unreachable blocks (for yields, declarations,...) - var unreachableProcessor = new UnreachableProcessor(this, ExploredColor); - newlyUnreachableBlocks.ForEach(b => b.Accept(unreachableProcessor)); + // Scan all the newly unreachable blocks (for yields, declarations,...) + var unreachableProcessor = new UnreachableProcessor(this, ExploredColor); + boundBlocks.ForEach(b => b.Accept(unreachableProcessor)); - // Remove the discovered yields from the next CFG version - if (unreachableProcessor.Yields != null) - { - yields = yields.RemoveRange(unreachableProcessor.Yields); - } + // Remove the discovered yields from the next CFG version + if (unreachableProcessor.Yields != null) + { + yields = yields.RemoveRange(unreachableProcessor.Yields); } - - // Repair all the unreachable blocks so that they reference the updated versions of the blocks - // (enables to properly produce reachability diagnostics) - unreachableBlocks = - unreachableBlocks.Concat(newlyUnreachableBlocks) - .Select(b => (BoundBlock)b.Accept(repairer)) - .ToImmutableArray(); } + // Repair all the unreachable blocks so that they reference the updated versions of the blocks + // (enables to properly produce reachability diagnostics) + unreachableBlocks = + unreachableBlocks.Concat(boundBlocks) + .Select(b => (BoundBlock)b.Accept(repairer)) + .ToImmutableArray(); + // Create a new CFG from the new versions of blocks and edges (expressions and statements are reused where unchanged) return x.Update( updatedStart, @@ -334,9 +330,5 @@ public sealed override object VisitCFGCaseBlock(MatchArmBlock x) public virtual MatchArmBlock OnVisitCFGCaseBlock(MatchArmBlock x) => (MatchArmBlock)base.VisitCFGCaseBlock(x); #endregion - - protected private virtual void OnUnreachableMethodFound(SourceMethodSymbolBase method) - { - } } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphUpdater.cs b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphUpdater.cs index 75d0874b6..e3304bbae 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphUpdater.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphUpdater.cs @@ -405,7 +405,7 @@ public override object VisitCompoundAssignEx(BoundCompoundAssignEx x) public override object VisitCallEx(BoundCallEx x) { var updatedArgs = x.Arguments.Select(a => (BoundArgument)Accept(a)).ToImmutableArray(); - return x.Update(x.MethodSymbol, updatedArgs, x.TypeArguments, x.Instance, x.ResultType); + return x.Update(x.MethodSymbol, updatedArgs, x.Instance, x.ResultType); } public override object VisitVariableName(BoundVariableName x) @@ -421,12 +421,6 @@ public override object VisitVariableRef(BoundVariableRef x) return x.Update(variable, x.ResultType); } - public override object VisitTemporalVariableRef(BoundTemporalVariableRef x) - { - Debug.Assert(x.Name.IsDirect); - return x; - } - public override object VisitListEx(BoundListEx x) { var items = VisitImmutableArrayPairs(x.Items); @@ -486,11 +480,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..4e4818d8f 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Graph/GraphWalker.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Graph/GraphWalker.cs @@ -243,14 +243,6 @@ public override T VisitVariableRef(BoundVariableRef x) return default; } - public override T VisitTemporalVariableRef(BoundTemporalVariableRef x) - { - // BoundSynthesizedVariableRef is based solely on BoundVariableRef so far - VisitVariableRef(x); - - return default; - } - public override T VisitListEx(BoundListEx x) { x.Items.ForEach(pair => @@ -338,11 +330,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; diff --git a/src/Aquila.CodeAnalysis/Semantics/LocalsTable.cs b/src/Aquila.CodeAnalysis/Semantics/LocalsTable.cs index 87f64a027..54d987a61 100644 --- a/src/Aquila.CodeAnalysis/Semantics/LocalsTable.cs +++ b/src/Aquila.CodeAnalysis/Semantics/LocalsTable.cs @@ -1,11 +1,10 @@ using Aquila.CodeAnalysis.Symbols; using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using Aquila.CodeAnalysis.FlowAnalysis; -using Aquila.CodeAnalysis.Symbols.Source; using Aquila.CodeAnalysis.Syntax; -using Aquila.Syntax.Ast; using Microsoft.CodeAnalysis.Text; namespace Aquila.CodeAnalysis.Semantics @@ -13,34 +12,31 @@ namespace Aquila.CodeAnalysis.Semantics /// /// Table of local variables used within method. /// - internal sealed partial class LocalsTable + internal sealed class LocalsTable { - #region Fields & Properties - - readonly Dictionary /*!*/ - _dict = new Dictionary(); + private readonly Dictionary _variables = new(); + private readonly SourceMethodSymbolBase _method; + private readonly Dictionary _lambdas = new(); + + private readonly List _capturedVariables = new(); /// /// Enumeration of direct local variables. /// - public IEnumerable Variables => _dict.Values; + public IEnumerable Variables => _variables.Values; + + public IEnumerable CapturedVariables => _capturedVariables; /// /// Count of local variables. /// - public int Count => _dict.Count; + public int Count => _variables.Count; /// /// Containing method. Cannot be null. /// public SourceMethodSymbolBase Method => _method; - readonly SourceMethodSymbolBase _method; - - #endregion - - #region Construction - /// /// Initializes table of locals of given method. /// @@ -50,44 +46,32 @@ public LocalsTable(SourceMethodSymbolBase method) _method = method; - // PopulateParameters(); } - #endregion - - void PopulateParameters() + private void PopulateParameters() { - // parameters foreach (var p in _method.SourceParameters) { - _dict[new VariableName(p.Name)] = new ParameterReference(p, Method); + _variables[new VariableName(p.Name)] = new ParameterReference(p, Method); } if (!_method.IsStatic) { - _dict[VariableName.ThisVariableName] = new ThisVariableReference(_method); + _variables[VariableName.ThisVariableName] = new ThisVariableReference(_method); } } - LocalVariableReference CreateAutoGlobal(VariableName name, TextSpan span) - { - throw new NotImplementedException(); - } - LocalVariableReference CreateLocal(VariableName name, VariableKind kind, VariableInit decl) { - Debug.Assert(!name.IsAutoGlobal); var locSym = new SourceLocalSymbol(Method, decl); Method.Flags |= MethodFlags.UsesLocals; return new LocalVariableReference(kind, Method, locSym, new BoundVariableName(name, locSym.Type)); } - LocalVariableReference CreateLocal(VariableName name, VariableKind kind, TypeSymbol type) { - Debug.Assert(!name.IsAutoGlobal); var locSym = new SynthesizedLocalSymbol(Method, name.Value, type); Method.Flags |= MethodFlags.UsesLocals; @@ -95,18 +79,20 @@ LocalVariableReference CreateLocal(VariableName name, VariableKind kind, TypeSym return new LocalVariableReference(kind, Method, locSym, new BoundVariableName(name, locSym.Type)); } - #region Public methods + public bool TryGetVariable(string name, out LocalVariableReference variable) => + _variables.TryGetValue(new VariableName(name), out variable); + public bool TryGetVariable(VariableName varname, out LocalVariableReference variable) => - _dict.TryGetValue(varname, out variable); + _variables.TryGetValue(varname, out variable); - IVariableReference BindVariable(VariableName varname, TextSpan span, - Func factory) + IVariableReference BindVariable(VariableName varname, + Func factory) { - if (!_dict.TryGetValue(varname, out var value)) + if (!_variables.TryGetValue(varname, out var value)) { - _dict[varname] = value = factory(varname, span); + _variables[varname] = value = factory(varname); } // @@ -114,19 +100,30 @@ IVariableReference BindVariable(VariableName varname, TextSpan span, return value; } + public SourceLambdaSymbol BindLambda(FuncEx lambdaEx) + { + if (_lambdas.TryGetValue(lambdaEx, out var lambdaSymbol)) + { + return lambdaSymbol; + } + + lambdaSymbol = new SourceLambdaSymbol(_method, lambdaEx); + _lambdas.Add(lambdaEx, lambdaSymbol); + return lambdaSymbol; + } + /// /// Gets local variable or create local if not yet. /// - public IVariableReference BindLocalVariable(VariableName varname, VariableInit decl) => BindVariable(varname, - decl.Span, (name, span) => CreateLocal(name, VariableKind.LocalVariable, decl)); + public IVariableReference BindLocalVariable(VariableName varName, VariableInit decl) => BindVariable(varName, + name => CreateLocal(name, VariableKind.LocalVariable, decl)); - public IVariableReference BindTemporalVariable(VariableName varname, TypeSymbol type) => - BindVariable(varname, default, (name, _) - => CreateLocal(name, VariableKind.LocalTemporalVariable, type)); - public IVariableReference BindLocalVariable(VariableName varName, TextSpan span, TypeSymbol type) => - BindVariable(varName, span, (_, _) => new LocalVariableReference(VariableKind.LocalVariable, _method, - new InPlaceSourceLocalSymbol(_method, varName, span, type), new BoundVariableName(varName, type))); + BindVariable(varName, name => new LocalVariableReference(VariableKind.LocalVariable, _method, + new InPlaceSourceLocalSymbol(_method, name, span, type), new BoundVariableName(name, type))); + + public IVariableReference BindTemporalVariable(VariableName varName, TypeSymbol type) => + BindVariable(varName, name => CreateLocal(name, VariableKind.LocalTemporalVariable, type)); #endregion } diff --git a/src/Aquila.CodeAnalysis/Semantics/Model/SourceSymbolProvider.cs b/src/Aquila.CodeAnalysis/Semantics/Model/SourceSymbolProvider.cs index 1d0d795db..b5fe1b3ab 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Model/SourceSymbolProvider.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Model/SourceSymbolProvider.cs @@ -18,6 +18,6 @@ public SourceSymbolProvider(SourceSymbolCollection table) public INamedTypeSymbol ResolveType(QualifiedName name, Dictionary resolved) => - _table.GetType(name, resolved); + _table.TryGetType(name, resolved); } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Semantics/Names.cs b/src/Aquila.CodeAnalysis/Semantics/Names.cs index d57b4a52f..893f5165c 100644 --- a/src/Aquila.CodeAnalysis/Semantics/Names.cs +++ b/src/Aquila.CodeAnalysis/Semantics/Names.cs @@ -256,48 +256,7 @@ public string Value #endregion - public bool IsThisVariableName - { - get { return this == ThisVariableName; } - } - - #region IsAutoGlobal - - /// - /// Gets value indicting whether the name represents an auto-global variable. - /// - public bool IsAutoGlobal - { - get { return IsAutoGlobalVariableName(this.Value); } - } - - /// - /// Checks whether a specified name is the name of an auto-global variable. - /// - /// The name. - /// Whether is auto-global. - public static bool IsAutoGlobalVariableName(string name) - { - switch (name) - { - case GlobalsName: - case ServerName: - case EnvName: - case CookieName: - case HttpRawPostDataName: - case FilesName: - case RequestName: - case GetName: - case PostName: - case SessionName: - return true; - - default: - return false; - } - } - - #endregion + public bool IsThisVariableName => this == ThisVariableName; #endregion 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/Aquila/IAquilaMethodSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Aquila/IAquilaMethodSymbol.cs index e82f3bb76..b62f30b15 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Aquila/IAquilaMethodSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Aquila/IAquilaMethodSymbol.cs @@ -13,11 +13,5 @@ public interface IAquilaMethodSymbol : IMethodSymbol /// Can be null for routines from PE. /// ControlFlowGraph ControlFlowGraph { get; } - - - /// - /// Gets value indicating the routine represents a global code. - /// - bool IsGlobalScope { get; } } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Symbols/MethodSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/MethodSymbol.cs index d0c4c02c6..c39e745b3 100644 --- a/src/Aquila.CodeAnalysis/Symbols/MethodSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/MethodSymbol.cs @@ -297,7 +297,10 @@ IMethodSymbol IMethodSymbol.Construct(ImmutableArray typeArguments, public virtual ControlFlowGraph ControlFlowGraph { get => null; - internal set { } + internal set + { + // ignored + } } /// diff --git a/src/Aquila.CodeAnalysis/Symbols/OverloadsList.cs b/src/Aquila.CodeAnalysis/Symbols/OverloadsList.cs index 14505216e..3b7e76a10 100644 --- a/src/Aquila.CodeAnalysis/Symbols/OverloadsList.cs +++ b/src/Aquila.CodeAnalysis/Symbols/OverloadsList.cs @@ -1,18 +1,20 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; using Aquila.CodeAnalysis.FlowAnalysis; using Aquila.CodeAnalysis.Semantics; using Aquila.CodeAnalysis.Utilities; +using EnumerableExtensions = Roslyn.Utilities.EnumerableExtensions; namespace Aquila.CodeAnalysis.Symbols { /// /// List of overloads for a function call. /// - internal struct OverloadsList + internal readonly struct OverloadsList { /// /// Defines the scope of members visibility. @@ -89,12 +91,11 @@ public MethodSymbol Resolve(TypeRefContext typeCtx, ImmutableArray !m.IsStatic); } } - else - { - } - // if (scope.ScopeIsDynamic && result.Any(IsNonPublic)) { // we have to postpone the resolution to runtime: @@ -144,47 +141,13 @@ public MethodSymbol Resolve(TypeRefContext typeCtx, ImmutableArray(); - - foreach (var m in result) - { - var nmandatory = 0; - var hasoptional = false; - var hasparams = false; - var match = true; - var hasunpacking = false; - - var expectedparams = m.Parameters; - - for (int i = 0; i < expectedparams.Count(); i++) - { - var p = expectedparams[i]; - } - - // - if ((args.Length >= nmandatory || hasunpacking) && (hasparams || args.Length <= expectedparams.Count())) - { - // TODO: this is naive implementation of overload resolution, - // make it properly using Conversion Cost - if (match && !hasparams) - { - return m; // perfect match - } - - // - result2.Add(m); - } - } - - // - return (result2.Count == 1) ? result2[0] : new AmbiguousMethodSymbol(result.AsImmutable(), true); + var m = EnumerableExtensions.WhereNotNull(result) + .FirstOrDefault(m => args.Length >= 0 && args.Length <= m.Parameters.Length); + + return m != null ? m : new AmbiguousMethodSymbol(result.AsImmutable(), true); } - static bool IsNonPublic(MethodSymbol m) => m.DeclaredAccessibility != Accessibility.Public; + private static bool IsNonPublic(MethodSymbol m) => m.DeclaredAccessibility != Accessibility.Public; /// /// Removes methods that are inaccessible for sure. diff --git a/src/Aquila.CodeAnalysis/Symbols/Platform/PlatformTypeManager.cs b/src/Aquila.CodeAnalysis/Symbols/Platform/PlatformTypeManager.cs index 6aab9a8c7..d2db5d878 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Platform/PlatformTypeManager.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Platform/PlatformTypeManager.cs @@ -65,7 +65,6 @@ public SynthesizedTypeSymbol SynthesizeType(NamespaceOrTypeSymbol container, str return type; } - public SynthesizedUnionTypeSymbol SynthesizeUnionType(NamespaceOrTypeSymbol container, IEnumerable types) { @@ -73,8 +72,13 @@ public SynthesizedUnionTypeSymbol SynthesizeUnionType(NamespaceOrTypeSymbol cont var symbol = _lazySynthesizedTypes.OfType() .FirstOrDefault(x => - x.ContainingTypes.OrderBy(x => x.Name).ThenBy(x => x.SpecialType) - .SequenceEqual(types.OrderBy(x => x.Name).ThenBy(x => x.SpecialType))); + x.ContainingTypes + .OrderBy(x => x.Name) + .ThenBy(x => x.SpecialType) + .SequenceEqual( + types.OrderBy(x => x.Name) + .ThenBy(x => x.SpecialType), (typeSymbol, symbol1) => + typeSymbol.Equals(symbol1))); if (symbol != null) return symbol; @@ -139,7 +143,7 @@ private void EnsureMetadataPopulated() #endregion - internal NamedTypeSymbol GetType(QualifiedName name, + internal NamedTypeSymbol TryGetType(QualifiedName name, Dictionary resolved = null) { EnsureMetadataPopulated(); @@ -153,23 +157,15 @@ internal NamedTypeSymbol GetType(QualifiedName name, if (first == null) { first = t; + alternatives = new List() { first }; } else { - // ambiguity - if (alternatives == null) - { - alternatives = new List() { first }; - } - alternatives.Add(t); } } - var result = - (alternatives != null) - ? new AmbiguousErrorTypeSymbol(alternatives.AsImmutable()) // ambiguity - : first ?? new MissingMetadataTypeSymbol(name.ClrName(), 0, false); + var result = alternatives?.Count == 1 ? first : null; if (resolved != null) { @@ -199,7 +195,7 @@ internal ImmutableArray GetNamespaces() internal SynthesizedTypeSymbol GetSynthesizedType(QualifiedName name, Dictionary resolved = null) { - var type = GetType(name, resolved); + var type = TryGetType(name, resolved); if (type is SynthesizedTypeSymbol st) return st; diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceAssemblySymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceAssemblySymbol.cs index 8935f77cd..e5b1e0b87 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceAssemblySymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceAssemblySymbol.cs @@ -296,7 +296,7 @@ internal override NamedTypeSymbol TryLookupForwardedMetadataTypeWithCycleDetecti public override NamedTypeSymbol GetTypeByMetadataName(string fullyQualifiedMetadataName) { - return SourceModule.SymbolCollection.GetType( + return SourceModule.SymbolCollection.TryGetType( NameUtils.MakeQualifiedName(fullyQualifiedMetadataName.Replace('.', QualifiedName.Separator), true)); } diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceFieldSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceFieldSymbol.cs index 8ffe5bf2e..23d3a4525 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceFieldSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceFieldSymbol.cs @@ -166,7 +166,7 @@ internal override ConstantValue GetConstantValue(bool earlyDecodingWellKnownAttr internal override TypeSymbol GetFieldType(ConsList fieldsBeingBound) { var binder = DeclaringCompilation.GetBinder(_fieldSyntax); - return binder.BindType(_fieldSyntax.Type); + return binder.TryResolveTypeSymbol(_fieldSyntax.Type); } /// diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceGlobalNamespaceSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceGlobalNamespaceSymbol.cs index 0057a016c..eebf8f0a6 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceGlobalNamespaceSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceGlobalNamespaceSymbol.cs @@ -190,7 +190,7 @@ public override ImmutableArray GetTypeMembers(string name) { EnsureUserVisibleTypes(); - var x = _sourceModule.SymbolCollection.GetType(NameUtils.MakeQualifiedName(name, true)); + var x = _sourceModule.SymbolCollection.TryGetType(NameUtils.MakeQualifiedName(name, true)); if (x != null) { if (x.IsErrorType()) @@ -218,7 +218,7 @@ public override ImmutableArray GetTypeMembers(string name) } var type = _sourceModule.DeclaringCompilation.PlatformSymbolCollection - .GetType(QualifiedName.Parse(name, false)); + .TryGetType(QualifiedName.Parse(name, false)); if (type != null) builder.Add(type); diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs new file mode 100644 index 000000000..acc870bb8 --- /dev/null +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceLambdaSymbol.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Aquila.CodeAnalysis.Semantics; +using Aquila.CodeAnalysis.Syntax; +using Microsoft.CodeAnalysis; + +namespace Aquila.CodeAnalysis.Symbols; + +internal sealed class SourceLambdaSymbol : SourceMethodSymbolBase +{ + private readonly FuncEx _functionExpr; + + public SourceLambdaSymbol(Symbol containingSymbol, FuncEx functionExpr) : base(containingSymbol) + { + _functionExpr = functionExpr; + } + + public override Accessibility DeclaredAccessibility => Accessibility.Internal; + + public override bool IsStatic => false; + + internal override ParameterListSyntax SyntaxSignature => _functionExpr.ParameterList; + + internal override TypeEx SyntaxReturnType => _functionExpr.ReturnType; + + internal override AquilaSyntaxNode Syntax => _functionExpr; + + internal override IEnumerable Statements => _functionExpr.Body?.Statements; + + protected override Binder GetMethodBinderCore() + { + return DeclaringCompilation.GetBinder(_functionExpr); + } + + public override void GetDiagnostics(DiagnosticBag diagnostic) + { + } +} \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceLocalSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceLocalSymbol.cs index d9985547e..49af1e64c 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceLocalSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceLocalSymbol.cs @@ -138,7 +138,7 @@ public virtual ITypeSymbol Type else { - tsymbol = binder.BindType(langElem); + tsymbol = binder.TryResolveTypeSymbol(langElem); } return tsymbol; diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbol.cs index 44ca83737..e6f25a69d 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbol.cs @@ -1,91 +1,51 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Collections.Immutable; 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; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Collections.Internal; +using Roslyn.Utilities; namespace Aquila.CodeAnalysis.Symbols; internal sealed class SourceMethodSymbol : SourceMethodSymbolBase { - readonly FuncDecl _syntax; - public SourceMethodSymbol(NamedTypeSymbol type, FuncDecl syntax): base(type) + public SourceMethodSymbol(Symbol containingSymbol, FuncDecl syntax) : base(containingSymbol) { - Contract.ThrowIfNull(syntax); - _syntax = syntax; } - - TextSpan NameSpan => _syntax.Identifier.Span; - + internal override ParameterListSyntax SyntaxSignature => _syntax.ParameterList; - internal override TypeEx SyntaxReturnType => _syntax.ReturnType; + internal override TypeEx SyntaxReturnType => _syntax.ReturnType; 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) { - } 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 GetMethodBinderCore() + { + return DeclaringCompilation.GetBinder(_syntax); } - - + public override Accessibility DeclaredAccessibility { get @@ -108,7 +68,11 @@ public override ImmutableArray GetAttributes() { foreach (var attr in attrList.Attributes) { - var type = (NamedTypeSymbol)DeclaringCompilation.GetBinder(_syntax).BindType(attr.Name); + var type = (NamedTypeSymbol)DeclaringCompilation.GetBinder(_syntax).TryResolveTypeSymbol(attr.Name); + + if (type is null) + throw new InvalidOperationException($"Type '{attr.Name}' not found"); + builder.Add(new SourceAttributeData(null, type, type.Ctor(), false)); } } diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbolBase.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbolBase.cs index b3cb4bb71..d555612bd 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbolBase.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceMethodSymbolBase.cs @@ -19,36 +19,34 @@ namespace Aquila.CodeAnalysis.Symbols /// /// Represents a Aquila class method. /// - internal abstract partial class SourceMethodSymbolBase : MethodSymbol + internal abstract partial class SourceMethodSymbolBase : MethodSymbol { - private readonly NamedTypeSymbol _type; + private readonly Symbol _type; private MethodSymbol _lazyOverridenMethod; - public SourceMethodSymbolBase(NamedTypeSymbol type) + protected SourceMethodSymbolBase(Symbol type) { Contract.ThrowIfNull(type); _type = type; } - + internal bool RequiresLateStaticBoundParam => - IsStatic && // `static` in instance method == typeof($this) - ControlFlowGraph != null && // cfg sets {Flags} - (this.Flags & MethodFlags.UsesLateStatic) != 0 - //&& (!_type.IsSealed || _type.IsTrait) - ; // `static` == `self` <=> self is sealed + IsStatic && + ControlFlowGraph != null && + (this.Flags & MethodFlags.UsesLateStatic) != 0; public override IMethodSymbol OverriddenMethod { get { - if ((_commonflags & CommonFlags.OverriddenMethodResolved) == 0) - { - Interlocked.CompareExchange(ref _lazyOverridenMethod, this.ResolveOverride(), null); + if ((_commonFlags & CommonFlags.OverriddenMethodResolved) != 0) + return _lazyOverridenMethod; + + Interlocked.CompareExchange(ref _lazyOverridenMethod, this.ResolveOverride(), null); - Debug.Assert(_lazyOverridenMethod != this); + Debug.Assert(_lazyOverridenMethod != this); - _commonflags |= CommonFlags.OverriddenMethodResolved; - } + _commonFlags |= CommonFlags.OverriddenMethodResolved; return _lazyOverridenMethod; } @@ -56,32 +54,27 @@ public override IMethodSymbol OverriddenMethod internal abstract ParameterListSyntax SyntaxSignature { get; } - internal abstract TypeEx SyntaxReturnType { get; } + internal abstract TypeEx SyntaxReturnType { get; } internal abstract AquilaSyntaxNode Syntax { get; } - internal abstract IList Statements { get; } + internal abstract IEnumerable Statements { get; } public abstract void GetDiagnostics(DiagnosticBag diagnostic); - - public override Symbol ContainingSymbol => _type; - - public override ImmutableArray DeclaringSyntaxReferences { get { throw new NotImplementedException(); } } - - public override bool IsAbstract => false; + public override bool IsAbstract => false; public override bool IsOverride => IsVirtual && this.OverriddenMethod != null && this.SignaturesMatch((MethodSymbol)this.OverriddenMethod); - public override bool IsSealed => false; + public override bool IsSealed => false; public override bool IsVirtual { @@ -102,12 +95,14 @@ protected enum CommonFlags OverriddenMethodResolved = 1, } - /// Internal true/false values. Initially all false. - protected CommonFlags _commonflags; - protected ControlFlowGraph _cfg; - LocalsTable _locals; + /// + /// Internal true/false values. Initially all false. + /// + private CommonFlags _commonFlags; + + private ControlFlowGraph _cfg; + private LocalsTable _locals; - /// /// Gets table of local variables. @@ -127,17 +122,18 @@ internal LocalsTable LocalsTable } public override ImmutableArray Locations => - ImmutableArray.Create( - Location.Create(null, Syntax is AquilaSyntaxNode element ? element.Span : default - )); + ImmutableArray.Create(Location.Create(Syntax.SyntaxTree, Syntax is { } element ? element.Span : default)); public override bool IsUnreachable => (Flags & MethodFlags.IsUnreachable) != 0; protected ImmutableArray _implicitParameters; private SourceParameterSymbol[] _srcParams; - /// Implicitly declared [params] parameter if the method allows access to its arguments. This allows more arguments to be passed than declared. - private SynthesizedParameterSymbol _implicitVarArg; // behaves like a stack of optional parameters + /// + /// Implicitly declared [params] parameter if the method allows access to its arguments. + /// This allows more arguments to be passed than declared. + /// + private SynthesizedParameterSymbol _implicitVarArg; internal class ImplicitParametersBuilder { @@ -150,7 +146,6 @@ public void Add(Func factory) } public ImmutableArray Build() => _builder.ToImmutableAndFree(); - } /// @@ -164,8 +159,8 @@ protected virtual ImplicitParametersBuilder PrepareImplicitParams() if (IsStatic) { // Context - builder.Add(index => new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.AqContext, - SpecialParameterSymbol.ContextName, index++)); + builder.Add(index => new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.AqContext, + SpecialParameterSymbol.ContextName, index++)); } return builder; @@ -306,7 +301,6 @@ internal ParameterSymbol GetParamsParameter() public override bool IsExtern => false; - public override bool CastToFalse => false; // source methods never cast special values to FALSE public override bool HasNotNull => !ReturnsNull; @@ -371,39 +365,75 @@ public sealed override int ParameterCount } } + public override TypeSymbol ReturnType => + SyntaxReturnType == null + ? DeclaringCompilation.GetSpecialType(SpecialType.System_Void) + : GetMethodBinderCore().TryResolveTypeSymbol(SyntaxReturnType); + public override bool ReturnsVoid => ReturnType.SpecialType == SpecialType.System_Void; /// /// Gets value indicating the method can return null. /// - public bool ReturnsNull + public bool ReturnsNull => true; + + public override RefKind RefKind => RefKind.None; + + /// + /// Lazily bound semantic block. + /// Entry point of analysis and emitting. + /// + public override ControlFlowGraph ControlFlowGraph { - get { return true; } + get + { + if (_cfg != null || this.Statements == null) + { + return _cfg; + } + + Interlocked.CompareExchange(ref _cfg, CreateControlFlowGraphCore(), null); + + return _cfg; + } + internal set => _cfg = value; } - public override RefKind RefKind => RefKind.None; + protected virtual Binder GetMethodBinderCore() + { + throw new NotImplementedException(); + } + + protected virtual ControlFlowGraph CreateControlFlowGraphCore() + { + var binder = GetMethodBinderCore(); + + var cfg = new ControlFlowGraph(this.Statements, binder) + { + Start = + { + FlowState = StateBinder.CreateInitialState(this) + } + }; + return cfg; + } public override ImmutableArray GetReturnTypeAttributes() { if (!ReturnsNull) { - // [return: NotNull] var returnType = this.ReturnType; if (returnType != null && (returnType.IsReferenceType) ) // only if it makes sense to check for NULL { - return ImmutableArray.Create(DeclaringCompilation.CreateNotNullAttribute()); + return ImmutableArray.Create(DeclaringCompilation.CreateNotNullAttribute()); } } - // return ImmutableArray.Empty; } - internal override ObsoleteAttributeData ObsoleteAttributeData - { - get { return null; } - } + internal override ObsoleteAttributeData ObsoleteAttributeData => null; internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) => !IsOverride && IsMetadataVirtual(ignoreInterfaceImplementationChanges); diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceParameterSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceParameterSymbol.cs index e67f3a07b..81236547e 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceParameterSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceParameterSymbol.cs @@ -146,7 +146,7 @@ TypeSymbol ResolveType() return ContainingType; } - return DeclaringCompilation.GetBinder(_syntax).BindType(_syntax.Type); + return DeclaringCompilation.GetBinder(_syntax).TryResolveTypeSymbol(_syntax.Type); } public override RefKind RefKind =>RefKind.None; diff --git a/src/Aquila.CodeAnalysis/Symbols/Source/SourceSymbolCollection.cs b/src/Aquila.CodeAnalysis/Symbols/Source/SourceSymbolCollection.cs index bcabbcb18..a68c5b831 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Source/SourceSymbolCollection.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Source/SourceSymbolCollection.cs @@ -86,7 +86,7 @@ private void UpdateSymbolsCore() Assert.NotNull(function.FuncOwner); var binder = _compilation.GetBinder(function.Parent); - var type = binder.BindType(function.FuncOwner.OwnerType); + var type = binder.TryResolveTypeSymbol(function.FuncOwner.OwnerType); if (type is SynthesizedTypeSymbol sts) { @@ -142,7 +142,7 @@ public IEnumerable GetMethods() /// /// Gets enumeration of all methods (global code, functions, lambdas and class methods) in source code. /// - public IEnumerable GetSourceMethods() => GetMethods().OfType(); + public IEnumerable GetSourceMethods() => GetMethods().OfType(); public IEnumerable GetModuleTypes() => _types.OfType(); @@ -152,7 +152,7 @@ public IEnumerable GetMethods() public MergedSourceCode GetMergedSourceCode() => _sourceCode; - public NamedTypeSymbol GetType(QualifiedName name, Dictionary resolved = null) + public NamedTypeSymbol? TryGetType(QualifiedName name, Dictionary resolved = null) { var resolvedTypes = _types.Where(x => x.MakeQualifiedName() == name).ToImmutableArray(); @@ -165,7 +165,7 @@ public NamedTypeSymbol GetType(QualifiedName name, Dictionary GetMembers() { if (_members == null) { - var builder = ImmutableArray.CreateBuilder(); builder.Add(new MethodTreeBuilderSymbol(this, _htmlDecl)); @@ -148,7 +142,6 @@ public override ImmutableArray GetAttributes() internal class MethodTreeBuilderSymbol : SourceMethodSymbolBase { - private readonly NamedTypeSymbol _type; private readonly HtmlDecl _htmlDecl; private IPlace _builderPlace; @@ -158,10 +151,9 @@ public MethodTreeBuilderSymbol(NamedTypeSymbol type, HtmlDecl htmlDecl) : base(t { Contract.ThrowIfNull(type); - _type = type; _htmlDecl = htmlDecl; - var ct = _type.DeclaringCompilation.CoreTypes; + var ct = type.DeclaringCompilation.CoreTypes; var componentBaseType = ct.Web_ComponentBase; _overridenMethod = componentBaseType.Method("BuildRenderTree", ct.Web_RenderTreeBuilder).Symbol; @@ -174,7 +166,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; @@ -182,8 +174,6 @@ public override void GetDiagnostics(DiagnosticBag diagnostic) { } - public override Symbol ContainingSymbol => this._type; - public override ImmutableArray DeclaringSyntaxReferences => ImmutableArray.Empty; @@ -209,29 +199,26 @@ public override void GetDiagnostics(DiagnosticBag diagnostic) public override bool IsExtern => false; - /// - public override ControlFlowGraph ControlFlowGraph + protected override Binder GetMethodBinderCore() { - get + return DeclaringCompilation.GetBinder(_htmlDecl.HtmlMarkup); + } + + protected override ControlFlowGraph CreateControlFlowGraphCore() + { + var markup = _htmlDecl.HtmlMarkup; + if (markup == null) return null; + + var cfg = new ControlFlowGraph(markup.HtmlNodes, GetMethodBinderCore()) { - if (_cfg != null) + Start = { - return _cfg; + FlowState = StateBinder.CreateInitialState(this) } + }; - if (_htmlDecl.HtmlMarkup == null) - { - return null; - } + return cfg; - var state = StateBinder.CreateInitialState(this); - var binder = DeclaringCompilation.GetBinder(_htmlDecl.HtmlMarkup); - var cfg = new ControlFlowGraph(this._htmlDecl.HtmlMarkup.HtmlNodes, binder); - Interlocked.CompareExchange(ref _cfg, cfg, null); - cfg.Start.FlowState = state; - return _cfg; - } - internal set => _cfg = value; } internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) diff --git a/src/Aquila.CodeAnalysis/Symbols/SubstitutedParameterSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/SubstitutedParameterSymbol.cs index 66e89c89c..7a95bdaa8 100644 --- a/src/Aquila.CodeAnalysis/Symbols/SubstitutedParameterSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/SubstitutedParameterSymbol.cs @@ -9,8 +9,6 @@ internal sealed class SubstitutedParameterSymbol : WrappedParameterSymbol // initially set to map which is only used to get the type, which is once computed is stored here. private object _mapOrType; - private readonly Symbol _containingSymbol; - internal SubstitutedParameterSymbol(MethodSymbol containingSymbol, TypeMap map, ParameterSymbol originalParameter) : this((Symbol)containingSymbol, map, originalParameter) { @@ -25,16 +23,13 @@ private SubstitutedParameterSymbol(Symbol containingSymbol, TypeMap map, Paramet base(originalParameter) { Debug.Assert(originalParameter.IsDefinition); - _containingSymbol = containingSymbol; + ContainingSymbol = containingSymbol; _mapOrType = map; } protected override Symbol OriginalSymbolDefinition => underlyingParameter.OriginalDefinition; - public override Symbol ContainingSymbol - { - get { return _containingSymbol; } - } + public override Symbol ContainingSymbol { get; } internal override TypeSymbol Type { @@ -60,13 +55,10 @@ internal override TypeSymbol Type } } - public override ImmutableArray CustomModifiers - { - get - { - var map = _mapOrType as TypeMap; - return map != null ? map.SubstituteCustomModifiers(this.underlyingParameter.Type, this.underlyingParameter.CustomModifiers) : this.underlyingParameter.CustomModifiers; - } - } + public override ImmutableArray CustomModifiers => + _mapOrType is TypeMap map + ? map.SubstituteCustomModifiers(this.underlyingParameter.Type, + this.underlyingParameter.CustomModifiers) + : this.underlyingParameter.CustomModifiers; } } 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/SynthesizedMethodSymbol.cs b/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedMethodSymbol.cs index fce73b463..b89ad0b3c 100644 --- a/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedMethodSymbol.cs +++ b/src/Aquila.CodeAnalysis/Symbols/Synthesized/SynthesizedMethodSymbol.cs @@ -58,8 +58,7 @@ public SynthesizedMethodSymbol(TypeSymbol containingType) { _containing = containingType as Cci.ITypeDefinition ?? throw new ArgumentNullException(nameof(containingType)); - _module = (ModuleSymbol)containingType.ContainingModule ?? - throw new NullReferenceException("Module is null"); + _module = containingType.ContainingModule ?? throw new NullReferenceException("Module is null"); _return = DeclaringCompilation.CoreTypes.Void; _parameters = ImmutableArray.Empty; @@ -120,7 +119,7 @@ internal SynthesizedMethodSymbol SetReturn(TypeSymbol type) { if (_explicitOverride != null) { - throw new Exception("Can't set name on the overriden method"); + throw new Exception("Can't set name on the overriden method"); } _return = type; 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.CodeAnalysis/Symbols/TypeSymbolExtensions.cs b/src/Aquila.CodeAnalysis/Symbols/TypeSymbolExtensions.cs index 77429e23f..1bdcd8d40 100644 --- a/src/Aquila.CodeAnalysis/Symbols/TypeSymbolExtensions.cs +++ b/src/Aquila.CodeAnalysis/Symbols/TypeSymbolExtensions.cs @@ -312,7 +312,7 @@ public static bool IsDelegateType(this TypeSymbol type) public static ImmutableArray DelegateParameters(this TypeSymbol type) { Debug.Assert( - (object)type.DelegateInvokeMethod() != null, // && !type.DelegateInvokeMethod().HasUseSiteError, + (object)type.DelegateInvokeMethod() != null, "This method should only be called on valid delegate types."); return type.DelegateInvokeMethod().Parameters; } @@ -321,7 +321,7 @@ public static MethodSymbol DelegateInvokeMethod(this TypeSymbol type) { Debug.Assert((object)type != null); Debug.Assert(type.IsDelegateType() || type.IsExpressionTree()); - return (MethodSymbol)type.GetDelegateType().DelegateInvokeMethod; + return type.GetDelegateType().DelegateInvokeMethod; } /// 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.CodeAnalysis/Utilities/ExceptionUtilities.cs b/src/Aquila.CodeAnalysis/Utilities/ExceptionUtilities.cs index 900349103..26716f932 100644 --- a/src/Aquila.CodeAnalysis/Utilities/ExceptionUtilities.cs +++ b/src/Aquila.CodeAnalysis/Utilities/ExceptionUtilities.cs @@ -38,7 +38,7 @@ public static NotImplementedException NotImplementedException(ILBuilder il, stri var syntax = op?.AquilaSyntax; if (syntax != null) return new NotImplementedException($"{message} not implemented at {location}"); - + if (il.SeqPointsOpt != null && il.SeqPointsOpt.Count != 0) { // get location from last sequence point @@ -60,16 +60,18 @@ public static NotImplementedException NotImplementedException(ILBuilder il, stri return new NotImplementedException($"{message} not implemented at {location}"); } - public static ArgumentNullException ArgumentNull(string argName) + public static NotImplementedException NotImplementedException(string message = null) { - return new ArgumentNullException(argName); + return new NotImplementedException(); } - public static ArgumentNullException ArgumentNull() + public static ArgumentNullException ArgumentNull(string argName) { - return new ArgumentNullException(); + return new ArgumentNullException(argName); } + public static ArgumentNullException ArgumentNull() => new ArgumentNullException(); + public static InvalidOperationException UnexpectedValue(object o) { string output = string.Format("Unexpected value '{0}' of type '{1}'", o, @@ -80,9 +82,7 @@ public static InvalidOperationException UnexpectedValue(object o) return new InvalidOperationException(output); } - internal static InvalidOperationException Unreachable - { - get { return new InvalidOperationException("This program location is thought to be unreachable."); } - } + internal static InvalidOperationException Unreachable => + new("This program location is thought to be unreachable."); } } \ No newline at end of file diff --git a/src/Aquila.CodeAnalysis/Web/WebGenerator.cs b/src/Aquila.CodeAnalysis/Web/WebGenerator.cs deleted file mode 100644 index 0f672d2f7..000000000 --- a/src/Aquila.CodeAnalysis/Web/WebGenerator.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Reflection.Metadata; -using Aquila.CodeAnalysis.CodeGen; -using Aquila.CodeAnalysis.Emit; -using Aquila.CodeAnalysis.Symbols; -using Aquila.CodeAnalysis.Symbols.Attributes; -using Aquila.CodeAnalysis.Symbols.Synthesized; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeGen; - -namespace Aquila.CodeAnalysis.Web; - -internal class ComponentBaseGenerator -{ - private readonly SynthesizedNamespaceSymbol _webNs; - private readonly SynthesizedManager _mrg; - private readonly CoreTypes _ct; - private readonly AquilaCompilation _compilation; - private readonly PEModuleBuilder _m; - private readonly AquilaSyntaxTree _syntaxTree; - - public ComponentBaseGenerator(PEModuleBuilder builder, AquilaSyntaxTree syntaxTree) - { - _m = builder; - _syntaxTree = syntaxTree; - _mrg = builder.SynthesizedManager; - _webNs = _mrg.SynthesizeNamespace(builder.SourceModule.GlobalNamespace, "Web"); - _ct = builder.Compilation.CoreTypes; - _compilation = builder.Compilation; - } - - public void Build() - { - var bType = _ct.Web_ComponentBase; - - var type = _mrg.SynthesizeType(_webNs, "Component") - .SetBaseType(bType) - .AddAttribute(new SynthesizedAttributeData(_ct.Web_Route.Ctor(_ct.String), - ImmutableArray.Create(new TypedConstant(_ct.String.Symbol, - TypedConstantKind.Primitive, "/view/library/invoice")), - ImmutableArray>.Empty)) - ; - - var thisPlace = new ThisArgPlace(type); - - var renderMethod = _mrg.SynthesizeMethod(type); - renderMethod - .SetVirtual(true) - .SetOverride(bType.Method("BuildRenderTree", _ct.Web_RenderTreeBuilder)) - .SetMethodBuilder((m, d) => il => - { - var builderArg = new ParamPlace(renderMethod.Parameters.First()); - var v = new Visitor(type, _ct, builderArg, m, d, il); - il.EmitRet(true); - }); - - var ctor = _mrg.SynthesizeConstructor(type) - .SetMethodBuilder((m, d) => il => - { - thisPlace.EmitLoad(il); - il.EmitCall(m, d, ILOpCode.Call, bType.Ctor()); - il.EmitRet(true); - }); - - type.AddMember(ctor); - type.AddMember(renderMethod); - - _m.SetMethodBody(ctor, ctor.CreateMethodBody(_m, DiagnosticBag.GetInstance())); - _m.SetMethodBody(renderMethod, renderMethod.CreateMethodBody(_m, DiagnosticBag.GetInstance())); - } - - - public void AddMarkupContent() - { - - } -} - -internal class Visitor : AquilaSyntaxVisitor -{ - private readonly TypeSymbol _componentType; - private readonly CoreTypes _ct; - private readonly ParamPlace _builder; - private PEModuleBuilder m; - private DiagnosticBag d; - private ILBuilder il; - private int _seq = 0; - - public Visitor(TypeSymbol componentType, CoreTypes ct, ParamPlace builder, PEModuleBuilder m, DiagnosticBag d, - ILBuilder il) - { - _componentType = componentType; - _ct = ct; - _builder = builder; - this.m = m; - this.d = d; - this.il = il; - } - - public void OpenElement(string elementName) - { - _builder.EmitLoad(il); - il.EmitIntConstant(_seq++); - il.EmitStringConstant(elementName); - var amc = _ct.Web_RenderTreeBuilder.Method("OpenElement", _ct.Int32, _ct.String); - il.EmitCall(m, d, ILOpCode.Call, amc); - } - - public void AddContent(string content) - { - _builder.EmitLoad(il); - il.EmitIntConstant(_seq++); - il.EmitStringConstant(content); - var amc = _ct.Web_RenderTreeBuilder.Method("AddContent", _ct.Int32, _ct.String); - il.EmitCall(m, d, ILOpCode.Call, amc); - } - - public void AddContent(IPlace place) - { - _builder.EmitLoad(il); - il.EmitIntConstant(_seq++); - place.EmitLoad(il); - var amc = _ct.Web_RenderTreeBuilder.Method("AddContent", _ct.Int32, _ct.Object); - il.EmitCall(m, d, ILOpCode.Call, amc); - } - - public void CloseElement() - { - _builder.EmitLoad(il); - var amc = _ct.Web_RenderTreeBuilder.Method("CloseElement"); - il.EmitCall(m, d, ILOpCode.Call, amc); - } - - public void AddAttribute(string name, string value) - { - _builder.EmitLoad(il); - il.EmitIntConstant(_seq++); - il.EmitStringConstant(name); - il.EmitStringConstant(value); - var amc = _ct.Web_RenderTreeBuilder.Method("AddAttribute", _ct.Int32, _ct.String, _ct.String); - il.EmitCall(m, d, ILOpCode.Call, amc); - } - - public void AddMarkupContent(string content) - { - _builder.EmitLoad(il); - il.EmitIntConstant(_seq++); - il.EmitStringConstant(content); - var amc = _ct.Web_RenderTreeBuilder.Method("AddMarkupContent", _ct.Int32, _ct.String); - il.EmitCall(m, d, ILOpCode.Call, amc); - } -} \ No newline at end of file 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