#include #include #include #include #include // Analyze binary conditional nodes fzl_an_res_t analyze_condition(fzl_analyzer_t *analyzer, fzl_node_t *cond_node) { if (!analyzer) return (fzl_an_res_t){.error = true}; if (!cond_node || (cond_node->type != FZL_NODETYPE_OR && cond_node->type != FZL_NODETYPE_AND && cond_node->type != FZL_NODETYPE_LESS && cond_node->type != FZL_NODETYPE_LESS_EQUAL && cond_node->type != FZL_NODETYPE_GREATER && cond_node->type != FZL_NODETYPE_GREATER_EQUAL && cond_node->type != FZL_NODETYPE_EQUAL && cond_node->type != FZL_NODETYPE_NEQUAL)) { an_push_error(analyzer, NULL, "node is not a binary conditional operator"); return (fzl_an_res_t){.error = true}; } fzl_an_res_t left = analyze_common(analyzer, cond_node->binary_op.left); if (left.error) return (fzl_an_res_t){.error = true}; fzl_an_res_t right = analyze_common(analyzer, cond_node->binary_op.right); if (right.error) return (fzl_an_res_t){.error = true}; if (cond_node->type == FZL_NODETYPE_OR || cond_node->type == FZL_NODETYPE_AND) { if (left.type != FZL_TYPE_BOOL) an_push_warning(analyzer, cond_node->binary_op.left->token, "left operand is not resulting with boolean type"); if (right.type != FZL_TYPE_BOOL) an_push_warning(analyzer, cond_node->binary_op.right->token, "right operand is not resulting with boolean type"); } else if (cond_node->type == FZL_NODETYPE_LESS || cond_node->type == FZL_NODETYPE_LESS_EQUAL || cond_node->type == FZL_NODETYPE_GREATER || cond_node->type == FZL_NODETYPE_GREATER_EQUAL) { if (left.type < FZL_TYPE_INT8) { an_push_error(analyzer, cond_node->binary_op.left->token, "left operand must have integer type"); return (fzl_an_res_t){.error = true}; } if (left.type < FZL_TYPE_INT8) { an_push_error(analyzer, cond_node->binary_op.left->token, "right operand must have integer type"); return (fzl_an_res_t){.error = true}; } } else if (left.type >= FZL_TYPE_INT8) { if (right.type < FZL_TYPE_INT8) { an_push_error(analyzer, cond_node->binary_op.right->token, "right operand must have integer type"); return (fzl_an_res_t){.error = true}; } return (fzl_an_res_t){ .error = false, .type = FZL_TYPE_BOOL, .classname = NULL}; } else if (left.type == FZL_TYPE_OBJECT) { if (!left.classname || !right.classname) { an_push_error(analyzer, cond_node->binary_op.left->token, "unhandled error :("); return (fzl_an_res_t){.error = true}; } if (!an_is_compatible(left.type, right.type, left.classname, right.classname)) { snprintf(an_problem, sizeof(an_problem), "'%s' and '%s' are incompatible", an_typetostr(left.type, left.classname), an_typetostr(right.type, right.classname)); an_push_error(analyzer, cond_node->binary_op.right->token, an_problem); return (fzl_an_res_t){.error = true}; } } else if (left.type == FZL_TYPE_STRING) { if (right.type != FZL_TYPE_STRING) { an_push_error(analyzer, cond_node->binary_op.right->token, "right operand must be a string"); return (fzl_an_res_t){.error = true}; } } else if (!an_is_compatible(left.type, right.type, left.classname, right.classname)) { snprintf(an_problem, sizeof(an_problem), "equality not supported between %s and %s", an_typetostr(left.type, left.classname), an_typetostr(right.type, right.classname)); return (fzl_an_res_t){.error = true}; } return (fzl_an_res_t){ .error = false, .type = FZL_TYPE_BOOL, .classname = NULL}; }