public bool VisitDereference(Dereference dereference) { if (!IsExpressionValid(dereference.Expression)) { return(false); } return(Typer.GetExpressionType(_context, _environment, dereference.Expression) != null); }
public static IType GetExpressionType( Context context, Scope environment, IExpression expression) { var self = new Typer(context, environment); return(self.GetExpressionType(expression)); }
public bool VisitArrayLiteral(ArrayLiteral arrayLiteral) { var isValid = arrayLiteral.Elements.Aggregate( true, (current, element) => current & IsExpressionValid(element)); if (!isValid) { return(false); } return(Typer.GetExpressionType(_context, _environment, arrayLiteral) != null); }
public bool VisitFunctionCall(FunctionCall functionCall) { var calleeType = Typer.GetExpressionType(_context, _environment, functionCall.Callee); if (calleeType == null) { return(false); } if (!(calleeType is FunctionType)) { _context.Error( functionCall.Span, $"tried to call a non-callable type \"{calleeType}\""); return(false); } var calleeFunctionType = (FunctionType)calleeType; if (functionCall.Arity != calleeFunctionType.Arity) { var s = calleeFunctionType.Arity == 1 ? "" : "s"; var wasOrWere = functionCall.Arity == 1 ? "was" : "were"; _context.Error( functionCall.Callee.Span, $"expected {calleeFunctionType.Arity} argument{s}, " + $"but {functionCall.Arity} {wasOrWere} given"); } var argumentsToCheck = Math.Min(functionCall.Arity, calleeFunctionType.Arity); var allArgumentsHaveCorrectType = true; for (var i = 0; i < argumentsToCheck; i++) { var argument = functionCall.Arguments[i]; var argumentType = Typer.GetExpressionType(_context, _environment, argument); var parameterType = calleeFunctionType.ParameterTypes[i]; if (parameterType.IsSame(argumentType)) { continue; } _context.Error( argument.Span, "type mismatch between argument and parameter; " + $"expected \"{parameterType}\", but found \"{argumentType}\""); allArgumentsHaveCorrectType = false; } return(allArgumentsHaveCorrectType); }
public bool VisitAddressOf(AddressOf addressOf) { if (!IsExpressionValid(addressOf.Expression)) { return(false); } if (!SemanticAnalyzer.IsLValue(addressOf.Expression)) { _context.Error(addressOf.Span, "cannot get the address of a temporary value"); return(false); } return(Typer.GetExpressionType(_context, _environment, addressOf.Expression) != null); }
public bool VisitInfixOperation(InfixOperation infixOperation) { if (!(IsExpressionValid(infixOperation.LeftOperand) && IsExpressionValid(infixOperation.RightOperand))) { return(false); } if (infixOperation.LeftOperand is InfixOperation child && infixOperation.Operator.Node != child.Operator.Node) { _context.Error( infixOperation.Operator.Span, "operator precedence is not supported; parentheses required"); } var leftOperandType = Typer.GetExpressionType( _context, _environment, infixOperation.LeftOperand); var rightOperandType = Typer.GetExpressionType( _context, _environment, infixOperation.RightOperand); if (leftOperandType != null && leftOperandType.GetInfixOperationResultType(infixOperation.Operator.Node) == null) { _context.Error( infixOperation.Operator.Span, $"infix operation \"{infixOperation.Operator.Node}\" " + $"is not defined for types \"{leftOperandType}\" and \"{rightOperandType}\""); return(false); } if (leftOperandType != null && leftOperandType.IsSame(rightOperandType)) { return(true); } _context.Error( infixOperation.Operator.Span, "type mismatch between operands of a infix expression; " + $"left is \"{leftOperandType}\", but right is \"{rightOperandType}\""); return(false); }
private void CheckIfCase(IExpression condition, Block body) { if (!ExpressionAnalyzer.IsExpressionValid(_context, _currentScope, condition)) { return; } var conditionType = Typer.GetExpressionType(_context, _currentScope, condition); if (conditionType != null && !(conditionType is BooleanType)) { _context.Error( condition.Span, "condition does not evaluate to \"bool\" type"); } AnalyzeBlock(body); }
public bool VisitSubscriptExpression(SubscriptExpression subscriptExpression) { if (!IsExpressionValid(subscriptExpression.Operand) || !IsExpressionValid(subscriptExpression.Index)) { return(false); } var operandType = Typer.GetExpressionType( _context, _environment, subscriptExpression.Operand); if (operandType == null) { return(false); } if (!(operandType is ArrayType)) { _context.Error( subscriptExpression.Span, $"cannot index into a non-array type \"{operandType}\""); return(false); } var indexType = Typer.GetExpressionType( _context, _environment, subscriptExpression.Index); if (indexType == null) { return(false); } if (!(indexType is IntegerType)) { _context.Error( subscriptExpression.Span, $"type \"{operandType}\" cannot be indexed by type \"{indexType}\""); return(false); } return(true); }
public void VisitAssignmentStatement(AssignmentStatement assignmentStatement) { if (!ExpressionAnalyzer.IsExpressionValid( _context, _currentScope, assignmentStatement.Target) || !ExpressionAnalyzer.IsExpressionValid( _context, _currentScope, assignmentStatement.Value)) { return; } if (!IsLValue(assignmentStatement.Target)) { _context.Error( assignmentStatement.Target.Span, "left-hand of the assignment is not assignable"); return; } var targetType = Typer.GetExpressionType( _context, _currentScope, assignmentStatement.Target); var valueType = Typer.GetExpressionType( _context, _currentScope, assignmentStatement.Value); if (targetType == null || valueType == null) { return; } if (!targetType.IsSame(valueType)) { _context.Error( assignmentStatement.Value.Span, $"type mismatch; expected \"{targetType}\", but found \"{valueType}\""); } }
public void VisitAssertStatement(AssertStatement assertStatement) { if (!ExpressionAnalyzer.IsExpressionValid( _context, _currentScope, assertStatement.Condition)) { return; } var conditionType = Typer.GetExpressionType( _context, _currentScope, assertStatement.Condition); if (conditionType != null && !(conditionType is BooleanType)) { _context.Error( assertStatement.Condition.Span, $"type mismatch; expected \"bool\", but found \"{conditionType}\""); } }
public void VisitWhileStatement(WhileStatement whileStatement) { if (ExpressionAnalyzer.IsExpressionValid( _context, _currentScope, whileStatement.Condition)) { var conditionType = Typer.GetExpressionType( _context, _currentScope, whileStatement.Condition); if (conditionType != null && !conditionType.IsSame(new BooleanType())) { _context.Error( whileStatement.Condition.Span, "while loop condition does not evaluate to type \"bool\""); } } _loopNestLevel++; AnalyzeBlock(whileStatement.Body); _loopNestLevel--; }
public bool VisitPrefixOperation(PrefixOperation prefixOperation) { if (!IsExpressionValid(prefixOperation.Operand)) { return(false); } var operandType = Typer.GetExpressionType( _context, _environment, prefixOperation.Operand); if (operandType == null || operandType.GetPrefixOperationResultType(prefixOperation.Operator.Node) != null) { return(true); } _context.Error( prefixOperation.Span, "cannot apply unary operator " + $"{prefixOperation.Operator.Node.GetDescription()} to type \"{operandType}\""); return(false); }
public void VisitVariableDefinition(VariableDefinition variableDefinition) { if (variableDefinition.TypeSignature != null && variableDefinition.Initializer != null) { var variableType = TypeSignatureParser.ParseTypeSignature( _context, variableDefinition.TypeSignature); if (!ExpressionAnalyzer.IsExpressionValid( _context, _currentScope, variableDefinition.Initializer)) { return; } var initializerType = Typer.GetExpressionType( _context, _currentScope, variableDefinition.Initializer); if (variableType != null && !variableType.IsSame(initializerType)) { // We made sure in the StatementParser that a definition without both initializer // and type signature is not a valid AST item and discarded it with an error. Debug.Assert(variableDefinition.Initializer != null); _context.Error( variableDefinition.Initializer.Span, $"expected type \"{variableType}\", but found \"{initializerType}\""); } _astContext.AddNodeType(variableDefinition.NodeId, variableType); } else if (variableDefinition.TypeSignature != null && variableDefinition.Initializer == null) { var variableType = TypeSignatureParser.ParseTypeSignature( _context, variableDefinition.TypeSignature); _astContext.AddNodeType(variableDefinition.NodeId, variableType); } else // variableDefinition.TypeSignature == null && variableDefinition.Initializer != null { if (!ExpressionAnalyzer.IsExpressionValid( _context, _currentScope, variableDefinition.Initializer)) { return; } var initializerType = Typer.GetExpressionType( _context, _currentScope, variableDefinition.Initializer); switch (initializerType) { case VoidType _: // Again, the linter is overly sensitive. There's no way for the Initializer // field to be null at this point. Debug.Assert(variableDefinition.Initializer != null); _context.Error( variableDefinition.Initializer.Span, "type \"void\" cannot be assigned to a variable"); break; case null: return; default: _astContext.AddNodeType(variableDefinition.NodeId, initializerType); break; } } if (!_currentScope.DefineSymbol( variableDefinition, _astContext.GetNodeType(variableDefinition.NodeId))) { _context.Error( variableDefinition.Span, $"redefined previously defined symbol \"{variableDefinition.Identifier}\""); } }