-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInterpreter.lua
More file actions
151 lines (135 loc) · 5.12 KB
/
Copy pathInterpreter.lua
File metadata and controls
151 lines (135 loc) · 5.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
local Node = require(script.Parent.Node)
local TokenTypes = require(script.Parent.TokenTypes)
local NodeTypes = require(script.Parent.NodeTypes)
local Interpreter = {}
Interpreter.__index = Interpreter
local function convert(val)
if val.type == NodeTypes.NumberNode then
return tonumber(val.value)
elseif val.type == NodeTypes.StringNode then
return tostring(val.value)
elseif val.type == NodeTypes.BooleanNode then
return val.value == true
elseif val.type == NodeTypes.NullNode then
return 'null'
end
end
function Interpreter.new(ast: table)
assert(type(ast) == "table", "Expected table, got " .. type(ast))
local self = setmetatable({}, Interpreter)
self.current_line = 1
self.nodes = ast
return self
end
Interpreter.Operations = {
[TokenTypes.PLUS] = function(a, b)
return a + b
end,
[TokenTypes.MINUS] = function(a, b)
return a - b
end,
[TokenTypes.MULTIPLY] = function(a, b)
return a * b
end,
[TokenTypes.DIVIDE] = function(a, b)
return a / b
end,
[TokenTypes.POWER] = function(a, b)
return a ^ b
end
}
function Interpreter:Evaluate()
print(self:VisitExpression(self.nodes).value)
end
function Interpreter:VisitExpression(expression: table)
assert(type(expression) == "table", "Expected table, got " .. type(expression))
if expression.type == NodeTypes.NumberNode then
return expression
elseif expression.type == NodeTypes.BinOpNode then
return self:VisitBinOpNode(expression)
elseif expression.type == NodeTypes.UnOpNode then
return self:VisitUnOpNode(expression)
elseif expression.type == NodeTypes.CondNode then
return self:VisitCondNode(expression)
end
end
function Interpreter:VisitBinOpNode(node: table)
assert(type(node) == "table", "Expected table for parameter 'node'")
local left = self:visitExpression(node.left)
local op = node.op
local right = self:visitExpression(node.right)
local result = Node.new(NodeTypes.NumberNode, 0)
if left.type == NodeTypes.StringNode or right.type == NodeTypes.StringNode then
if op == TokenTypes.PLUS then
if left.type == NodeTypes.NumberNode and string.sub(tostring(left.value), -2) == ".0" then
left.value = string.sub(tostring(left.value), 1, -3)
elseif right.type == NodeTypes.NumberNode and string.sub(tostring(right.value), -2) == ".0" then
right.value = string.sub(tostring(right.value), 1, -3)
end
result.type = NodeTypes.StringNode
result.value = tostring(left.value) .. tostring(right.value)
end
else
if op == TokenTypes.PLUS then
result.value = left.value + right.value
elseif op == TokenTypes.MINUS then
result.value = left.value - right.value
elseif op == TokenTypes.MULTIPLY then
result.value = left.value * right.value
elseif op == TokenTypes.DIVIDE then
if right.value == 0 then
error("DivisionByZeroError on line " .. self.current_line)
end
result.value = left.value / right.value
elseif op == TokenTypes.POWER then
result.value = left.value ^ right.value
end
end
return result
end
function Interpreter:VisitUnOpNode(node)
local val = self:VisitExpression(node.node).value
if val.type == NodeTypes.BooleanNode then
return Node.new(NodeTypes.BooleanNode, not val.value)
end
return Node.new(NodeTypes.NumberNode, -val)
end
function Interpreter:VisitCondNode(node)
local left = self:VisitExpression(node.left)
local right = self:VisitExpression(node.right)
local op = node.op
local resultNode = Node.new(NodeTypes.BooleanNode, 0)
local ops = {TokenTypes.AND, TokenTypes.OR}
if not self:contains(ops, op) then
left = convert(left)
right = convert(right)
if op == TokenTypes.EEQ then
resultNode.value = left == right
elseif op == TokenTypes.NQ then
resultNode.value = left ~= right
elseif op == TokenTypes.LT then
resultNode.value = left < right
elseif op == TokenTypes.LTE then
resultNode.value = left <= right
elseif op == TokenTypes.GT then
resultNode.value = left > right
elseif op == TokenTypes.GTE then
resultNode.value = left >= right
else
error("InvalidConditionOperatorError: " .. op .. ", line " .. self.current_line)
end
else
if left.type ~= NodeTypes.BooleanNode or right.type ~= NodeTypes.BooleanNode then
error("InvalidConditionOperatorError: " .. op .. ", line " .. self.current_line)
end
left = left.value
right = right.value
if op == TokenTypes.AND then
resultNode.value = left and right
else
resultNode.value = left or right
end
end
return resultNode
end
return Interpreter