Skip to content

Commit 2da7088

Browse files
committed
More folding and tests.
1 parent d79c278 commit 2da7088

File tree

2 files changed

+160
-12
lines changed

2 files changed

+160
-12
lines changed

dumbParser.lua

Lines changed: 104 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4014,7 +4014,7 @@ end
40144014
local function isValueNumberOrString(v)
40154015
return type(v) == "number" or type(v) == "string"
40164016
end
4017-
local function isValueFiniteNumber(v)
4017+
local function isValueFiniteNumber(v) -- Should we actually use the logic of isValueNumberLike() where this function is used? @Incomplete
40184018
return type(v) == "number" and v == v and v ~= 1/0 and v ~= -1/0
40194019
end
40204020
local function isValueNumberLike(v)
@@ -4030,78 +4030,129 @@ local bits2 = {}
40304030

40314031
local unaryFolders = {
40324032
["-"] = function(unary, expr)
4033+
-- -numberLike -> number
40334034
if expr.type == "literal" and isValueNumberLike(expr.value) then
4034-
return AstLiteral(unary.token, -expr.value)
4035+
return AstLiteral(unary.token, -expr.value) -- This may convert a string to a number.
40354036
end
4037+
40364038
return nil
40374039
end,
4040+
40384041
["not"] = function(unary, expr)
4039-
-- @Incomplete: Fold 'not (expr1 ~= expr2)' into 'expr1 == expr2'.
4040-
if expr.type == "literal" then
4042+
-- not literal -> boolean
4043+
if expr.type == "literal" then -- :SimplifyTruthfulValues
40414044
return AstLiteral(unary.token, (not expr.value))
4045+
4046+
-- not (x == y) -> x ~= y
4047+
-- not (x ~= y) -> x == y
4048+
elseif expr.type == "binary" then
4049+
if expr.operator == "==" then
4050+
local binary = AstBinary(unary.token, "~=")
4051+
binary.left = expr.left
4052+
binary.right = expr.right
4053+
return binary
4054+
elseif expr.operator == "~=" then
4055+
local binary = AstBinary(unary.token, "==")
4056+
binary.left = expr.left
4057+
binary.right = expr.right
4058+
return binary
4059+
end
40424060
end
4061+
40434062
return nil
40444063
end,
4064+
40454065
["#"] = function(unary, expr)
4046-
-- I don't think there's ever anything to do here.
4066+
-- #string -> number
4067+
if expr.type == "literal" and type(expr.value) == "string" then
4068+
return AstLiteral(unary.token, #expr.value)
4069+
end
4070+
4071+
-- We could get the length of tables containing only constants, but who in their right mind writes #{}?
4072+
40474073
return nil
40484074
end,
4075+
40494076
["~"] = function(unary, expr)
4077+
-- ~number -> number
40504078
if expr.type == "literal" and isValueFiniteNumber(expr.value) then
40514079
intToBits(expr.value, bits1)
40524080
for i = 1, INT_SIZE do
40534081
bits1[i] = 1 - bits1[i]
40544082
end
40554083
return AstLiteral(unary.token, bitsToInt(bits1))
40564084
end
4085+
40574086
return nil
40584087
end,
40594088
}
40604089

40614090
local binaryFolders = {
40624091
["+"] = function(binary, l, r)
4092+
-- numberLike + numberLike -> number
40634093
if l.type == "literal" and r.type == "literal" and isValueNumberLike(l.value) and isValueNumberLike(r.value) then
40644094
return AstLiteral(binary.token, l.value+r.value)
40654095
end
4096+
40664097
return nil
40674098
end,
4099+
40684100
["-"] = function(binary, l, r)
4101+
-- numberLike - numberLike -> number
40694102
if l.type == "literal" and r.type == "literal" and isValueNumberLike(l.value) and isValueNumberLike(r.value) then
40704103
return AstLiteral(binary.token, l.value-r.value)
40714104
end
4105+
40724106
return nil
40734107
end,
4108+
40744109
["*"] = function(binary, l, r)
4110+
-- numberLike * numberLike -> number
40754111
if l.type == "literal" and r.type == "literal" and isValueNumberLike(l.value) and isValueNumberLike(r.value) then
40764112
return AstLiteral(binary.token, l.value*r.value)
40774113
end
4114+
40784115
return nil
40794116
end,
4117+
40804118
["/"] = function(binary, l, r)
4119+
-- numberLike / numberLike -> number
40814120
if l.type == "literal" and r.type == "literal" and isValueNumberLike(l.value) and isValueNumberLike(r.value) then
40824121
return AstLiteral(binary.token, l.value/r.value)
40834122
end
4123+
40844124
return nil
40854125
end,
4126+
40864127
["//"] = function(binary, l, r)
4128+
-- numberLike // numberLike -> number
40874129
if l.type == "literal" and r.type == "literal" and isValueNumberLike(l.value) and isValueNumberLike(r.value) then
40884130
return AstLiteral(binary.token, mathFloor(l.value/r.value))
40894131
end
4132+
40904133
return nil
40914134
end,
4135+
40924136
["^"] = function(binary, l, r)
4137+
-- numberLike ^ numberLike -> number
40934138
if l.type == "literal" and r.type == "literal" and isValueNumberLike(l.value) and isValueNumberLike(r.value) then
40944139
return AstLiteral(binary.token, l.value^r.value)
40954140
end
4141+
40964142
return nil
40974143
end,
4144+
40984145
["%"] = function(binary, l, r)
4146+
-- numberLike % numberLike -> number
40994147
if l.type == "literal" and r.type == "literal" and isValueNumberLike(l.value) and isValueNumberLike(r.value) then
41004148
return AstLiteral(binary.token, l.value%r.value)
41014149
end
4150+
41024151
return nil
41034152
end,
4153+
41044154
["&"] = function(binary, l, r)
4155+
-- number & number -> number
41054156
if l.type == "literal" and r.type == "literal" and isValueFiniteNumber(l.value) and isValueFiniteNumber(r.value) then
41064157
intToBits(l.value, bits1)
41074158
intToBits(r.value, bits2)
@@ -4110,9 +4161,12 @@ local binaryFolders = {
41104161
end
41114162
return AstLiteral(binary.token, bitsToInt(bits1))
41124163
end
4164+
41134165
return nil
41144166
end,
4167+
41154168
["~"] = function(binary, l, r)
4169+
-- number ~ number -> number
41164170
if l.type == "literal" and r.type == "literal" and isValueFiniteNumber(l.value) and isValueFiniteNumber(r.value) then
41174171
intToBits(l.value, bits1)
41184172
intToBits(r.value, bits2)
@@ -4121,9 +4175,12 @@ local binaryFolders = {
41214175
end
41224176
return AstLiteral(binary.token, bitsToInt(bits1))
41234177
end
4178+
41244179
return nil
41254180
end,
4181+
41264182
["|"] = function(binary, l, r)
4183+
-- number | number -> number
41274184
if l.type == "literal" and r.type == "literal" and isValueFiniteNumber(l.value) and isValueFiniteNumber(r.value) then
41284185
intToBits(l.value, bits1)
41294186
intToBits(r.value, bits2)
@@ -4132,9 +4189,12 @@ local binaryFolders = {
41324189
end
41334190
return AstLiteral(binary.token, bitsToInt(bits1))
41344191
end
4192+
41354193
return nil
41364194
end,
4195+
41374196
[">>"] = function(binary, l, r)
4197+
-- number >> number -> number
41384198
if l.type == "literal" and r.type == "literal" and isValueFiniteNumber(l.value) and type(r.value) == "number" then
41394199
intToBits(l.value, bits1)
41404200

@@ -4157,7 +4217,9 @@ local binaryFolders = {
41574217

41584218
return nil
41594219
end,
4220+
41604221
["<<"] = function(binary, l, r)
4222+
-- number << number -> number
41614223
if l.type == "literal" and r.type == "literal" and isValueFiniteNumber(l.value) and type(r.value) == "number" then
41624224
intToBits(l.value, bits1)
41634225

@@ -4180,54 +4242,87 @@ local binaryFolders = {
41804242

41814243
return nil
41824244
end,
4245+
41834246
[".."] = function(binary, l, r)
4247+
-- numberOrString .. numberOrString -> string
41844248
if l.type == "literal" and r.type == "literal" and isValueNumberOrString(l.value) and isValueNumberOrString(r.value) then
41854249
return AstLiteral(binary.token, l.value..r.value)
41864250
end
4251+
41874252
return nil
41884253
end,
4254+
41894255
["<"] = function(binary, l, r)
4256+
-- number < number -> boolean
4257+
-- string < string -> boolean
41904258
if l.type == "literal" and r.type == "literal" and areValuesNumbersOrStringsAndOfSameType(l.value, r.value) then
41914259
return AstLiteral(binary.token, (l.value < r.value))
41924260
end
4261+
41934262
return nil
41944263
end,
4264+
41954265
["<="] = function(binary, l, r)
4266+
-- number <= number -> boolean
4267+
-- string <= string -> boolean
41964268
if l.type == "literal" and r.type == "literal" and areValuesNumbersOrStringsAndOfSameType(l.value, r.value) then
41974269
return AstLiteral(binary.token, (l.value <= r.value))
41984270
end
4271+
41994272
return nil
42004273
end,
4274+
42014275
[">"] = function(binary, l, r)
4276+
-- number > number -> boolean
4277+
-- string > string -> boolean
42024278
if l.type == "literal" and r.type == "literal" and areValuesNumbersOrStringsAndOfSameType(l.value, r.value) then
42034279
return AstLiteral(binary.token, (l.value > r.value))
42044280
end
4281+
42054282
return nil
42064283
end,
4284+
42074285
[">="] = function(binary, l, r)
4286+
-- number >= number -> boolean
4287+
-- string >= string -> boolean
42084288
if l.type == "literal" and r.type == "literal" and areValuesNumbersOrStringsAndOfSameType(l.value, r.value) then
42094289
return AstLiteral(binary.token, (l.value >= r.value))
42104290
end
4291+
42114292
return nil
42124293
end,
4294+
42134295
["=="] = function(binary, l, r)
4296+
-- literal == literal -> boolean
42144297
if l.type == "literal" and r.type == "literal" then
42154298
return AstLiteral(binary.token, (l.value == r.value))
42164299
end
4300+
42174301
return nil
42184302
end,
4303+
42194304
["~="] = function(binary, l, r)
4305+
-- literal ~= literal -> boolean
42204306
if l.type == "literal" and r.type == "literal" then
42214307
return AstLiteral(binary.token, (l.value ~= r.value))
42224308
end
4309+
42234310
return nil
42244311
end,
4312+
42254313
["and"] = function(binary, l, r)
4314+
-- truthfulLiteral and x -> x
4315+
-- untruthfulLiteral and x -> untruthfulLiteral
42264316
if l.type == "literal" then return l.value and r or l end
4317+
42274318
return nil
42284319
end,
4320+
42294321
["or"] = function(binary, l, r)
4322+
-- truthfulLiteral or x -> untruthfulLiteral
4323+
-- untruthfulLiteral or x -> x
42304324
if l.type == "literal" then return l.value and l or r end
4325+
42314326
return nil
42324327
end,
42334328
}
@@ -4246,12 +4341,12 @@ local function simplifyNode(node, parent, container, key)
42464341
if replacement then replace(node, replacement, parent, container, key, statsForSimplify) end
42474342

42484343
elseif node.type == "binary" then
4249-
-- @Incomplete: Fold 'expr - -n' into 'expr + n' etc.
4344+
-- @Incomplete: Fold 'expr - -n' into 'expr + n' etc. (Actually, this will probably mess up metamethods.)
42504345
local replacement = binaryFolders[node.operator](node, node.left, node.right)
42514346
if replacement then replace(node, replacement, parent, container, key, statsForSimplify) end
42524347

42534348
elseif node.type == "if" then
4254-
-- @Incomplete: Fold 'if not not expr' into 'if expr'. (Also for 'while' and 'repeat'.)
4349+
-- @Incomplete: Fold 'if not not expr' into 'if expr'. (Also for 'while' and 'repeat' etc., i.e. all conditional expressions.)
42554350
local ifNode = node
42564351

42574352
if ifNode.condition.type == "literal" then -- @Incomplete: There are more values that make simplification possible (e.g. functions, but who would put that here anyway). :SimplifyTruthfulValues
@@ -4272,7 +4367,7 @@ local function simplifyNode(node, parent, container, key)
42724367

42734368
if whileLoop.condition.type == "literal" then -- :SimplifyTruthfulValues
42744369
if whileLoop.condition.value then
4275-
whileLoop.condition.value = true
4370+
whileLoop.condition.value = true -- Convert literal's value to boolean.
42764371
else
42774372
tableRemove(container, key)
42784373
tableInsert(statsForSimplify.nodeRemovals, Location(whileLoop))
@@ -4288,7 +4383,7 @@ local function simplifyNode(node, parent, container, key)
42884383
replace(repeatLoop, repeatLoop.body, parent, container, key, statsForSimplify)
42894384
return simplifyNode(repeatLoop.body, parent, container, key)
42904385
else
4291-
repeatLoop.condition.value = false
4386+
repeatLoop.condition.value = false -- Convert literal's value to boolean.
42924387
end
42934388
end
42944389

0 commit comments

Comments
 (0)