@@ -13,6 +13,11 @@ mutable struct Instruction{F} <: AbstractInstruction
1313 tape:: Tape
1414end
1515
16+ mutable struct TapeInstruction <: AbstractInstruction
17+ subtape:: Tape
18+ tape:: Tape
19+ end
20+
1621Tape () = Tape (Vector {AbstractInstruction} (), 1 , nothing )
1722Tape (owner) = Tape (Vector {AbstractInstruction} (), 1 , owner)
1823MacroTools. @forward Tape. tape Base. iterate, Base. length
@@ -21,6 +26,9 @@ const NULL_TAPE = Tape()
2126
2227function setowner! (tape:: Tape , owner)
2328 tape. owner = owner
29+ for ins in tape
30+ isa (ins, TapeInstruction) && setowner! (ins. subtape, owner)
31+ end
2432 return tape
2533end
2634
@@ -52,6 +60,12 @@ function Base.show(io::IO, instruction::Instruction)
5260 println (io, " Instruction($(fun)$(map (val, instruction. input)) , tape=$(objectid (tape)) )" )
5361end
5462
63+ function Base. show (io:: IO , ti:: TapeInstruction )
64+ subtape = ti. subtape
65+ tape = ti. tape
66+ println (io, " TapeInstruction($(subtape) ), tape=$(objectid (tape)) )" )
67+ end
68+
5569function Base. show (io:: IO , tp:: Tape )
5670 buf = IOBuffer ()
5771 print (buf, " $(length (tp)) -element Tape" )
@@ -70,10 +84,19 @@ function (instr::Instruction{F})() where F
7084 instr. output. val = output
7185end
7286
87+ function (instr:: TapeInstruction )()
88+ run (instr. subtape)
89+ end
90+
7391function increase_counter! (t:: Tape )
7492 t. counter > length (t) && return
75- # instr = t[t.counter]
76- t. counter += 1
93+ instr = t[t. counter]
94+ if isa (instr, TapeInstruction)
95+ increase_counter! (instr. subtape)
96+ else
97+ # must be a produce instruction?
98+ t. counter += 1
99+ end
77100 return t
78101end
79102
@@ -84,21 +107,62 @@ function run(tape::Tape, args...)
84107 end
85108 for instruction in tape
86109 instruction ()
87- increase_counter! ( tape)
110+ tape. counter += 1
88111 end
89112end
90113
114+ # if we should trace into a function
115+ # TODO :
116+ # overload (instr::Instruction{F})() to specify
117+ # which function to trace into
118+ function trace_into end
119+ trace_into (x) = false
120+
91121function run_and_record! (tape:: Tape , f, args... )
92122 f = val (f) # f maybe a Boxed closure
93- output = try
94- box (f (map (val, args)... ))
95- catch e
96- @warn e
97- Box {Any} (nothing )
123+ should_trace = trace_into (f)
124+ if ! should_trace
125+ output = try
126+ box (f (map (val, args)... ))
127+ catch e
128+ @warn e
129+ Box {Any} (nothing )
130+ end
131+ ins = Instruction (f, args, output, tape)
132+ push! (tape, ins)
133+ return output
134+ else
135+ real_args = map (val, args)
136+ ir = IRTools. @code_ir f (real_args... )
137+ ir = intercept (ir; recorder= :run_and_record! )
138+ # 1. we should distinguish fixed args and varargs here
139+ arg_len = ir |> IRTools. arguments |> length
140+ arg_len -= 2 # 1 for f, 1 for vargs
141+ p_args = real_args[1 : arg_len]
142+ v_args = arg_len < 1 ? real_args : real_args[arg_len+ 1 : end ]
143+ # detect if there is an vararg for f
144+ if length (v_args) == 1
145+ m = which (f, typeof (real_args))
146+ no_vararg = @static if VERSION >= v " 1.7"
147+ (m. sig <: Tuple ) && hasproperty (m. sig, :types ) &&
148+ ! isa (m. sig. types[end ], Core. TypeofVararg)
149+ else
150+ (m. sig <: Tuple ) && hasproperty (m. sig, :types ) &&
151+ ! (m. sig. types[end ] <: Vararg{Any} )
152+ end
153+ if no_vararg
154+ v_args = v_args[1 ]
155+ end
156+ end
157+ subtape = IRTools. evalir (ir, f, p_args... , v_args)
158+ # 2. we should recover the args after getting the tape
159+ # to keep the chain complete
160+ subtape[1 ]. input = args
161+ ins = TapeInstruction (subtape, tape)
162+ output = subtape[end ]. output
163+ push! (tape, ins)
164+ return output
98165 end
99- ins = Instruction (f, args, output, tape)
100- push! (tape, ins)
101- return output
102166end
103167
104168function unbox_condition (ir)
0 commit comments