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; } }
/// <summary> /// Analyze an expression to apply its effects to the reachability graph. /// </summary> /// <returns>The place of the object resulting from evaluating this expression or null /// if the there is no result or the result is not an object reference.</returns> private TempValue?Analyze(IExpression?expression, ReachabilityGraph graph, VariableScope scope) { if (expression is null) { return(null); } var referenceType = expression.DataType.Known().UnderlyingReferenceType(); var isReferenceType = !(referenceType is null); switch (expression) { default: throw ExhaustiveMatch.Failed(expression); case IAssignmentExpression exp: { var leftPlace = AnalyzeAssignmentPlace(exp.LeftOperand, graph, scope); var rightPlace = AnalyzeAssignmentSource(exp.RightOperand, graph, scope); graph.Assign(leftPlace, rightPlace); return(null); } case ISelfExpression exp: throw new InvalidOperationException($"`self` reference not wrapped in move, borrow, or share"); case IMoveExpression exp: { _ = referenceType ?? throw new InvalidOperationException("Can't move value type"); // The referent should be a name or `self` so we don't need to evaluate it var variable = graph.GetVariableFor(exp.ReferencedSymbol); var temp = graph.AddTempValue(exp); temp?.MoveFrom(variable); return(temp); } case IBorrowExpression exp: { _ = referenceType ?? throw new InvalidOperationException("Can't borrow value type"); // If there is a variable, it is a simple borrow expression var variable = graph.TryGetVariableFor(exp.ReferencedSymbol); if (!(variable is null)) { var temp = graph.AddTempValue(exp); temp?.BorrowFrom(variable); return(temp); } // Can this happen? throw new NotImplementedException(); //var temp = Analyze(exp.) //var temp = graph.NewTempValue(referenceType); //temp.BorrowFrom(variable); //return temp; } case IShareExpression exp: { _ = referenceType ?? throw new InvalidOperationException("Can't share value type"); // The referent should be a name or `self` so we don't need to evaluate it var variable = graph.TryGetVariableFor(exp.ReferencedSymbol); if (!(variable is null)) { var temp = graph.AddTempValue(exp); temp?.ShareFrom(variable); return(temp); }