-
-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathreplace.lua
More file actions
93 lines (85 loc) · 2.58 KB
/
replace.lua
File metadata and controls
93 lines (85 loc) · 2.58 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
--[[
expr = expression to change
find = sub-expression to find
repl = sub-expression to replace
cond(node) = condition per node, returns 'true' if we don't want to find/replace this tree
TODO rewrite to use symmath.map() ?
TODO rewrite to use symmath.match() ? But match() returns matched objects ... I don't think it returns indexes/paths into expression trees to look them up (for the sake of replacing them)
--]]
local function replaceRecurse(expr, find, repl, cond)
local Constant = require 'symmath.Constant'
if Constant.isNumber(find) then
find = Constant(find)
end
if repl == nil then
error("expected to have something to replace, got nil")
elseif Constant.isNumber(repl) then
repl = Constant(repl)
end
-- cond returns true to short circuit search
if cond and cond(expr) then return end
local modified
-- [[ TODO (a + a + b + b):replace(a + b, x) will fail
local replacedAll, replacedIndex
-- here I need to not just test equality, but also portions of equality
-- esp for commutative equals operators
if expr.removeIfContains then
local status, removed = expr:removeIfContains(find)
-- "removed" was originally most likely a BinOp
-- but its children have been removed
-- therefore it could reach an invalid state of having 0 or 1 children
if status then
--DEBUG(@5):print("# children left", #removed, '<br>')
-- bit of a hack
local BinaryOp = require 'symmath.op.Binary'
if BinaryOp:isa(removed) then
if #removed == 0 then
expr = repl
replacedAll = true
else
expr = removed
table.insert(expr, repl)
replacedIndex = #expr
end
end
modified = true
end
--DEBUG(@5):print("expr is now",expr,'<br>')
end
if replacedAll then return expr end
--]]
-- found find then replace
if expr == find then return repl end
-- recursive call
local clone = require 'symmath.clone'
for i=1,#expr do
if expr[i] == nil then
print('this had a nil: '..require 'ext.tolua'(expr))
print('when replacing '..tostring(find))
print(' with '..tostring(repl))
error'here'
end
-- don't recursively apply our replace() to the replaced result
if i ~= replacedIndex then
local replexpri = replaceRecurse(expr[i], find, repl, cond)
if replexpri then
if not modified then -- clone before modifying children
expr = clone(expr)
modified = true
end
expr[i] = replexpri
end
end
end
if modified then
return expr
end
end
local function replace(expr, ...)
assert(expr)
local result = replaceRecurse(expr, ...)
if not result then return expr end
result = result:flatten() or result
return result
end
return replace