-
Notifications
You must be signed in to change notification settings - Fork 0
/
frontend_example.ml
218 lines (201 loc) · 7.23 KB
/
frontend_example.ml
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
open Compiler_lib
module StringMap = Interpreter.StringMap
module HeapIdMap = Interpreter.HeapIdMap
module HeapIdSet = Inspect.HeapIdSet
let suffix_code =
String.trim
{|
-- TODO double check that the order is: init, update, draw, update, draw, ...
_init()
__reset_button_states()
|}
let frame_code = String.trim {|
_update()
_draw()
__reset_button_states()
|}
let print_lua_perf_counters fixed_env =
let named_counters =
fixed_env.Interpreter.fun_defs |> Hashtbl.to_seq
|> Seq.map (fun (name, (_, cfg)) -> (name, !(cfg.Interpreter.counter_ref)))
|> List.of_seq
in
Perf.print_named_counters named_counters
let make_heap_value_abstract_by_mark :
(Interpreter.heap_value -> Interpreter.heap_value) StringMap.t =
let funcs =
[
( "player_rem_xy",
let half = Pico_number.of_string "0.5" in
assert (Pico_number.add half half = Pico_number.of_int 1);
let neg_half = Pico_number.neg half in
let wide =
Pico_number_interval.of_numbers neg_half (Pico_number.below half)
in
let f_scalar = function
| Interpreter.SNumber v ->
assert (Pico_number_interval.contains_number wide v);
Interpreter.SNumberInterval wide
| Interpreter.SNumberInterval v ->
assert (Pico_number_interval.contains_interval wide v);
Interpreter.SNumberInterval wide
| _ -> assert false
in
function
| Interpreter.Scalar v -> Interpreter.Scalar (f_scalar v)
| Interpreter.Vector vec -> Interpreter.map_vector f_scalar vec );
]
in
let lift f = function
| Interpreter.HValue v -> Interpreter.HValue (f v)
| v -> v
in
funcs |> List.to_seq
|> Seq.map (fun (k, v) -> (k, lift v))
|> StringMap.of_seq
let make_state_abstract (state : Interpreter.state) : Interpreter.state =
let marks = Inspect.mark_heap state in
let make_heap_value_abstract_by_heap_id =
marks |> StringMap.to_seq
|> Seq.filter_map (fun (mark, heap_ids) ->
match StringMap.find_opt mark make_heap_value_abstract_by_mark with
| Some f ->
Some
(heap_ids |> HeapIdSet.to_seq
|> Seq.map (fun heap_id -> (heap_id, f)))
| None -> None)
|> Seq.concat |> HeapIdMap.of_seq
in
{
state with
Interpreter.heap =
state.Interpreter.heap |> Interpreter.Heap.seq_of_old
|> Seq.map (fun (heap_id, v) ->
match
HeapIdMap.find_opt heap_id make_heap_value_abstract_by_heap_id
with
| Some f -> (heap_id, f v)
| None -> (heap_id, v))
|> Interpreter.Heap.old_of_seq;
}
let run_step cfg states fixed_env =
Perf.reset_counters ();
let states =
states |> Interpreter.LazyStateSet.to_non_normalized_non_deduped_seq
|> Seq.mapi (fun i state -> (i, state))
|> Seq.concat_map (fun (i, state) ->
Printf.printf "Processing state %d with vector size %d\n%!" i
state.Interpreter.vector_size;
let states_and_maybe_returns =
Interpreter.interpret_cfg
(Interpreter.LazyStateSet.of_list [ state ])
cfg
in
match states_and_maybe_returns with
| Interpreter.StateAndMaybeReturnSet.StateSet states ->
states
|> Interpreter.LazyStateSet.to_non_normalized_non_deduped_seq
| Interpreter.StateAndMaybeReturnSet.StateAndReturnSet _ ->
failwith "Unexpected return value")
|> List.of_seq
in
Perf.print_counters ();
print_lua_perf_counters fixed_env;
states |> Interpreter.LazyStateSet.of_list
|> Interpreter.LazyStateSet.to_normalized_non_deduped_seq
|> Seq.map make_state_abstract
|> List.of_seq |> Interpreter.LazyStateSet.of_list
|> Interpreter.vectorize_states
let print_state_summary state =
let summary = Inspect.make_state_summary state in
Printf.printf "%s\n" @@ Inspect.show_state_summary summary
let print_step states =
(let states = Interpreter.LazyStateSet.normalize states in
Printf.printf "Got %d states (%d if expanding vectors) after execution\n"
(states |> Interpreter.LazyStateSet.to_normalized_state_set
|> Interpreter.StateSet.cardinal)
(states |> Interpreter.LazyStateSet.to_non_normalized_non_deduped_seq
|> Seq.fold_left (fun acc s -> acc + s.Interpreter.vector_size) 0));
states |> Interpreter.LazyStateSet.to_normalized_state_set
|> Interpreter.StateSet.to_seq
|> Seq.concat_map Interpreter.unvectorize_state
|> Seq.map Inspect.make_state_summary
|> Seq.fold_left
(fun m s ->
let old_count =
m |> Inspect.StateSummaryMap.find_opt s |> Option.value ~default:0
in
Inspect.StateSummaryMap.add s (old_count + 1) m)
Inspect.StateSummaryMap.empty
|> Inspect.StateSummaryMap.to_seq |> Seq.take 3
|> Seq.iter (fun (state_summary, count) ->
Printf.printf "%d %s\n" count
@@ Inspect.show_state_summary state_summary);
Printf.printf "\n%!"
let write_debug_image (i_frame : int) (states : Interpreter.LazyStateSet.t) =
let min_coord = -32 in
let max_coord = 144 in
let img_size = max_coord - min_coord in
let coord_to_pixel_index v =
let i = v - min_coord in
assert (i >= 0 && i < img_size);
i
in
let img = Rgb24.create img_size img_size in
for x = 0 to img_size - 1 do
for y = 0 to img_size - 1 do
Rgb24.set img x y { r = 0; g = 0; b = 0 }
done
done;
states |> Interpreter.LazyStateSet.to_non_normalized_non_deduped_seq
|> Seq.concat_map Interpreter.unvectorize_state
|> Seq.iter (fun state ->
let summary = Inspect.make_state_summary state in
match summary.player with
| Some { x; y } ->
let x = coord_to_pixel_index @@ Pico_number.int_of x in
let y = coord_to_pixel_index @@ Pico_number.int_of y in
Rgb24.set img x y { r = 255; g = 255; b = 255 }
| None -> ());
Bmp.save
(Printf.sprintf "output/frame_%04d.bmp" i_frame)
[] (Images.Rgb24 img)
let () =
let lua_code = BatFile.with_file_in "celeste-minimal.lua" BatIO.read_all in
let ast =
Lua_parser.Parse.parse_from_string
@@ String.concat "\n"
[
BatFile.with_file_in "builtin_level_3.lua" BatIO.read_all;
BatFile.with_file_in "builtin_level_4.lua" BatIO.read_all;
lua_code;
suffix_code;
"\n";
]
in
let cfg, fun_defs = Frontend.compile ast in
let cfg, fixed_env_ref, initial_state =
Interpreter.init cfg fun_defs
@@ List.concat
[
Builtin.level_1_builtins;
Builtin.level_2_builtins;
Builtin.load_level_5_builtins ();
]
in
let frame_ast =
Lua_parser.Parse.parse_from_string
@@ String.concat "\n" [ frame_code; "\n" ]
in
let frame_cfg, frame_fun_defs = Frontend.compile frame_ast in
assert (frame_fun_defs = []);
let frame_cfg = Interpreter.prepare_cfg frame_cfg fixed_env_ref in
let states = ref @@ Interpreter.LazyStateSet.of_list [ initial_state ] in
states := run_step cfg !states !fixed_env_ref;
print_step !states;
for i = 1 to 100 do
Printf.printf "Frame %d\n%!" i;
states := run_step frame_cfg !states !fixed_env_ref;
print_step !states;
write_debug_image i !states
done