• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ArkScript-lang / Ark / 12320172861

13 Dec 2024 05:24PM UTC coverage: 79.237% (+1.9%) from 77.378%
12320172861

Pull #503

github

web-flow
Merge 07e6b2965 into db229689d
Pull Request #503: December 2024 fixes

131 of 143 new or added lines in 10 files covered. (91.61%)

9 existing lines in 2 files now uncovered.

5667 of 7152 relevant lines covered (79.24%)

14742.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.0
/src/arkreactor/Compiler/AST/Optimizer.cpp
1
#include <Ark/Compiler/AST/Optimizer.hpp>
2

3
namespace Ark::internal
4
{
5
    Optimizer::Optimizer(const unsigned debug) noexcept :
300✔
6
        Pass("Optimizer", debug), m_ast()
150✔
7
    {}
450✔
8

9
    void Optimizer::process(const Node& ast)
6✔
10
    {
6✔
11
        // do not handle non-list nodes
12
        if (ast.nodeType() != NodeType::List)
6✔
NEW
13
            return;
×
14
        m_ast = ast;
6✔
15

16
        m_logger.traceStart("process");
6✔
17
        countAndPruneDeadCode(m_ast);
6✔
18

19
        // logic: remove piece of code with only 1 reference, if they aren't function calls
20
        pruneUnusedGlobalVariables(m_ast);
6✔
21
        m_logger.traceEnd();
6✔
22

23
        m_logger.trace("AST after name pruning nodes");
6✔
24
        if (m_logger.shouldTrace())
6✔
NEW
25
            m_ast.debugPrint(std::cout) << '\n';
×
26
    }
6✔
27

28
    const Node& Optimizer::ast() const noexcept
6✔
29
    {
6✔
30
        return m_ast;
6✔
31
    }
32

33
    void Optimizer::countAndPruneDeadCode(Node& node)
308✔
34
    {
308✔
35
        if (node.nodeType() == NodeType::Symbol || node.nodeType() == NodeType::Capture)
308✔
36
        {
37
            auto [element, inserted] = m_sym_appearances.try_emplace(node.string(), 0);
181✔
38
            if (!inserted)
115✔
39
                element->second++;
66✔
40
        }
115✔
41
        else if (node.nodeType() == NodeType::Field)
193✔
42
        {
43
            for (auto& child : node.list())
12✔
44
                countAndPruneDeadCode(child);
8✔
45
        }
4✔
46
        else if (node.nodeType() == NodeType::List)
189✔
47
        {
48
            // FIXME: very primitive removal of (if true/false ...) and (while false ...)
49
            if (node.constList().size() > 1 && node.constList().front().nodeType() == NodeType::Keyword &&
193✔
50
                (node.constList().front().keyword() == Keyword::If || node.constList().front().keyword() == Keyword::While))
50✔
51
            {
52
                const auto keyword = node.constList().front().keyword();
10✔
53
                const auto condition = node.constList()[1];
10✔
54
                const auto body = node.constList()[2];
10✔
55

56
                if (condition.nodeType() == NodeType::Symbol && condition.string() == "false")
10✔
57
                {
58
                    // replace the node by an Unused, it is either a (while cond block) or (if cond then)
59
                    if (node.constList().size() == 3)
3✔
60
                        node = Node(NodeType::Unused);
2✔
61
                    else  // it is a (if cond then else)
62
                    {
63
                        const auto back = node.constList().back();
1✔
64
                        node = back;
1✔
65
                    }
1✔
66
                }
3✔
67
                // only update '(if true then [else])' to 'then'
68
                else if (keyword == Keyword::If && condition.nodeType() == NodeType::Symbol && condition.string() == "true")
7✔
69
                    node = body;
1✔
70

71
                // do not try to iterate on the child nodes as they do not exist anymore,
72
                // we performed some optimization that squashed them.
73
                if (!node.isListLike())
10✔
74
                    return;
2✔
75
            }
10✔
76

77
            // iterate over children
78
            for (auto& child : node.list())
392✔
79
                countAndPruneDeadCode(child);
294✔
80
        }
98✔
81
        else if (node.nodeType() == NodeType::Namespace)
89✔
NEW
82
            countAndPruneDeadCode(*node.arkNamespace().ast);
×
83
    }
308✔
84

85
    void Optimizer::pruneUnusedGlobalVariables(Node& node)
6✔
86
    {
6✔
87
        for (auto& child : node.list())
41✔
88
        {
89
            if (child.nodeType() == NodeType::List && !child.constList().empty() &&
62✔
90
                child.constList()[0].nodeType() == NodeType::Keyword)
27✔
91
            {
92
                const Keyword kw = child.constList()[0].keyword();
14✔
93

94
                // eliminate nested begin blocks
95
                if (kw == Keyword::Begin)
14✔
96
                {
NEW
97
                    pruneUnusedGlobalVariables(child);
×
98
                    // skip let/ mut detection
99
                    continue;
×
100
                }
101

102
                // check if it's a let/mut declaration and perform removal
103
                if (kw == Keyword::Let || kw == Keyword::Mut)
14✔
104
                {
105
                    const std::string name = child.constList()[1].string();
13✔
106
                    // a variable was only declared and never used
107
                    if (m_sym_appearances.contains(name) && m_sym_appearances[name] < 1)
13✔
108
                    {
109
                        m_logger.debug("Removing unused variable '{}'", name);
2✔
110
                        // erase the node by turning it to an Unused node
111
                        child = Node(NodeType::Unused);
2✔
112
                    }
2✔
113
                }
13✔
114
            }
14✔
115
            else if (child.nodeType() == NodeType::Namespace)
21✔
NEW
116
                pruneUnusedGlobalVariables(*child.arkNamespace().ast);
×
117
        }
35✔
118
    }
6✔
119
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc