private void Analyze(IStatement statement, ReachabilityGraph graph, VariableScope scope)
        {
            switch (statement)
            {
            default:
                throw ExhaustiveMatch.Failed(statement);

            case IVariableDeclarationStatement stmt:
            {
                var initializer = AnalyzeAssignmentSource(stmt.Initializer, graph, scope);
                var variable    = VariableDeclared(stmt, graph, scope);
                // TODO this variable's references effectively go away when it is no longer live
                // TODO how does the idea of in use variables work with variables?
                graph.Assign(variable, initializer);
                if (!stmt.VariableIsLiveAfter.Result)
                {
                    // Variable is dead, effectively it can be removed
                    variable?.Dead();
                }
            }
            break;

            case IExpressionStatement stmt:
                Analyze(stmt.Expression, graph, scope);
                break;

            case IResultStatement exp:
                // TODO deal with passing the result to the block
                Analyze(exp.Expression, graph, scope);
                break;
            }
        }
        public void Emit(DeclarationIL declaration, Code code)
        {
            switch (declaration)
            {
            default:
                throw ExhaustiveMatch.Failed(declaration);

            case FunctionIL function:
                if (function.IsExternal)
                {
                    EmitExternalFunctionSignature(function, code);
                }
                else
                {
                    EmitFunction(function, code);
                }
                break;

            case MethodDeclarationIL method:
                EmitMethod(method, code);
                break;

            case ConstructorIL constructor:
                EmitConstructor(constructor, code);
                break;

            case ClassIL type:
                EmitType(type, code);
                break;

            case FieldIL _:
                // fields are emitted as part of the type
                break;
            }
        }
        internal void MarkReferencedObjects()
        {
            foreach (var reference in References.Where(r => !r.IsReleased))
            {
                var effectiveAccess = reference.EffectiveAccess();
                var referent        = reference.Referent;
                switch (effectiveAccess)
                {
                default:
                    throw ExhaustiveMatch.Failed(effectiveAccess);

                case Access.ReadOnly:
                    if (reference.IsUsed)
                    {
                        referent.MarkReadOnly();
                    }
                    else
                    {
                        // If not used, we still need to recurse into it. We can identify it still.
                        referent.MarkIdentifiable();
                    }
                    break;

                case Access.Identify:
                    referent.MarkIdentifiable();
                    break;

                case Access.Mutable:
                    referent.MarkMutable();
                    break;
                }
            }
        }
        public void AssignFrom(StackPlace place, ReferenceCapability referenceCapability)
        {
            if (place.Graph != Graph)
            {
                throw new ArgumentException("Must be part of the same graph", nameof(place));
            }

            switch (referenceCapability)
            {
            default:
                throw ExhaustiveMatch.Failed(referenceCapability);

            case ReferenceCapability.Owned:
            case ReferenceCapability.OwnedMutable:
            case ReferenceCapability.Isolated:
            case ReferenceCapability.IsolatedMutable:
            case ReferenceCapability.Held:
            case ReferenceCapability.HeldMutable:
                MoveFrom(place);
                break;

            case ReferenceCapability.Shared:
                ShareFrom(place);
                break;

            case ReferenceCapability.Borrowed:
                BorrowFrom(place);
                break;

            case ReferenceCapability.Identity:
                IdentityFrom(place);
                break;
            }
        }
Exemple #5
0
        private void ResolveReachabilityAnnotation(
            CodeFile file,
            IParameterNameSyntax syntax,
            FixedSet <BindingSymbol> symbols)
        {
            switch (syntax)
            {
            default:
                throw ExhaustiveMatch.Failed(syntax);

            case INamedParameterNameSyntax syn:
            {
                var referencedSymbol = symbols.OfType <VariableSymbol>().SingleOrDefault(s => s.Name == syn.Name);
                syn.ReferencedSymbol.Fulfill(referencedSymbol);
                if (referencedSymbol is null)
                {
                    diagnostics.Add(NameBindingError.CouldNotBindParameterName(file, syn.Span));
                }
            }
            break;

            case ISelfParameterNameSyntax syn:
            {
                var referencedSymbol = symbols.OfType <SelfParameterSymbol>().SingleOrDefault();
                syn.ReferencedSymbol.Fulfill(referencedSymbol);
                if (referencedSymbol is null)
                {
                    diagnostics.Add(NameBindingError.CouldNotBindParameterName(file, syn.Span));
                }
            }
            break;
            }
        }
