7
7
#include "variable.h"
8
8
#include "context.h"
9
9
#include "parse_context.h"
10
+ #include "serialize_parse_context.h"
10
11
#include "vm_assembler.h"
11
12
#include "tag_markup.h"
12
13
#include <stdio.h>
@@ -44,6 +45,9 @@ static void block_body_mark(void *ptr)
44
45
if (body -> compiled ) {
45
46
document_body_entry_mark (& body -> as .compiled .document_body_entry );
46
47
rb_gc_mark (body -> as .compiled .nodelist );
48
+ } else if (body -> from_serialize ) {
49
+ document_body_entry_mark (& body -> as .serialize .document_body_entry );
50
+ rb_gc_mark (body -> as .serialize .parse_context );
47
51
} else {
48
52
rb_gc_mark (body -> as .intermediate .parse_context );
49
53
if (body -> as .intermediate .vm_assembler_pool )
@@ -56,7 +60,7 @@ static void block_body_mark(void *ptr)
56
60
static void block_body_free (void * ptr )
57
61
{
58
62
block_body_t * body = ptr ;
59
- if (!body -> compiled ) {
63
+ if (!body -> compiled && ! body -> from_serialize ) {
60
64
// Free the assembler instead of recycling it because the vm_assembler_pool may have been GC'd
61
65
vm_assembler_pool_free_assembler (body -> as .intermediate .code );
62
66
}
@@ -67,7 +71,7 @@ static size_t block_body_memsize(const void *ptr)
67
71
{
68
72
const block_body_t * body = ptr ;
69
73
if (!ptr ) return 0 ;
70
- if (body -> compiled ) {
74
+ if (body -> compiled || body -> from_serialize ) {
71
75
return sizeof (block_body_t );
72
76
} else {
73
77
return sizeof (block_body_t ) + vm_assembler_alloc_memsize (body -> as .intermediate .code );
@@ -88,6 +92,7 @@ static VALUE block_body_allocate(VALUE klass)
88
92
VALUE obj = TypedData_Make_Struct (klass , block_body_t , & block_body_data_type , body );
89
93
90
94
body -> compiled = false;
95
+ body -> from_serialize = false;
91
96
body -> obj = obj ;
92
97
body -> tags = c_buffer_init ();
93
98
body -> as .intermediate .blank = true;
@@ -103,18 +108,24 @@ static VALUE block_body_initialize(VALUE self, VALUE parse_context)
103
108
block_body_t * body ;
104
109
BlockBody_Get_Struct (self , body );
105
110
106
- body -> as . intermediate . parse_context = parse_context ;
107
-
108
- if ( parse_context_document_body_initialized_p ( parse_context )) {
109
- body -> as .intermediate . vm_assembler_pool = parse_context_get_vm_assembler_pool ( parse_context ) ;
111
+ if ( is_serialize_parse_context_p ( parse_context )) {
112
+ body -> from_serialize = true;
113
+ body -> as . serialize . document_body_entry = document_body_entry_init ();
114
+ body -> as .serialize . parse_context = parse_context ;
110
115
} else {
111
- parse_context_init_document_body (parse_context );
112
- body -> as .intermediate .root = true;
113
- body -> as .intermediate .vm_assembler_pool = parse_context_init_vm_assembler_pool (parse_context );
114
- }
116
+ body -> as .intermediate .parse_context = parse_context ;
117
+
118
+ if (parse_context_document_body_initialized_p (parse_context )) {
119
+ body -> as .intermediate .vm_assembler_pool = parse_context_get_vm_assembler_pool (parse_context );
120
+ } else {
121
+ parse_context_init_document_body (parse_context );
122
+ body -> as .intermediate .root = true;
123
+ body -> as .intermediate .vm_assembler_pool = parse_context_init_vm_assembler_pool (parse_context );
124
+ }
115
125
116
- body -> as .intermediate .code = vm_assembler_pool_alloc_assembler (body -> as .intermediate .vm_assembler_pool );
117
- vm_assembler_add_leave (body -> as .intermediate .code );
126
+ body -> as .intermediate .code = vm_assembler_pool_alloc_assembler (body -> as .intermediate .vm_assembler_pool );
127
+ vm_assembler_add_leave (body -> as .intermediate .code );
128
+ }
118
129
119
130
return Qnil ;
120
131
}
@@ -138,6 +149,22 @@ static void block_body_push_tag_markup(block_body_t *body, VALUE parse_context,
138
149
parse_context_set_parent_tag (parse_context , tag_markup );
139
150
}
140
151
152
+ static void ensure_intermediate (block_body_t * body )
153
+ {
154
+ if (body -> compiled ) {
155
+ rb_raise (rb_eRuntimeError , "Liquid::C::BlockBody is already compiled" );
156
+ }
157
+ }
158
+
159
+ static void ensure_intermediate_not_parsing (block_body_t * body )
160
+ {
161
+ ensure_intermediate (body );
162
+
163
+ if (body -> as .intermediate .code -> parsing ) {
164
+ rb_raise (rb_eRuntimeError , "Liquid::C::BlockBody is in a incompletely parsed state" );
165
+ }
166
+ }
167
+
141
168
static VALUE internal_block_body_parse (block_body_t * body , parse_context_t * parse_context )
142
169
{
143
170
tokenizer_t * tokenizer = parse_context -> tokenizer ;
@@ -257,7 +284,7 @@ static VALUE internal_block_body_parse(block_body_t *body, parse_context_t *pars
257
284
}
258
285
259
286
VALUE tag_markup = tag_markup_new (tag_name , markup , false);
260
- block_body_push_tag_markup ( body , parse_context -> ruby_obj , tag_markup );
287
+ parse_context_set_parent_tag ( parse_context -> ruby_obj , tag_markup );
261
288
262
289
VALUE new_tag = rb_funcall (tag_class , intern_parse , 4 ,
263
290
tag_name , markup , parse_context -> tokenizer_obj , parse_context -> ruby_obj );
@@ -270,11 +297,12 @@ static VALUE internal_block_body_parse(block_body_t *body, parse_context_t *pars
270
297
if (tokenizer -> raw_tag_body ) {
271
298
if (tokenizer -> raw_tag_body_len ) {
272
299
vm_assembler_add_write_raw (body -> as .intermediate .code , tokenizer -> raw_tag_body ,
273
- tokenizer -> raw_tag_body_len );
300
+ tokenizer -> raw_tag_body_len );
274
301
}
275
302
tokenizer -> raw_tag_body = NULL ;
276
303
tokenizer -> raw_tag_body_len = 0 ;
277
304
} else {
305
+ vm_assembler_write_tag (body -> as .intermediate .code , tag_markup );
278
306
block_body_add_node (body , new_tag );
279
307
}
280
308
@@ -290,32 +318,87 @@ static VALUE internal_block_body_parse(block_body_t *body, parse_context_t *pars
290
318
return unknown_tag ;
291
319
}
292
320
293
- static void ensure_intermediate (block_body_t * body )
321
+ typedef struct block_body_yield_tag_args {
322
+ block_body_t * body ;
323
+ serialize_parse_context_t * serialize_context ;
324
+ tag_markup_header_t * current_tag ;
325
+ } block_body_yield_tag_args_t ;
326
+
327
+ static VALUE block_body_try_yield_tag (VALUE uncast_args )
294
328
{
295
- if (body -> compiled ) {
296
- rb_raise (rb_eRuntimeError , "Liquid::C::BlockBody is already compiled" );
297
- }
329
+ block_body_yield_tag_args_t * args = (block_body_yield_tag_args_t * )uncast_args ;
330
+ tag_markup_header_t * current_tag = args -> current_tag ;
331
+
332
+ serialize_parse_context_enter_tag (args -> serialize_context , current_tag );
333
+ VALUE tag_name = rb_utf8_str_new (tag_markup_header_name (current_tag ), current_tag -> tag_name_len );
334
+ VALUE markup = rb_utf8_str_new (tag_markup_header_markup (current_tag ), current_tag -> markup_len );
335
+ return rb_yield_values (2 , tag_name , markup );
298
336
}
299
337
300
- static void ensure_intermediate_not_parsing ( block_body_t * body )
338
+ static VALUE block_body_rescue_yield_tag ( VALUE uncast_args , VALUE exception )
301
339
{
340
+ block_body_yield_tag_args_t * args = (block_body_yield_tag_args_t * )uncast_args ;
341
+
342
+ serialize_parse_context_exit_tag (args -> serialize_context , & args -> body -> as .serialize .document_body_entry ,
343
+ args -> current_tag );
344
+ rb_exc_raise (exception );
345
+ }
346
+
347
+ static VALUE block_body_parse_from_serialize (block_body_t * body , VALUE tokenizer_obj , VALUE parse_context_obj )
348
+ {
349
+ assert (body -> from_serialize );
350
+ assert (is_serialize_parse_context_p (parse_context_obj ));
351
+
302
352
ensure_intermediate (body );
353
+ if (body -> as .serialize .parse_context != parse_context_obj ) {
354
+ rb_raise (rb_eArgError , "Liquid::C::BlockBody#parse called with different parse context" );
355
+ }
303
356
304
- if (body -> as .intermediate .code -> parsing ) {
305
- rb_raise (rb_eRuntimeError , "Liquid::C::BlockBody is in a incompletely parsed state" );
357
+ serialize_parse_context_t * serialize_context ;
358
+ SerializeParseContext_Get_Struct (parse_context_obj , serialize_context );
359
+
360
+ body -> as .serialize .document_body_entry = serialize_context -> current_entry ;
361
+
362
+ tag_markup_header_t * current_tag = serialize_context -> current_tag ;
363
+ while (current_tag ) {
364
+ bool tag_unknown = TAG_UNKNOWN_P (current_tag );
365
+
366
+ if (tag_unknown ) {
367
+ block_body_yield_tag_args_t yield_args = {
368
+ .body = body ,
369
+ .serialize_context = serialize_context ,
370
+ .current_tag = current_tag
371
+ };
372
+ return rb_rescue (block_body_try_yield_tag , (VALUE )& yield_args , block_body_rescue_yield_tag , (VALUE )& yield_args );
373
+ } else {
374
+ VALUE tag_name = rb_utf8_str_new (tag_markup_header_name (current_tag ), current_tag -> tag_name_len );
375
+ VALUE markup = rb_utf8_str_new (tag_markup_header_markup (current_tag ), current_tag -> markup_len );
376
+
377
+ VALUE tag_class = rb_funcall (tag_registry , intern_square_brackets , 1 , tag_name );
378
+ assert (RTEST (tag_class ));
379
+
380
+ serialize_parse_context_enter_tag (serialize_context , current_tag );
381
+ VALUE new_tag = rb_funcall (tag_class , intern_parse , 4 ,
382
+ tag_name , markup , tokenizer_obj , parse_context_obj );
383
+ serialize_parse_context_exit_tag (serialize_context , & body -> as .serialize .document_body_entry , current_tag );
384
+
385
+ c_buffer_write_ruby_value (& body -> tags , new_tag );
386
+ }
387
+
388
+ current_tag = tag_markup_get_next_tag (& body -> as .serialize .document_body_entry , current_tag );
306
389
}
390
+
391
+ return rb_yield_values (2 , Qnil , Qnil );
307
392
}
308
393
309
- static VALUE block_body_parse (VALUE self , VALUE tokenizer_obj , VALUE parse_context_obj )
394
+ static VALUE block_body_parse_from_source (VALUE self , block_body_t * body , VALUE tokenizer_obj , VALUE parse_context_obj )
310
395
{
311
396
parse_context_t parse_context = {
312
397
.parent_tag = parse_context_get_parent_tag (parse_context_obj ),
313
398
.tokenizer_obj = tokenizer_obj ,
314
399
.ruby_obj = parse_context_obj ,
315
400
};
316
401
Tokenizer_Get_Struct (tokenizer_obj , parse_context .tokenizer );
317
- block_body_t * body ;
318
- BlockBody_Get_Struct (self , body );
319
402
320
403
ensure_intermediate_not_parsing (body );
321
404
if (body -> as .intermediate .parse_context != parse_context_obj ) {
@@ -332,17 +415,29 @@ static VALUE block_body_parse(VALUE self, VALUE tokenizer_obj, VALUE parse_conte
332
415
tag_name = tag_markup_get_tag_name (unknown_tag );
333
416
markup = tag_markup_get_markup (unknown_tag );
334
417
block_body_push_tag_markup (body , parse_context_obj , unknown_tag );
418
+
419
+ if (RTEST (parse_context .parent_tag )) {
420
+ tag_markup_set_block_body (parse_context .parent_tag , self , body );
421
+ }
335
422
}
336
423
337
424
VALUE block_ret = rb_yield_values (2 , tag_name , markup );
338
425
339
- if (RTEST (parse_context .parent_tag )) {
340
- tag_markup_set_block_body (parse_context .parent_tag , self , body );
341
- }
342
-
343
426
return block_ret ;
344
427
}
345
428
429
+ static VALUE block_body_parse (VALUE self , VALUE tokenizer_obj , VALUE parse_context_obj )
430
+ {
431
+ block_body_t * body ;
432
+ BlockBody_Get_Struct (self , body );
433
+
434
+ if (body -> from_serialize ) {
435
+ return block_body_parse_from_serialize (body , tokenizer_obj , parse_context_obj );
436
+ } else {
437
+ return block_body_parse_from_source (self , body , tokenizer_obj , parse_context_obj );
438
+ }
439
+ }
440
+
346
441
347
442
static VALUE block_body_freeze (VALUE self )
348
443
{
@@ -351,26 +446,32 @@ static VALUE block_body_freeze(VALUE self)
351
446
352
447
if (body -> compiled ) return Qnil ;
353
448
354
- VALUE parse_context = body -> as .intermediate .parse_context ;
355
- VALUE document_body = parse_context_get_document_body (parse_context );
356
-
357
- bool root = body -> as .intermediate .root ;
358
-
359
- vm_assembler_pool_t * assembler_pool = body -> as .intermediate .vm_assembler_pool ;
360
- vm_assembler_t * assembler = body -> as .intermediate .code ;
361
- bool blank = body -> as .intermediate .blank ;
362
- uint32_t render_score = body -> as .intermediate .render_score ;
363
- vm_assembler_t * code = body -> as .intermediate .code ;
364
449
body -> compiled = true;
365
- body -> as .compiled .nodelist = Qundef ;
366
- document_body_write_block_body (document_body , blank , render_score , code , & body -> as .compiled .document_body_entry );
367
- vm_assembler_pool_recycle_assembler (assembler_pool , assembler );
368
450
369
- if (root ) {
370
- parse_context_remove_document_body (parse_context );
371
- parse_context_remove_vm_assembler_pool (parse_context );
451
+ if (body -> from_serialize ) {
452
+ body -> as .compiled .nodelist = Qundef ;
453
+ } else {
454
+ VALUE parse_context = body -> as .intermediate .parse_context ;
455
+ VALUE document_body = parse_context_get_document_body (parse_context );
456
+
457
+ bool root = body -> as .intermediate .root ;
458
+
459
+ vm_assembler_pool_t * assembler_pool = body -> as .intermediate .vm_assembler_pool ;
460
+ vm_assembler_t * assembler = body -> as .intermediate .code ;
461
+ bool blank = body -> as .intermediate .blank ;
462
+ uint32_t render_score = body -> as .intermediate .render_score ;
463
+ vm_assembler_t * code = body -> as .intermediate .code ;
464
+ body -> as .compiled .nodelist = Qundef ;
465
+ document_body_write_block_body (document_body , blank , render_score , code , & body -> as .compiled .document_body_entry );
466
+ vm_assembler_pool_recycle_assembler (assembler_pool , assembler );
467
+
468
+ if (root ) {
469
+ parse_context_remove_document_body (parse_context );
470
+ parse_context_remove_vm_assembler_pool (parse_context );
471
+ }
372
472
}
373
473
474
+
374
475
rb_call_super (0 , NULL );
375
476
376
477
return Qnil ;
@@ -408,6 +509,8 @@ static VALUE block_body_remove_blank_strings(VALUE self)
408
509
block_body_t * body ;
409
510
BlockBody_Get_Struct (self , body );
410
511
512
+ if (body -> from_serialize ) return Qnil ;
513
+
411
514
ensure_intermediate_not_parsing (body );
412
515
413
516
if (!body -> as .intermediate .blank ) {
0 commit comments