Commit e22aff57 authored by jan.koester's avatar jan.koester
Browse files

if else

parent 5657cf56
Loading
Loading
Loading
Loading
+64 −52
Changes for parser.cpp: 64 added lines, 52 removed lines.
Original line number Diff line number Diff line
@@ -215,22 +215,63 @@ bool Parser::handle_conditional(const std::string& line_in, Makefile& mf) {
        }
    }

    if (line.substr(0, 5) == "ifeq " || line.substr(0, 5) == "ifeq\t" ||
        line == "ifeq") {
    auto is_if_directive = [](const std::string& l) {
        return l.substr(0, 5) == "ifeq " || l.substr(0, 5) == "ifeq\t" || l == "ifeq" ||
               l.substr(0, 6) == "ifneq " || l.substr(0, 6) == "ifneq\t" || l == "ifneq" ||
               l.substr(0, 6) == "ifdef " || l.substr(0, 6) == "ifdef\t" ||
               l.substr(0, 7) == "ifndef " || l.substr(0, 7) == "ifndef\t";
    };

    if (is_if_directive(line)) {
        // A nested conditional inside an inactive branch is always inactive.
        if (!cond_stack_.empty() && !cond_stack_.back().active) {
            cond_stack_.push_back({false, false});
            return true;
        }
        bool cond = eval_if_directive(line, mf);
        cond_stack_.push_back({cond, cond});
        return true;
    }

    if (line == "else" || line.substr(0, 5) == "else ") {
        if (cond_stack_.empty()) return true;
        std::string rest = line.size() > 5 ? trim(line.substr(5)) : "";
        bool parent_active = cond_stack_.size() < 2 || cond_stack_[cond_stack_.size() - 2].active;
        if (!parent_active || cond_stack_.back().seen_true) {
            // Either the enclosing branch is dead, or an earlier branch of this
            // if-chain already matched: this clause is inactive regardless.
            cond_stack_.back().active = false;
            return true;
        }
        if (!rest.empty() && is_if_directive(rest)) {
            // 'else ifeq/ifneq/ifdef/ifndef ...': evaluate the new condition.
            bool cond = eval_if_directive(rest, mf);
            cond_stack_.back().active = cond;
            if (cond) cond_stack_.back().seen_true = true;
        } else {
            // Plain 'else'.
            cond_stack_.back().active = true;
            cond_stack_.back().seen_true = true;
        }
        return true;
    }

    if (line == "endif") {
        if (!cond_stack_.empty()) cond_stack_.pop_back();
        return true;
    }

    return false;
}

bool Parser::eval_if_directive(const std::string& line, Makefile& mf) {
    if (line.substr(0, 5) == "ifeq " || line.substr(0, 5) == "ifeq\t" || line == "ifeq") {
        std::string args = trim(line.substr(4));
        std::string a, b;
        if (!args.empty() && args[0] == '(') {
            int depth = 0;
            size_t comma_pos = std::string::npos;
            for (size_t i = 1; i < args.size(); i++) {
                // Count plain parens only. '$(' contains a '(' that is matched
                // by its corresponding ')', so no special-casing is needed; a
                // separate '$' increment would double-count and hide the
                // top-level comma (e.g. ifeq ($(filter a,$(X)),)).
                if (args[i] == '(') { depth++; continue; }
                if (args[i] == ')') {
                    if (depth > 0) { depth--; continue; }
@@ -258,25 +299,16 @@ bool Parser::handle_conditional(const std::string& line_in, Makefile& mf) {
                }
            }
        }
        a = expand(a, mf);
        b = expand(b, mf);
        cond_stack_.push_back({a == b, a == b});
        return true;
        return expand(a, mf) == expand(b, mf);
    }

    if (line.substr(0, 6) == "ifneq " || line.substr(0, 6) == "ifneq\t" ||
        line == "ifneq") {
        if (!cond_stack_.empty() && !cond_stack_.back().active) {
            cond_stack_.push_back({false, false});
            return true;
        }
    if (line.substr(0, 6) == "ifneq " || line.substr(0, 6) == "ifneq\t" || line == "ifneq") {
        std::string args = trim(line.substr(5));
        std::string a, b;
        if (!args.empty() && args[0] == '(') {
            int depth = 0;
            size_t comma_pos = std::string::npos;
            for (size_t i = 1; i < args.size(); i++) {
                // Plain paren counting (see ifeq above for rationale).
                if (args[i] == '(') { depth++; continue; }
                if (args[i] == ')') {
                    if (depth > 0) { depth--; continue; }
@@ -291,50 +323,30 @@ bool Parser::handle_conditional(const std::string& line_in, Makefile& mf) {
                size_t end = args.rfind(')');
                b = trim(args.substr(comma_pos + 1, end - comma_pos - 1));
            }
        } else if (args.size() >= 4 && (args[0] == '"' || args[0] == '\'')) {
            char q1 = args[0];
            size_t end1 = args.find(q1, 1);
            if (end1 != std::string::npos) {
                a = args.substr(1, end1 - 1);
                std::string rest = trim(args.substr(end1 + 1));
                if (!rest.empty()) {
                    char q2 = rest[0];
                    size_t end2 = rest.find(q2, 1);
                    if (end2 != std::string::npos) b = rest.substr(1, end2 - 1);
                }
            }
        a = expand(a, mf);
        b = expand(b, mf);
        cond_stack_.push_back({a != b, a != b});
        return true;
        }
        return expand(a, mf) != expand(b, mf);
    }

    if (line.substr(0, 6) == "ifdef " || line.substr(0, 6) == "ifdef\t") {
        if (!cond_stack_.empty() && !cond_stack_.back().active) {
            cond_stack_.push_back({false, false});
            return true;
        }
        std::string var = trim(line.substr(5));
        bool defined = mf.variables.count(var) && !mf.variables.at(var).value.empty();
        cond_stack_.push_back({defined, defined});
        return true;
        return mf.variables.count(var) && !mf.variables.at(var).value.empty();
    }

    if (line.substr(0, 7) == "ifndef " || line.substr(0, 7) == "ifndef\t") {
        if (!cond_stack_.empty() && !cond_stack_.back().active) {
            cond_stack_.push_back({false, false});
            return true;
        }
        std::string var = trim(line.substr(6));
        bool defined = mf.variables.count(var) && !mf.variables.at(var).value.empty();
        cond_stack_.push_back({!defined, !defined});
        return true;
    }

    if (line == "else" || line.substr(0, 5) == "else ") {
        if (cond_stack_.empty()) return true;
        bool parent_active = cond_stack_.size() < 2 || cond_stack_[cond_stack_.size() - 2].active;
        if (parent_active && !cond_stack_.back().seen_true) {
            cond_stack_.back().active = true;
            cond_stack_.back().seen_true = true;
        } else {
            cond_stack_.back().active = false;
        }
        return true;
    }

    if (line == "endif") {
        if (!cond_stack_.empty()) cond_stack_.pop_back();
        return true;
        return !(mf.variables.count(var) && !mf.variables.at(var).value.empty());
    }

    return false;