Exemple #6
0
        /// <summary>
        /// If the type has not been resolved, this resolves it. This function
        /// also watches for type cycles and reports an error.
        /// </summary>
        private void BuildEntitySymbol(IEntityDeclarationSyntax entity)
        {
            switch (entity)
            {
            default:
                throw ExhaustiveMatch.Failed(entity);

            case IMethodDeclarationSyntax method:
                BuildMethodSymbol(method);
                break;

            case IConstructorDeclarationSyntax constructor:
                BuildConstructorSymbol(constructor);
                break;

            case IAssociatedFunctionDeclarationSyntax associatedFunction:
                BuildAssociatedFunctionSymbol(associatedFunction);
                break;

            case IFieldDeclarationSyntax field:
                BuildFieldSymbol(field);
                break;

            case IFunctionDeclarationSyntax syn:
                BuildFunctionSymbol(syn);
                break;

            case IClassDeclarationSyntax syn:
                BuildClassSymbol(syn);
                break;
            }
        }
Exemple #7
0
        public void Example(Shape shape)
        {
            switch (shape)
            {
            default:
                throw ExhaustiveMatch.Failed(shape);

            case Square square:
                Console.WriteLine("Square: " + square);
                break;

            case Circle circle:
                Console.WriteLine("Circle: " + circle);
                break;

            //case EquilateralTriangle equilateralTriangle:
            //    Console.WriteLine("EquilateralTriangle: " + equilateralTriangle);
            //    break;
            case Triangle triangle:
                Console.WriteLine("Triangle: " + triangle);
                break;
                //case string s:
                //    Console.WriteLine("string: " + s);
                //    break;
            }
        }
Exemple #8
0
        private void BuildParameterSymbols(
            InvocableSymbol containingSymbol,
            IEnumerable <IConstructorParameterSyntax> parameters,
            IEnumerable <DataType> types)
        {
            foreach (var(param, type) in parameters.Zip(types))
            {
                switch (param)
                {
                default:
                    throw ExhaustiveMatch.Failed(param);

                case INamedParameterSyntax namedParam:
                {
                    var symbol = new VariableSymbol(containingSymbol, namedParam.Name,
                                                    namedParam.DeclarationNumber.Result, namedParam.IsMutableBinding, type);
                    namedParam.Symbol.Fulfill(symbol);
                    symbolTree.Add(symbol);
                }
                break;

                case IFieldParameterSyntax _:
                    // Referenced field already assigned
                    break;
                }
            }
        }
        public void Disassemble(DeclarationIL declaration, AssemblyBuilder builder)
        {
            switch (declaration)
            {
            default:
                throw ExhaustiveMatch.Failed(declaration);

            case FunctionIL function:
                Disassemble(function, builder);
                break;

            case MethodDeclarationIL method:
                Disassemble(method, builder);
                break;

            case ConstructorIL constructor:
                Disassemble(constructor, builder);
                break;

            case ClassIL type:
                Disassemble(type, builder);
                break;

            case FieldIL field:
                Disassemble(field, builder);
                break;
            }
        }
