xaizek / zograscope (License: AGPLv3 only) (since 2018-12-07)
Mainly a syntax-aware diff that also provides a number of additional tools.
<root> / src / make / MakeLanguage.cpp (aeca51ae5b3329b9146f9498f65fc2e36e810488) (6,284B) (mode 100644) [raw]
// Copyright (C) 2017 xaizek <xaizek@posteo.net>
//
// This file is part of zograscope.
//
// zograscope is free software: you can redistribute it and/or modify
// it under the terms of version 3 of the GNU Affero General Public License as
// published by the Free Software Foundation.
//
// zograscope is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with zograscope.  If not, see <http://www.gnu.org/licenses/>.

#include "MakeLanguage.hpp"

#include <cassert>

#include "make/MakeSType.hpp"
#include "make/make-parser.gen.hpp"
#include "mtypes.hpp"
#include "tree.hpp"
#include "types.hpp"

using namespace makestypes;

MakeLanguage::MakeLanguage() : map(NTOKENS)
{
    map[COMMENT] = Type::Comments;
    map[ASSIGN_OP] = Type::Assignments;
    map[CALL_PREFIX] = Type::LeftBrackets;
    map[CALL_SUFFIX] = Type::RightBrackets;
    map['('] = Type::LeftBrackets;
    map[')'] = Type::RightBrackets;
    map[':'] = Type::Operators;

    map[VAR] = Type::UserTypes;

    map[OVERRIDE] = Type::Keywords;
    map[EXPORT] = Type::Keywords;
    map[UNEXPORT] = Type::Keywords;

    map[IFDEF] = Type::Directives;
    map[IFNDEF] = Type::Directives;
    map[IFEQ] = Type::Directives;
    map[IFNEQ] = Type::Directives;
    map[ELSE] = Type::Directives;
    map[ENDIF] = Type::Directives;

    map[DEFINE] = Type::Directives;
    map[ENDEF] = Type::Directives;
    map[UNDEFINE] = Type::Directives;

    map[INCLUDE] = Type::Directives;

    map[SLIT] = Type::StrConstants;
}

Type
MakeLanguage::mapToken(int token) const
{
    return map[token];
}

TreeBuilder
MakeLanguage::parse(const std::string &contents, const std::string &fileName,
                    int tabWidth, bool debug, cpp17::pmr::monolithic &mr) const
{
    return make_parse(contents, fileName, tabWidth, debug, mr);
}

bool
MakeLanguage::isTravellingNode(const Node */*x*/) const
{
    return false;
}

bool
MakeLanguage::hasFixedStructure(const Node */*x*/) const
{
    return false;
}

bool
MakeLanguage::canBeFlattened(const Node */*parent*/, const Node *child,
                             int level) const
{
    switch (level) {
        case 0:
        case 1:
        case 2:
            return false;
        default:
            return -child->stype != MakeSType::CallExpr
                && -child->stype != MakeSType::Recipe
                && -child->stype != MakeSType::Rule;
    }
}

bool
MakeLanguage::isUnmovable(const Node *x) const
{
    return (-x->stype == MakeSType::Statements);
}

bool
MakeLanguage::isContainer(const Node *x) const
{
    return (-x->stype == MakeSType::Statements);
}

bool
MakeLanguage::isDiffable(const Node *x) const
{
    return -x->stype == MakeSType::Comment
        || Language::isDiffable(x);
}

bool
MakeLanguage::isStructural(const Node *x) const
{
    return Language::isStructural(x);
}

bool
MakeLanguage::isEolContinuation(const Node *x) const
{
    return (-x->stype == MakeSType::LineGlue);
}

bool
MakeLanguage::alwaysMatches(const Node *x) const
{
    return (-x->stype == MakeSType::Makefile);
}

bool
MakeLanguage::isPseudoParameter(const Node */*x*/) const
{
    return false;
}

bool
MakeLanguage::shouldSplice(SType parent, const Node *childNode) const
{
    MakeSType child = -childNode->stype;

    if (-parent == MakeSType::Statements && child == MakeSType::Statements) {
        return true;
    }

    if (childNode->type == Type::Virtual &&
        child == MakeSType::TemporaryContainer) {
        return true;
    }

    return false;
}

bool
MakeLanguage::isValueNode(SType stype) const
{
    return (-stype == MakeSType::IfCond);
}

bool
MakeLanguage::isLayerBreak(SType /*parent*/, SType stype) const
{
    return -stype == MakeSType::CallExpr
        || -stype == MakeSType::AssignmentExpr
        || -stype == MakeSType::Rule
        || -stype == MakeSType::Recipe
        || isValueNode(stype);
}

bool
MakeLanguage::shouldDropLeadingWS(SType /*stype*/) const
{
    return false;
}

bool
MakeLanguage::isSatellite(SType stype) const
{
    return (-stype == MakeSType::Separator);
}

MType
MakeLanguage::classify(SType stype) const
{
    switch (-stype) {
        case MakeSType::Comment:
            return MType::Comment;

        case MakeSType::CallExpr:
            return MType::Call;

        case MakeSType::Directive:
        case MakeSType::Include:
            return MType::Directive;

        default:
            return MType::Other;
    }
}

const char *
MakeLanguage::toString(SType stype) const
{
    switch (-stype) {
        case MakeSType::None:                return "MakeSType::None";
        case MakeSType::LineGlue:            return "MakeSType::LineGlue";
        case MakeSType::Makefile:            return "MakeSType::Makefile";
        case MakeSType::Statements:          return "MakeSType::Statements";
        case MakeSType::Separator:           return "MakeSType::Separator";
        case MakeSType::IfStmt:              return "MakeSType::IfStmt";
        case MakeSType::IfCond:              return "MakeSType::IfCond";
        case MakeSType::MultilineAssignment: return "MakeSType::MultilineAssignment";
        case MakeSType::TemporaryContainer:  return "MakeSType::TemporaryContainer";
        case MakeSType::Include:             return "MakeSType::Include";
        case MakeSType::Directive:           return "MakeSType::Directive";
        case MakeSType::Comment:             return "MakeSType::Comment";
        case MakeSType::AssignmentExpr:      return "MakeSType::AssignmentExpr";
        case MakeSType::CallExpr:            return "MakeSType::CallExpr";
        case MakeSType::ArgumentList:        return "MakeSType::ArgumentList";
        case MakeSType::Argument:            return "MakeSType::Argument";
        case MakeSType::Rule:                return "MakeSType::Rule";
        case MakeSType::Recipe:              return "MakeSType::Recipe";
        case MakeSType::Punctuation:         return "MakeSType::Punctuation";
    }

    assert(false && "Unhandled enumeration item");
    return "<UNKNOWN>";
}
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/zograscope

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/zograscope

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master