// checkForNonBoolCondition checks if the condition is of a boolean type, and if not, adds an error to the typechecker func checkForNonBoolCondition(condition interfaces.Expr, typeCheckArgs interfaces.TypeCheckArgs) { typeOfCondition := condition.TypeCheck(typeCheckArgs) if typeOfCondition != expr.NewBoolType() && typeOfCondition != expr.NewUnknownType() { typeCheckArgs.TypeChecker().AddEncounteredError(errors.NewNonBooleanConditionError(condition, typeOfCondition)) } }
func (this VarDecl) TypeCheck(typeCheckArgs interfaces.TypeCheckArgs) { // store type for identifier so when we find VarExpr with this VarID we know its real type (used during typechecking) typeCheckArgs.Symbols().SetTypeForVarID(this.ValueType(), this.VariableIdentifier()) // we mark it as known to indicate that earlier references to this VarID are valid typeCheckArgs.TypeChecker().MarkVarIDAsKnown(this.VariableIdentifier()) }
// checkQuestionForRedeclarationWithDifferentTypes checks if the passed question has been declared before with a different type, and if so, adds an error to the typechecker func checkQuestionForRedeclarationWithDifferentTypes(question interfaces.Question, typeCheckArgs interfaces.TypeCheckArgs) { varDecl := question.VarDecl() varID := varDecl.VariableIdentifier() if typeCheckArgs.Symbols().IsTypeSetForVarID(varID) && typeCheckArgs.Symbols().TypeForVarID(varID) != varDecl.ValueType() { typeCheckArgs.TypeChecker().AddEncounteredError(errors.NewQuestionRedeclaredWithDifferentTypesError(varDecl.ValueType(), typeCheckArgs.Symbols().TypeForVarID(varID))) } }
// checkIfQuestionTypeMatchesComputationType checks if the declared computed question type and its actual type match, and if not, adds an error to the typechecker func (this ComputedQuestion) checkIfQuestionTypeMatchesComputationType(typeCheckArgs interfaces.TypeCheckArgs) { actualType := this.Computation().TypeCheck(typeCheckArgs) expectedType := this.VarDeclValueType() // check if question declaration type matches the type of the computation if actualType != expr.NewUnknownType() && actualType != expectedType { typeCheckArgs.TypeChecker().AddEncounteredError(errors.NewDeclaratedTypeAndActualTypeDeviateError(expectedType, actualType)) } }
// checkForEqualTypes checks if the operands in a BinaryOperator have the same type, and if the types are unequal adds an error to the typechecker func (binaryExpr BinaryOperator) checkForEqualTypes(typeCheckArgs interfaces.TypeCheckArgs) { lhsType := binaryExpr.LHS().TypeCheck(typeCheckArgs) rhsType := binaryExpr.RHS().TypeCheck(typeCheckArgs) if lhsType == NewUnknownType() || rhsType == NewUnknownType() { return } if lhsType != rhsType { typeCheckArgs.TypeChecker().AddEncounteredError(errors.NewOperandsOfDifferentTypesError(binaryExpr, lhsType, rhsType)) } }
func (this InputQuestion) TypeCheck(typeCheckArgs interfaces.TypeCheckArgs) { checkQuestionForDuplicateLabels(this, typeCheckArgs.TypeChecker()) checkQuestionForRedeclarationWithDifferentTypes(this, typeCheckArgs) typeCheckArgs = typeCheckArgs.SetCurrentVarDeclVisited(this.VarDecl()) this.VarDecl().TypeCheck(typeCheckArgs) collectVarIDsInExpressions(typeCheckArgs) checkForCyclicDependencies(this, typeCheckArgs.TypeChecker()) }
// checkIfOperandHasExpectedType checks that an operand's actual type matches it expected type, and if not adds an error to the typechecker func checkIfOperandHasExpectedType(expr interfaces.Expr, expectedTypes []interfaces.ValueType, typeCheckArgs interfaces.TypeCheckArgs) interfaces.ValueType { actualType := expr.TypeCheck(typeCheckArgs) if actualType == NewUnknownType() { return NewUnknownType() } if !typeIsInExpectedTypes(actualType, expectedTypes) { typeCheckArgs.TypeChecker().AddEncounteredError(errors.NewOperandWithUnexpectedTypeError(expr, expectedTypes, actualType)) } return actualType }
func (this VarExpr) TypeCheck(typeCheckArgs interfaces.TypeCheckArgs) interfaces.ValueType { typeCheckArgs.TypeChecker().AddDependencyForVarDecl(this.VarIdentifier(), typeCheckArgs.CurrentVarDeclVisited()) // Return the true type of the VarExpr; the type of the Expr referred to if typeCheckArgs.Symbols().IsTypeSetForVarID(this.VarIdentifier()) { return typeCheckArgs.Symbols().TypeForVarID(this.VarIdentifier()).(interfaces.ValueType) } // We don't already mark it as an error; because there is only one scope, the VarDecl may be simply declared later on typeCheckArgs.TypeChecker().MarkVarIDAsUnknown(this.VarIdentifier()) // No type info in symbol table (reference to undefined question) return NewUnknownType() }
func (this Form) TypeCheck(typeCheckArgs interfaces.TypeCheckArgs) { this.Content().TypeCheck(typeCheckArgs) // Only at the end of the form we truly know the question is not declared anywhere (since QL is not a sequential program) this.checkForUndefinedReferences(typeCheckArgs.TypeChecker()) }