Exemple #10
0
        private DeclarationIL Build(IDeclaration declaration, ISymbolTree symbolTree)
        {
            if (declarationsIL.TryGetValue(declaration.Symbol, out var declarationIL))
            {
                return(declarationIL);
            }

            switch (declaration)
            {
            default:
                throw ExhaustiveMatch.Failed(declaration);

            case IFunctionDeclaration function:
            {
                var il = ilFactory.CreateGraph(function);
                declarationIL = new FunctionIL(false, false, function.Symbol, BuildParameters(function.Parameters), il);
                break;
            }

            case IAssociatedFunctionDeclaration associatedFunction:
            {
                var il = ilFactory.CreateGraph(associatedFunction);
                declarationIL = new FunctionIL(false, true, associatedFunction.Symbol, BuildParameters(associatedFunction.Parameters), il);
                break;
            }

            case IConcreteMethodDeclaration method:
            {
                var il = ilFactory.CreateGraph(method);
                declarationIL = new MethodDeclarationIL(method.Symbol, BuildParameter(method.SelfParameter), BuildParameters(method.Parameters), il);
                break;
            }

            case IAbstractMethodDeclaration method:
            {
                declarationIL = new MethodDeclarationIL(method.Symbol, BuildParameter(method.SelfParameter), BuildParameters(method.Parameters), null);
                break;
            }

            case IConstructorDeclaration constructor:
            {
                var il                   = ilFactory.CreateGraph(constructor);
                var parameters           = BuildConstructorParameters(constructor);
                var fieldInitializations = BuildFieldInitializations(constructor);
                declarationIL = new ConstructorIL(constructor.Symbol, parameters, fieldInitializations, il);
                break;
            }

            case IFieldDeclaration fieldDeclaration:
                declarationIL = new FieldIL(fieldDeclaration.Symbol);
                break;

            case IClassDeclaration classDeclaration:
                declarationIL = new ClassIL(classDeclaration.Symbol,
                                            BuildClassMembers(classDeclaration, symbolTree));
                break;
            }
            declarationsIL.Add(declaration.Symbol, declarationIL);
            return(declarationIL);
        }
        public VariableFlags IdentifierName(
            INameExpression nameExpression,
            VariableFlags possiblyMoved)
        {
            var symbol = nameExpression.ReferencedSymbol;

            if (possiblyMoved[symbol] == true)
            {
                diagnostics.Add(SemanticError.UseOfPossiblyMovedValue(file, nameExpression.Span));
            }

            var valueSemantics = nameExpression.Semantics;

            // TODO this isn't correct, but for now fields don't have proper move, borrow handling
            //?? nameExpression.Type.Assigned().OldValueSemantics;
            switch (valueSemantics)
            {
            case ExpressionSemantics.Move:
            case ExpressionSemantics.Acquire:
                return(possiblyMoved.Set(symbol, true));

            case ExpressionSemantics.Copy:
            case ExpressionSemantics.Borrow:
            case ExpressionSemantics.Share:
            case ExpressionSemantics.Void:
            case ExpressionSemantics.Never:
            case ExpressionSemantics.CreateReference:
                // If it were move or copy, that would have been set to the ExpressionSemantics
                // Not moving value
                return(possiblyMoved);

            default:
                throw ExhaustiveMatch.Failed(valueSemantics);
            }
        }
Exemple #12
0
        /// <remarks>
        /// It wouldn't make sense to get all declarations including non-member because
        /// that includes namespace declarations. However, some namespaces come from
        /// the implicit namespace of a compilation unit or are implicitly declared,
        /// so it wouldn't give a full list of the namespaces.
        /// </remarks>
        private static IEnumerable <IEntityDeclarationSyntax> GetEntityDeclarations(
            FixedSet <ICompilationUnitSyntax> compilationUnits)
        {
            var declarations = new Queue <IDeclarationSyntax>();

            declarations.EnqueueRange(compilationUnits.SelectMany(cu => cu.Declarations));
            while (declarations.TryDequeue(out var declaration))
            {
                switch (declaration)
                {
                default:
                    throw ExhaustiveMatch.Failed(declaration);

                case IMemberDeclarationSyntax syn:
                    yield return(syn);

                    break;

                case IFunctionDeclarationSyntax syn:
                    yield return(syn);

                    break;

                case INamespaceDeclarationSyntax syn:
                    declarations.EnqueueRange(syn.Declarations);
                    break;

                case IClassDeclarationSyntax syn:
                    yield return(syn);

                    declarations.EnqueueRange(syn.Members);
                    break;
                }
            }
        }
