ArkScript
A small, fast, functional and scripting language for video games
Optimizer.cpp
Go to the documentation of this file.
2
3namespace Ark::internal
4{
5 Optimizer::Optimizer(const unsigned debug) noexcept :
6 Pass("Optimizer", debug), m_ast()
7 {}
8
9 void Optimizer::process(const Node& ast)
10 {
11 // do not handle non-list nodes
13 return;
14 m_ast = ast;
15
16 m_logger.traceStart("process");
18
19 // logic: remove piece of code with only 1 reference, if they aren't function calls
22
23 m_logger.trace("AST after name pruning nodes");
25 m_ast.debugPrint(std::cout) << '\n';
26 }
27
28 const Node& Optimizer::ast() const noexcept
29 {
30 return m_ast;
31 }
32
34 {
35 if (node.nodeType() == NodeType::Symbol || node.nodeType() == NodeType::Capture)
36 {
37 auto [element, inserted] = m_sym_appearances.try_emplace(node.string(), 0);
38 if (!inserted)
39 element->second++;
40 }
41 else if (node.nodeType() == NodeType::Field)
42 {
43 for (auto& child : node.list())
45 }
46 else if (node.nodeType() == NodeType::List)
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 &&
50 (node.constList().front().keyword() == Keyword::If || node.constList().front().keyword() == Keyword::While))
51 {
52 const auto keyword = node.constList().front().keyword();
53 const auto condition = node.constList()[1];
54 const auto body = node.constList()[2];
55
56 if (condition.nodeType() == NodeType::Symbol && condition.string() == "false")
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)
60 node = Node(NodeType::Unused);
61 else // it is a (if cond then else)
62 {
63 const auto back = node.constList().back();
64 node = back;
65 }
66 }
67 // only update '(if true then [else])' to 'then'
68 else if (keyword == Keyword::If && condition.nodeType() == NodeType::Symbol && condition.string() == "true")
69 node = body;
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())
74 return;
75 }
76
77 // iterate over children
78 for (auto& child : node.list())
80 }
81 else if (node.nodeType() == NodeType::Namespace)
83 }
84
86 {
87 for (auto& child : node.list())
88 {
89 if (child.nodeType() == NodeType::List && !child.constList().empty() &&
90 child.constList()[0].nodeType() == NodeType::Keyword)
91 {
92 const Keyword kw = child.constList()[0].keyword();
93
94 // eliminate nested begin blocks
95 if (kw == Keyword::Begin)
96 {
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)
104 {
105 const std::string name = child.constList()[1].string();
106 // a variable was only declared and never used
107 if (m_sym_appearances.contains(name) && m_sym_appearances[name] < 1)
108 {
109 m_logger.debug("Removing unused variable '{}'", name);
110 // erase the node by turning it to an Unused node
111 child = Node(NodeType::Unused);
112 }
113 }
114 }
115 else if (child.nodeType() == NodeType::Namespace)
116 pruneUnusedGlobalVariables(*child.arkNamespace().ast);
117 }
118 }
119}
Optimizes a given ArkScript AST.
bool shouldTrace() const
Definition Logger.hpp:39
void trace(const char *fmt, Args &&... args)
Write a trace level log using fmtlib.
Definition Logger.hpp:98
void debug(const char *fmt, Args &&... args)
Write a debug level log using fmtlib.
Definition Logger.hpp:65
void traceStart(std::string &&trace_name)
Definition Logger.hpp:75
A node of an Abstract Syntax Tree for ArkScript.
Definition Node.hpp:31
NodeType nodeType() const noexcept
Return the node type.
Definition Node.cpp:77
bool isListLike() const noexcept
Check if the node is a list like node.
Definition Node.cpp:82
const std::string & string() const noexcept
Return the string held by the value (if the node type allows it)
Definition Node.cpp:37
const std::vector< Node > & constList() const noexcept
Return the list of sub-nodes held by the node.
Definition Node.cpp:72
Namespace & arkNamespace() noexcept
Return the namespace held by the value (if the node type allows it)
Definition Node.cpp:52
std::ostream & debugPrint(std::ostream &os) const noexcept
Print a node to an output stream with added type annotations.
Definition Node.cpp:233
std::vector< Node > & list() noexcept
Return the list of sub-nodes held by the node.
Definition Node.cpp:67
Optimizer(unsigned debug) noexcept
Construct a new Optimizer.
Definition Optimizer.cpp:5
void pruneUnusedGlobalVariables(Node &node)
Remove unused global variables from the AST.
Definition Optimizer.cpp:85
const Node & ast() const noexcept override
Returns the modified AST.
Definition Optimizer.cpp:28
void countAndPruneDeadCode(Node &node)
Count the occurrences of each symbol in the AST, recursively, and prune if false/true,...
Definition Optimizer.cpp:33
std::unordered_map< std::string, unsigned > m_sym_appearances
Definition Optimizer.hpp:54
void process(const Node &ast) override
Send the AST to the optimizer, then run the different optimization strategies on it.
Definition Optimizer.cpp:9
An interface to describe compiler passes.
Definition Pass.hpp:23
Keyword
The different keywords available.
Definition Common.hpp:60
std::shared_ptr< Node > ast
Definition Namespace.hpp:18