def highest_number_type(left, right): if left == AST.DecimalTypeNode() or right == AST.DecimalTypeNode(): return AST.DecimalTypeNode() elif left == AST.IntTypeNode() and right == AST.IntTypeNode(): return AST.IntTypeNode() else: assert False, "Not both operands are of number type!"
def test_arithmetic_expr(self): self.check_good_expression("10 * 20", AST.IntTypeNode()) self.check_good_expression("10.0 * 20", AST.DecimalTypeNode()) self.check_good_expression("10 + 20", AST.IntTypeNode()) self.check_good_expression("10.0 + 20", AST.DecimalTypeNode()) self.check_good_expression("\"abc\" + \"def\"", AST.StringTypeNode()) self.check_bad_expression("10 * \"abc\"", 0, 1) self.check_bad_expression("10 + true", 0, 1) self.check_bad_expression("10 + \"abc\"", 0, 1)
def test_question_parsing(self): def format_question(q, n, var_type): return "\"{}\" {}: {}".format(q, n, var_type) question = "Did you sell a house in 2010?" name = "hasSoldHouse" q_type = AST.BoolTypeNode() q_str = format_question(question, name, "boolean") test_node = AST.QuestionNode(question, name, q_type) self.validate_node(self.q_parser, q_str, test_node) question = "Did you sell a house in 2010?" q_type = AST.IntTypeNode() q_str = format_question(question, name, "integer") test_node = AST.QuestionNode(question, name, q_type) self.validate_node(self.q_parser, q_str, test_node) question = "question?" name = "decimalVar" q_type = AST.DecimalTypeNode() q_str = format_question(question, name, "decimal") test_node = AST.QuestionNode(question, name, q_type) self.validate_node(self.q_parser, q_str, test_node) question_str = "name: \"question?\" boolean " self.check_parse_exception(self.q_parser, question_str, pp.ParseException) question_str = "\"question\" name boolean " self.check_parse_exception(self.q_parser, question_str, pp.ParseException) question_str = "\"question?\" boolean: name" self.check_parse_exception(self.q_parser, question_str, pp.ParseException)
def arithmetic_expr_node(self, expr_node): """ Default behavior for arithmetic binOps. """ left, right = self.get_binop_types(expr_node) if not (left.is_numeric() and right.is_numeric()): self.handler.add_binop_error(expr_node, left, right) return AST.DecimalTypeNode() return self.highest_number_type(left, right)
def mon_op_node(self, mon_op_node): """ Default behavior for monOps. """ var_type = self.get_monop_type(mon_op_node) if not var_type.is_numeric(): self.handler.add_monop_error(mon_op_node, var_type) return AST.DecimalTypeNode() return var_type
def highest_number_type(left, right): """ :type left: AST.TypeNode """ if left.is_decimal() or right.is_decimal(): return AST.DecimalTypeNode() elif left.is_money() or right.is_money(): return AST.MoneyTypeNode() elif left.is_integer() and right.is_integer(): return AST.IntTypeNode() else: assert False, "Not both operands are of number type!"
def add_node(self, add_node): # '+' has different behavior than the other calculation binOps. left, right = self.get_binop_types(add_node) valid_types = left.is_alphanumeric() and right.is_alphanumeric() different_types = left.is_numeric() ^ right.is_numeric() if not valid_types or different_types: self.handler.add_binop_error(add_node, left, right) return AST.DecimalTypeNode() if left.is_numeric() and right.is_numeric(): return self.highest_number_type(left, right) return left
def calculation_expr_node(self, expr_node): left, right = self.get_binop_types(expr_node) if not (left.is_numeric() and right.is_numeric()): self.handler.add_binop_error(expr_node, left, right) return AST.DecimalTypeNode() return self.highest_number_type(left, right)
def mon_op_node(self, mon_op_node): var_type = self.get_monop_type(mon_op_node) if not var_type.is_numeric(): self.handler.add_monop_error(mon_op_node, var_type) return AST.DecimalTypeNode() return var_type
def decimal_node(_): return AST.DecimalTypeNode()