Exemple #13
0
        private static bool CompileCode(
            Project project,
            string cacheDir,
            string codePath,
            object consoleLock)
        {
            var compiler = new CLangCompiler();

            var runtimeLibrarySourcePath = System.IO.Path.Combine(cacheDir, CodeEmitter.RuntimeLibraryCodeFileName);

            File.WriteAllText(runtimeLibrarySourcePath, CodeEmitter.RuntimeLibraryCode, Encoding.UTF8);
            var runtimeLibraryHeaderPath = System.IO.Path.Combine(cacheDir, CodeEmitter.RuntimeLibraryHeaderFileName);

            File.WriteAllText(runtimeLibraryHeaderPath, CodeEmitter.RuntimeLibraryHeader, Encoding.UTF8);

            var    sourceFiles       = new[] { codePath, runtimeLibrarySourcePath };
            var    headerSearchPaths = new[] { cacheDir };
            string outputPath        = project.Template switch
            {
                ProjectTemplate.App => Path.ChangeExtension(codePath, "exe"),
                ProjectTemplate.Lib => Path.ChangeExtension(codePath, "dll"),
                _ => throw ExhaustiveMatch.Failed(project.Template)
            };

            lock (consoleLock)
            {
                Console.WriteLine($"CLang Compiling {project.Name} ({project.Path})...");
                var exitCode = compiler.Compile(ConsoleCompilerOutput.Instance, sourceFiles,
                                                headerSearchPaths, outputPath);

                return(exitCode == 0);
            }
        }
 public static string ToInstructionString(this BooleanLogicOperator @operator)
 {
     return(@operator switch
     {
         BooleanLogicOperator.And => "AND",
         BooleanLogicOperator.Or => "OR",
         _ => throw ExhaustiveMatch.Failed(@operator)
     });
 private static INonMemberDeclaration BuildNonMemberDeclaration(INonMemberEntityDeclarationSyntax entity)
 {
     return(entity switch
     {
         IClassDeclarationSyntax syn => BuildClass(syn),
         IFunctionDeclarationSyntax syn => BuildFunction(syn),
         _ => throw ExhaustiveMatch.Failed(entity)
     });
Exemple #16
0
 public static string ToSymbolString(this AccessOperator @operator)
 {
     return(@operator switch
     {
         AccessOperator.Standard => ".",
         AccessOperator.Conditional => "?.",
         _ => throw ExhaustiveMatch.Failed(@operator)
     });
 public override string ToString()
 {
     return(Fixity switch
     {
         UnaryOperatorFixity.Prefix => $"{Operator.ToSymbolString()}{Operand.ToGroupedString(ExpressionPrecedence)}",
         UnaryOperatorFixity.Postfix => $"{Operand.ToGroupedString(ExpressionPrecedence)}{Operator.ToSymbolString()}",
         _ => throw ExhaustiveMatch.Failed(Fixity)
     });
Exemple #18
0
 private static ParameterIL BuildParameter(IParameter parameter)
 {
     return(parameter switch
     {
         INamedParameter namedParameter => new NamedParameterIL(namedParameter.Symbol),
         ISelfParameter selfParameter => new SelfParameterIL(selfParameter.Symbol),
         IFieldParameter fieldParameter => new FieldParameterIL(fieldParameter.ReferencedSymbol),
         _ => throw ExhaustiveMatch.Failed(parameter)
     });
Exemple #19
0
        private void ResolveBodyTypes(IEntityDeclarationSyntax declaration)
        {
            switch (declaration)
            {
            default:
                throw ExhaustiveMatch.Failed(declaration);

            case IFunctionDeclarationSyntax function:
            {
                var resolver = new BasicBodyAnalyzer(function, symbolTreeBuilder, symbolTrees, stringSymbol, diagnostics,
                                                     function.Symbol.Result.ReturnDataType);
                resolver.ResolveTypes(function.Body);
                break;
            }

            case IAssociatedFunctionDeclarationSyntax associatedFunction:
            {
                var resolver = new BasicBodyAnalyzer(associatedFunction, symbolTreeBuilder, symbolTrees,
                                                     stringSymbol, diagnostics,
                                                     associatedFunction.Symbol.Result.ReturnDataType);
                resolver.ResolveTypes(associatedFunction.Body);
                break;
            }

            case IConcreteMethodDeclarationSyntax method:
            {
                var resolver = new BasicBodyAnalyzer(method, symbolTreeBuilder,
                                                     symbolTrees, stringSymbol, diagnostics, method.Symbol.Result.ReturnDataType);
                resolver.ResolveTypes(method.Body);
                break;
            }

            case IAbstractMethodDeclarationSyntax _:
                // has no body, so nothing to resolve
                break;

            case IFieldDeclarationSyntax field:
                if (field.Initializer != null)
                {
                    var resolver = new BasicBodyAnalyzer(field, symbolTreeBuilder, symbolTrees, stringSymbol, diagnostics);
                    resolver.CheckType(ref field.Initializer, field.Symbol.Result.DataType);
                }
                break;

            case IConstructorDeclarationSyntax constructor:
            {
                var resolver = new BasicBodyAnalyzer(constructor, symbolTreeBuilder, symbolTrees, stringSymbol, diagnostics, constructor.ImplicitSelfParameter.Symbol.Result.DataType);
                resolver.ResolveTypes(constructor.Body);
                break;
            }

            case IClassDeclarationSyntax _:
                // body of class is processed as separate items
                break;
            }
        }
Exemple #20
0
        /// <summary>
        /// Convert an expression that yields a value into an operand for another instruction
        /// </summary>
        private Operand ConvertToOperand(IExpression expression)
        {
            switch (expression)
            {
            default:
                throw ExhaustiveMatch.Failed(expression);

            case ISelfExpression exp:
                return(graph.SelfVariable.Reference(exp.Span));

            case INameExpression exp:
            {
                var symbol = exp.ReferencedSymbol;
                return(graph.VariableFor(symbol).Reference(exp.Span));
            }

            case IBorrowExpression exp:
                return(ConvertToOperand(exp.Referent));

            case IShareExpression exp:
                return(ConvertToOperand(exp.Referent));

            case IMoveExpression exp:
                return(ConvertToOperand(exp.Referent));

            case IAssignmentExpression _:
            case IBinaryOperatorExpression _:
            case IUnaryOperatorExpression _:
            case IFieldAccessExpression _:
            case IMethodInvocationExpression _:
            case INewObjectExpression _:
            case IImplicitNumericConversionExpression _:
            case IIntegerLiteralExpression _:
            case IStringLiteralExpression _:
            case IBoolLiteralExpression _:
            case INoneLiteralExpression _:
            case IImplicitImmutabilityConversionExpression _:
            case IImplicitOptionalConversionExpression _:
            case IUnsafeExpression _:
            case IBlockExpression _:
            case IImplicitNoneConversionExpression _:
            case IBreakExpression _:
            case INextExpression _:
            case IReturnExpression _:
            case IIfExpression _:
            case IFunctionInvocationExpression _:
            case IForeachExpression _:
            case ILoopExpression _:
            case IWhileExpression _:
            {
                var tempVar = graph.Let(expression.DataType.Assigned().Known(), CurrentScope);
                ConvertIntoPlace(expression, tempVar.Place(expression.Span));
                return(tempVar.Reference(expression.Span));
            }
            }
        }
Exemple #21
0
        public void EnumValueGivesEnumMessage()
        {
            const string expectedMessage = "'ExhaustiveMatching.Tests.Fakes.ExampleEnum.Yes' was not matched. Match is supposed to be exhaustive.";

            var ex = ExhaustiveMatch.Failed(ExampleEnum.Yes);

            Assert.Equal(expectedMessage, ex.Message);
            Assert.Equal(ExampleEnum.Yes, ex.FailedValue);
            Assert.Equal(typeof(ExampleEnum), ex.MatchingType);
        }
Exemple #22
0
        public void NullValueForEnumTypeGivesNullObjectMessage()
        {
            const string expectedMessage = "The value 'null' was not matched when matching a 'System.Enum'. Match is supposed to be exhaustive.";

            var ex = ExhaustiveMatch.Failed <Enum>(null);

            Assert.Equal(expectedMessage, ex.Message);
            Assert.Null(ex.FailedValue);
            Assert.Equal(typeof(Enum), ex.MatchingType);
        }
Exemple #23
0
 public static string ToInstructionString(this NumericInstructionOperator @operator)
 {
     return(@operator switch
     {
         NumericInstructionOperator.Add => "ADD",
         NumericInstructionOperator.Subtract => "SUB",
         NumericInstructionOperator.Multiply => "MUL",
         NumericInstructionOperator.Divide => "DIV",
         _ => throw ExhaustiveMatch.Failed(@operator)
     });
Exemple #24
0
        public void WithoutValueGivesGenericMessage()
        {
            const string expectedMessage = "A match that was supposed to be exhaustive failed to match.";

            var ex = ExhaustiveMatch.Failed();

            Assert.Equal(expectedMessage, ex.Message);
            Assert.Null(ex.FailedValue);
            Assert.Null(ex.MatchingType);
        }
Exemple #25
0
        public void NullValueForNullableEnumGivesNullObjectMessage()
        {
            const string expectedMessage = "The value 'null' was not matched when matching a 'ExhaustiveMatching.Tests.Fakes.ExampleEnum?'. Match is supposed to be exhaustive.";
            ExampleEnum? value           = default;

            var ex = ExhaustiveMatch.Failed(value);

            Assert.Equal(expectedMessage, ex.Message);
            Assert.Null(ex.FailedValue);
            Assert.Equal(typeof(ExampleEnum?), ex.MatchingType);
        }
        public string Convert(ParameterIL parameter)
        {
            var type = typeConverter.Convert(parameter.DataType);

            return(parameter switch
            {
                NamedParameterIL param => $"{type} {nameMangler.Mangle(param.Symbol.Name)}",
                SelfParameterIL _ => $"{type} {nameMangler.SelfName}",
                FieldParameterIL param => $"{type} {nameMangler.Mangle(param.InitializeField.Name)}",
                _ => throw ExhaustiveMatch.Failed(parameter)
            });
Exemple #27
0
        public void ObjectValueGivesTypeMessage()
        {
            const string expectedMessage = "Object of type 'System.String' was not matched when matching a 'System.ICloneable'. Match is supposed to be exhaustive.";
            var          value           = (ICloneable)"TestingValue";

            var ex = ExhaustiveMatch.Failed(value);

            Assert.Equal(expectedMessage, ex.Message);
            Assert.Equal(value, ex.FailedValue);
            Assert.Equal(typeof(ICloneable), ex.MatchingType);
        }
 public static string ToSymbolString(this AssignmentOperator @operator)
 {
     return(@operator switch
     {
         AssignmentOperator.Simple => "=",
         AssignmentOperator.Plus => "+=",
         AssignmentOperator.Minus => "-=",
         AssignmentOperator.Asterisk => "*=",
         AssignmentOperator.Slash => "/=",
         _ => throw ExhaustiveMatch.Failed(@operator)
     });
Exemple #29
0
        public void NullObjectGivesNullObjectMessage()
        {
            const string expectedMessage = "The value 'null' was not matched when matching a 'System.ICloneable'. Match is supposed to be exhaustive.";
            ICloneable   value           = default;

            var ex = ExhaustiveMatch.Failed(value);

            Assert.Equal(expectedMessage, ex.Message);
            Assert.Null(ex.FailedValue);
            Assert.Equal(typeof(ICloneable), ex.MatchingType);
        }
Exemple #30
0
        public void InvalidEnumValueGivesInvalidEnumMessage()
        {
            const ExampleEnum invalidValue    = (ExampleEnum)123;
            const string      expectedMessage = "The value 123 is not valid for enum type 'ExhaustiveMatching.Tests.Fakes.ExampleEnum'. Match is supposed to be exhaustive.";

            var ex = ExhaustiveMatch.Failed(invalidValue);

            Assert.Equal(expectedMessage, ex.Message);
            Assert.Equal(invalidValue, ex.FailedValue);
            Assert.Equal(typeof(ExampleEnum), ex.MatchingType);
        }