stash 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/stash/build.c +267 -0
- data/ext/stash/execute.c +248 -0
- data/ext/stash/extconf.rb +3 -0
- data/ext/stash/intern.h +79 -0
- data/ext/stash/lex.yy.c +2143 -0
- data/ext/stash/lex.yy.h +333 -0
- data/ext/stash/mustache.c +50 -0
- data/ext/stash/mustache.h +124 -0
- data/ext/stash/optimize.c +208 -0
- data/ext/stash/stash.c +177 -0
- data/ext/stash/stash.h +17 -0
- data/ext/stash/tokens.c +151 -0
- data/ext/stash/types.c +181 -0
- data/lib/stash.rb +2 -34
- data/lib/stash/debug.rb +46 -0
- metadata +30 -88
- data/.document +0 -5
- data/LICENSE +0 -20
- data/README.markdown +0 -92
- data/Rakefile +0 -46
- data/VERSION +0 -1
- data/lib/stash/class_methods.rb +0 -59
- data/lib/stash/hash.rb +0 -62
- data/lib/stash/list.rb +0 -91
- data/lib/stash/redis_adapter.rb +0 -152
- data/lib/stash/string.rb +0 -16
- data/spec/hash_spec.rb +0 -29
- data/spec/list_spec.rb +0 -65
- data/spec/spec.opts +0 -1
- data/spec/spec_helper.rb +0 -12
- data/spec/string_spec.rb +0 -9
- data/stash.gemspec +0 -68
@@ -0,0 +1,208 @@
|
|
1
|
+
#include "intern.h"
|
2
|
+
|
3
|
+
/* forward declare helper functions */
|
4
|
+
static bool contains_node_type(mustache_node_t* root, enum mustache_node_type type);
|
5
|
+
static void remove_node(mustache_node_t* node);
|
6
|
+
static bool is_posfix_standalone(mustache_node_t* node);
|
7
|
+
bool is_whitespace(mustache_node_t* text_node);
|
8
|
+
|
9
|
+
bool optimize_block(mustache_node_t* node)
|
10
|
+
{
|
11
|
+
mustache_node_t* child = node->first_child;
|
12
|
+
while (child) {
|
13
|
+
if (!child->optimize(child)) {
|
14
|
+
return false;
|
15
|
+
}
|
16
|
+
child = child->next_sibling;
|
17
|
+
}
|
18
|
+
return true;
|
19
|
+
}
|
20
|
+
|
21
|
+
bool optimize_text(mustache_node_t* node)
|
22
|
+
{
|
23
|
+
// Remove indentation from starting standalone tags
|
24
|
+
if ((!node->prv_sibling || node->prv_sibling->type == NODE_NEWLINE) &&
|
25
|
+
node->next_sibling &&
|
26
|
+
(node->next_sibling->type == NODE_SECTION || node->next_sibling->type == NODE_INVERTED_SECTION) &&
|
27
|
+
contains_node_type(node->next_sibling->first_child, NODE_NEWLINE) &&
|
28
|
+
is_whitespace(node)) {
|
29
|
+
remove_node(node);
|
30
|
+
}
|
31
|
+
|
32
|
+
// Remove indentation from ending standalone tags if beginning tag was intented
|
33
|
+
if (!node->next_sibling &&
|
34
|
+
node->prv_sibling &&
|
35
|
+
node->prv_sibling->type == NODE_NEWLINE &&
|
36
|
+
node->parent &&
|
37
|
+
node->parent->parent &&
|
38
|
+
(node->parent->parent->type == NODE_SECTION || node->parent->parent->type == NODE_INVERTED_SECTION) &&
|
39
|
+
(!node->parent->parent->next_sibling || (node->parent->parent->prv_sibling && is_whitespace(node->parent->parent->prv_sibling))) &&
|
40
|
+
is_whitespace(node)) {
|
41
|
+
remove_node(node);
|
42
|
+
}
|
43
|
+
|
44
|
+
return true;
|
45
|
+
}
|
46
|
+
|
47
|
+
bool optimize_newline(mustache_node_t* node)
|
48
|
+
{
|
49
|
+
// Remove newlines after starting standalone section tags
|
50
|
+
if (!node->prv_sibling &&
|
51
|
+
node->parent &&
|
52
|
+
node->parent->parent &&
|
53
|
+
(node->parent->parent->type == NODE_SECTION || node->parent->parent->type == NODE_INVERTED_SECTION)&&
|
54
|
+
(!node->parent->parent->prv_sibling || is_whitespace(node->parent->parent->prv_sibling))) {
|
55
|
+
remove_node(node);
|
56
|
+
}
|
57
|
+
|
58
|
+
// Remove newlines after ending standalone section tags
|
59
|
+
if (node->prv_sibling &&
|
60
|
+
(node->prv_sibling->type == NODE_SECTION || node->prv_sibling->type == NODE_INVERTED_SECTION) &&
|
61
|
+
(!node->prv_sibling->first_child->first_child || contains_node_type(node->prv_sibling->first_child, NODE_NEWLINE))) {
|
62
|
+
remove_node(node);
|
63
|
+
}
|
64
|
+
return true;
|
65
|
+
}
|
66
|
+
|
67
|
+
bool optimize_variable(mustache_node_t* node)
|
68
|
+
{
|
69
|
+
return true;
|
70
|
+
}
|
71
|
+
|
72
|
+
bool optimize_section(mustache_node_t* node)
|
73
|
+
{
|
74
|
+
return node->first_child->optimize(node->first_child);
|
75
|
+
}
|
76
|
+
|
77
|
+
bool optimize_comment(mustache_node_t* node)
|
78
|
+
{
|
79
|
+
// Remove whitespace from standalone comments.
|
80
|
+
// Comments that satisfy any of the following conditions are considered standalone:
|
81
|
+
// 1. "{{!comment}}"
|
82
|
+
// 2. "{{!comment}} "
|
83
|
+
// 3. "{{!comment}}\n"
|
84
|
+
// 4. "{{!comment}} \n"
|
85
|
+
// 5. " {{!comment}}"
|
86
|
+
// 6. " {{!comment}} "
|
87
|
+
// 7. " {{!comment}}\n"
|
88
|
+
// 8. " {{!comment}} \n"
|
89
|
+
// 9. "\n{{!comment}}"
|
90
|
+
// 10. "\n{{!comment}} "
|
91
|
+
// 11. "\n{{!comment}}\n"
|
92
|
+
// 12. "\n{{!comment}} \n"
|
93
|
+
// 13. "\n {{!comment}}"
|
94
|
+
// 14. "\n {{!comment}} "
|
95
|
+
// 15. "\n {{!comment}}\n"
|
96
|
+
// 16. "\n {{!comment}} \n"
|
97
|
+
|
98
|
+
bool is_standalone = false;
|
99
|
+
mustache_node_t* tmp = NULL;
|
100
|
+
mustache_node_t* prv = node->prv_sibling;
|
101
|
+
mustache_node_t* next = node->next_sibling;
|
102
|
+
if (!prv) {
|
103
|
+
is_standalone = is_posfix_standalone(node);
|
104
|
+
} else if (is_whitespace(prv)) {
|
105
|
+
if (!prv->prv_sibling &&
|
106
|
+
(!node->parent || !node->parent->parent || !(node->parent->parent->type == NODE_SECTION || node->parent->parent->type == NODE_INVERTED_SECTION))) {
|
107
|
+
is_standalone = is_posfix_standalone(node);
|
108
|
+
} else if (prv->type == NODE_NEWLINE) {
|
109
|
+
is_standalone = is_posfix_standalone(node);
|
110
|
+
} else if (prv->prv_sibling && prv->prv_sibling->type == NODE_NEWLINE) {
|
111
|
+
is_standalone = is_posfix_standalone(node);
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
// if the comment is standalone, remove the unnessesary nodes.
|
116
|
+
if (is_standalone) {
|
117
|
+
if (prv && prv->type == NODE_TEXT && node->type == NODE_COMMENT) {
|
118
|
+
remove_node(prv);
|
119
|
+
}
|
120
|
+
if (next && next->type == NODE_TEXT) {
|
121
|
+
tmp = next->next_sibling;
|
122
|
+
remove_node(next);
|
123
|
+
next = tmp;
|
124
|
+
}
|
125
|
+
while (next && next->type == NODE_NEWLINE) {
|
126
|
+
tmp = next->next_sibling;
|
127
|
+
remove_node(next);
|
128
|
+
next = tmp;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
return true;
|
132
|
+
}
|
133
|
+
|
134
|
+
bool optimize_partial(mustache_node_t* node)
|
135
|
+
{
|
136
|
+
return optimize_comment(node);
|
137
|
+
}
|
138
|
+
|
139
|
+
|
140
|
+
/* helper functions */
|
141
|
+
|
142
|
+
static bool contains_node_type(mustache_node_t* root, enum mustache_node_type type)
|
143
|
+
{
|
144
|
+
if (root->type == type) {
|
145
|
+
return true;
|
146
|
+
}
|
147
|
+
|
148
|
+
if ((root->first_child && contains_node_type(root->first_child, type)) ||
|
149
|
+
(root->next_sibling && contains_node_type(root->next_sibling, type))) {
|
150
|
+
return true;
|
151
|
+
}
|
152
|
+
|
153
|
+
return false;
|
154
|
+
}
|
155
|
+
|
156
|
+
bool is_whitespace(mustache_node_t* text_node)
|
157
|
+
{
|
158
|
+
if (text_node->type == NODE_NEWLINE) {
|
159
|
+
return true;
|
160
|
+
}
|
161
|
+
|
162
|
+
if (text_node->type != NODE_TEXT) {
|
163
|
+
return false;
|
164
|
+
}
|
165
|
+
|
166
|
+
char* text = text_node->token->text;
|
167
|
+
while (text[0]) {
|
168
|
+
if (!isspace(text[0])) {
|
169
|
+
return false;
|
170
|
+
}
|
171
|
+
text++;
|
172
|
+
}
|
173
|
+
return true;
|
174
|
+
}
|
175
|
+
|
176
|
+
static void remove_node(mustache_node_t* node)
|
177
|
+
{
|
178
|
+
if (!node) {
|
179
|
+
return;
|
180
|
+
}
|
181
|
+
|
182
|
+
mustache_node_t* prv = node->prv_sibling;
|
183
|
+
mustache_node_t* next = node->next_sibling;
|
184
|
+
|
185
|
+
if (prv) {
|
186
|
+
prv->next_sibling = next;
|
187
|
+
} else {
|
188
|
+
node->parent->first_child = next;
|
189
|
+
}
|
190
|
+
|
191
|
+
if (next) {
|
192
|
+
next->prv_sibling = prv;
|
193
|
+
}
|
194
|
+
|
195
|
+
// TODO: free node
|
196
|
+
// TODO: free node's children
|
197
|
+
}
|
198
|
+
|
199
|
+
static bool is_posfix_standalone(mustache_node_t* node)
|
200
|
+
{
|
201
|
+
mustache_node_t* next = node->next_sibling;
|
202
|
+
if (!next || next->type == NODE_NEWLINE) {
|
203
|
+
return true;
|
204
|
+
} else if (next->type == NODE_TEXT && is_whitespace(next)) {
|
205
|
+
return (!next->next_sibling || next->next_sibling->type == NODE_NEWLINE);
|
206
|
+
}
|
207
|
+
return false;
|
208
|
+
}
|
data/ext/stash/stash.c
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <sys/time.h>
|
3
|
+
#include <sys/resource.h>
|
4
|
+
#include "mustache.h"
|
5
|
+
#include "stash.h"
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
extern void log_template_execution_time(mustache_context_t* m_ctx, double time);
|
10
|
+
extern double get_time();
|
11
|
+
|
12
|
+
VALUE cTemplate = Qnil;
|
13
|
+
|
14
|
+
static VALUE cTemplate_init(VALUE self, VALUE rb_template_string)
|
15
|
+
{
|
16
|
+
mustache_node_t* c_template;
|
17
|
+
Data_Get_Struct(self, mustache_node_t, c_template);
|
18
|
+
|
19
|
+
char* c_template_string;
|
20
|
+
long c_template_string_length;
|
21
|
+
mustache_error_t* error = NULL;
|
22
|
+
|
23
|
+
c_template_string = strdup(rb_str2cstr(rb_template_string, &c_template_string_length));
|
24
|
+
mustache_build_template(c_template_string, c_template, &error);
|
25
|
+
|
26
|
+
if (error) {
|
27
|
+
rb_raise(rb_eSyntaxError, error->error_text);
|
28
|
+
}
|
29
|
+
|
30
|
+
return self;
|
31
|
+
}
|
32
|
+
|
33
|
+
static VALUE cTemplate_render(int argc, VALUE* argv, VALUE self)
|
34
|
+
{
|
35
|
+
VALUE data = Qnil;
|
36
|
+
VALUE partials = Qnil;
|
37
|
+
VALUE debug = Qnil;
|
38
|
+
|
39
|
+
if (argc > 0) {
|
40
|
+
VALUE type = TYPE(argv[0]);
|
41
|
+
if (type != T_OBJECT && type != T_HASH) {
|
42
|
+
rb_raise(rb_eArgError, "Expected an object or hash as argument 1");
|
43
|
+
return Qnil;
|
44
|
+
}
|
45
|
+
data = argv[0];
|
46
|
+
}
|
47
|
+
|
48
|
+
if (argc > 1) {
|
49
|
+
VALUE type = TYPE(argv[1]);
|
50
|
+
if (type != T_HASH) {
|
51
|
+
rb_raise(rb_eArgError, "Expected a hash as argument 2");
|
52
|
+
return Qnil;
|
53
|
+
}
|
54
|
+
partials = argv[1];
|
55
|
+
}
|
56
|
+
|
57
|
+
if (argc > 2) {
|
58
|
+
if (strcmp(rb_obj_classname(argv[2]), "Template::Debug") != 0) {
|
59
|
+
rb_raise(rb_eArgError, "Expected an instance of Template::Debug as argument 3");
|
60
|
+
return Qnil;
|
61
|
+
}
|
62
|
+
debug = argv[2];
|
63
|
+
}
|
64
|
+
|
65
|
+
// Get the template
|
66
|
+
mustache_node_t* c_template;
|
67
|
+
Data_Get_Struct(self, mustache_node_t, c_template);
|
68
|
+
|
69
|
+
// Create the context
|
70
|
+
mustache_context_t* m_ctx = create_mustache_context(NULL);
|
71
|
+
mustache_ruby_context_t* r_ctx = (mustache_ruby_context_t*) m_ctx->custom;
|
72
|
+
m_ctx->data = (void*) data;
|
73
|
+
m_ctx->partials = (void*) partials;
|
74
|
+
m_ctx->debug_mode = debug != Qnil;
|
75
|
+
|
76
|
+
double start = 0;
|
77
|
+
if (m_ctx->debug_mode) {
|
78
|
+
start = get_time();
|
79
|
+
r_ctx->debugObject = debug;
|
80
|
+
}
|
81
|
+
|
82
|
+
// Execute the template
|
83
|
+
mustache_execute_template(c_template, m_ctx);
|
84
|
+
|
85
|
+
if (m_ctx->debug_mode) {
|
86
|
+
log_template_execution_time(m_ctx, get_time() - start);
|
87
|
+
}
|
88
|
+
|
89
|
+
// Return the buffer
|
90
|
+
VALUE result = rb_str_resize(r_ctx->buffer, r_ctx->buffer_length);
|
91
|
+
m_ctx->destroy(m_ctx);
|
92
|
+
return result;
|
93
|
+
}
|
94
|
+
|
95
|
+
static void template_mark(mustache_node_t* node)
|
96
|
+
{
|
97
|
+
}
|
98
|
+
|
99
|
+
static void template_free(mustache_node_t* node)
|
100
|
+
{
|
101
|
+
}
|
102
|
+
|
103
|
+
static VALUE template_allocate(VALUE klass)
|
104
|
+
{
|
105
|
+
mustache_node_t* c_template = mustache_create_node();
|
106
|
+
return Data_Wrap_Struct(cTemplate, template_mark, template_free, c_template);
|
107
|
+
}
|
108
|
+
|
109
|
+
void Init_stash()
|
110
|
+
{
|
111
|
+
// Define the Template class
|
112
|
+
cTemplate = rb_define_class("Template", rb_cObject);
|
113
|
+
rb_define_alloc_func(cTemplate, template_allocate);
|
114
|
+
rb_define_method(cTemplate, "initialize", cTemplate_init, 1);
|
115
|
+
rb_define_method(cTemplate, "render", cTemplate_render, -1);
|
116
|
+
}
|
117
|
+
|
118
|
+
bool mustache_write_to_buffer(mustache_context_t* m_ctx, char* data, size_t data_length)
|
119
|
+
{
|
120
|
+
if (data_length == 0) {
|
121
|
+
return true;
|
122
|
+
}
|
123
|
+
|
124
|
+
mustache_ruby_context_t* r_ctx = (mustache_ruby_context_t*) m_ctx->custom;
|
125
|
+
rb_str_buf_cat(r_ctx->buffer, data, data_length);
|
126
|
+
r_ctx->buffer_length += data_length;
|
127
|
+
return true;
|
128
|
+
}
|
129
|
+
|
130
|
+
void* mustache_malloc(long size)
|
131
|
+
{
|
132
|
+
return ruby_xmalloc(size);
|
133
|
+
}
|
134
|
+
|
135
|
+
void mustache_free(void* ptr)
|
136
|
+
{
|
137
|
+
ruby_xfree(ptr);
|
138
|
+
}
|
139
|
+
|
140
|
+
mustache_node_t* get_partial(char* key, void* partials)
|
141
|
+
{
|
142
|
+
VALUE rb_partials = (VALUE) partials;
|
143
|
+
Check_Type(rb_partials, T_HASH);
|
144
|
+
|
145
|
+
VALUE rb_value;
|
146
|
+
if (NIL_P(rb_value = rb_hash_aref(rb_partials, ID2SYM(rb_intern(key))))) {
|
147
|
+
return NULL;
|
148
|
+
}
|
149
|
+
|
150
|
+
if (rb_class_of(rb_value) != cTemplate) {
|
151
|
+
rb_raise(rb_eTypeError, "Expected Template");
|
152
|
+
}
|
153
|
+
|
154
|
+
mustache_node_t* template = NULL;
|
155
|
+
Data_Get_Struct(rb_value, mustache_node_t, template);
|
156
|
+
return template;
|
157
|
+
}
|
158
|
+
|
159
|
+
double get_time()
|
160
|
+
{
|
161
|
+
struct timeval t;
|
162
|
+
struct timezone tzp;
|
163
|
+
gettimeofday(&t, &tzp);
|
164
|
+
return t.tv_sec + t.tv_usec*1e-6;
|
165
|
+
}
|
166
|
+
|
167
|
+
void log_template_execution_time(mustache_context_t* m_ctx, double time)
|
168
|
+
{
|
169
|
+
mustache_ruby_context_t* r_ctx = (mustache_ruby_context_t*) m_ctx->custom;
|
170
|
+
rb_ivar_set(r_ctx->debugObject, rb_intern("@total_time"), rb_float_new(time));
|
171
|
+
}
|
172
|
+
|
173
|
+
void log_ruby_callback_execution_time(mustache_context_t* m_ctx, ID callback_name, double time)
|
174
|
+
{
|
175
|
+
mustache_ruby_context_t* r_ctx = (mustache_ruby_context_t*) m_ctx->custom;
|
176
|
+
rb_funcall(r_ctx->debugObject, rb_intern("log_callback"), 2, ID2SYM(callback_name), rb_float_new(time));
|
177
|
+
}
|
data/ext/stash/stash.h
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
typedef struct mustache_ruby_context {
|
2
|
+
VALUE buffer;
|
3
|
+
long buffer_length;
|
4
|
+
VALUE debugObject;
|
5
|
+
} mustache_ruby_context_t;
|
6
|
+
|
7
|
+
mustache_context_t* create_mustache_context(mustache_context_t* parent);
|
8
|
+
|
9
|
+
mustache_value_t* convert_type(
|
10
|
+
char* key,
|
11
|
+
void* context,
|
12
|
+
mustache_context_t* m_lookup_context,
|
13
|
+
mustache_context_t* m_exection_context);
|
14
|
+
|
15
|
+
mustache_node_t* get_partial(char* key, void* partials);
|
16
|
+
void log_ruby_callback_execution_time(mustache_context_t* m_ctx, ID callback_name, double time);
|
17
|
+
double get_time();
|
data/ext/stash/tokens.c
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
#include "intern.h"
|
2
|
+
|
3
|
+
void set_start_delimiter(char* delimiter, scanner_data_t* data)
|
4
|
+
{
|
5
|
+
data->statement_start = strdup(delimiter);
|
6
|
+
}
|
7
|
+
|
8
|
+
void use_next_end_delimiter(scanner_data_t* data)
|
9
|
+
{
|
10
|
+
data->statement_end = data->next_statement_end;
|
11
|
+
data->next_statement_end = "";
|
12
|
+
}
|
13
|
+
|
14
|
+
void set_next_end_delimiter(char* delimiter, scanner_data_t* data)
|
15
|
+
{
|
16
|
+
data->statement_end = strdup(delimiter);
|
17
|
+
}
|
18
|
+
|
19
|
+
mustache_token_t* pop_token(mustache_token_t** head)
|
20
|
+
{
|
21
|
+
mustache_token_t* token = *head;
|
22
|
+
*head = token->next;
|
23
|
+
return token;
|
24
|
+
}
|
25
|
+
|
26
|
+
void reverse(mustache_token_t** head)
|
27
|
+
{
|
28
|
+
mustache_token_t* prv = NULL;
|
29
|
+
mustache_token_t* current = *head;
|
30
|
+
|
31
|
+
while (current) {
|
32
|
+
mustache_token_t* next = current->next;
|
33
|
+
current->next = prv;
|
34
|
+
prv = current;
|
35
|
+
current = next;
|
36
|
+
}
|
37
|
+
|
38
|
+
*head = prv;
|
39
|
+
}
|
40
|
+
|
41
|
+
bool is_token(mustache_token_t* head, enum mustache_token_type type)
|
42
|
+
{
|
43
|
+
if (!head) {
|
44
|
+
return false;
|
45
|
+
}
|
46
|
+
|
47
|
+
return head->type == type;
|
48
|
+
}
|
49
|
+
|
50
|
+
void free_token(mustache_token_t* token)
|
51
|
+
{
|
52
|
+
if (!token) {
|
53
|
+
return;
|
54
|
+
}
|
55
|
+
|
56
|
+
if (*token->text) {
|
57
|
+
free(token->text);
|
58
|
+
}
|
59
|
+
|
60
|
+
free(token);
|
61
|
+
}
|
62
|
+
|
63
|
+
bool is_string_in_buffer(char* string, int string_len, char* buffer, int buffer_len)
|
64
|
+
{
|
65
|
+
if (buffer_len < string_len) {
|
66
|
+
return false;
|
67
|
+
}
|
68
|
+
|
69
|
+
return strncmp(&buffer[buffer_len - string_len], string, string_len) == 0;
|
70
|
+
}
|
71
|
+
|
72
|
+
mustache_token_t* create_token(enum mustache_token_type type, char* text)
|
73
|
+
{
|
74
|
+
mustache_token_t* token = malloc(sizeof(mustache_token_t));
|
75
|
+
char* copied_text = strdup(text);
|
76
|
+
|
77
|
+
if (token) {
|
78
|
+
token->type = type;
|
79
|
+
token->text = copied_text;
|
80
|
+
token->next = NULL;
|
81
|
+
}
|
82
|
+
|
83
|
+
return token;
|
84
|
+
}
|
85
|
+
|
86
|
+
void push_token(enum mustache_token_type type, char* text, yyscan_t yyscanner)
|
87
|
+
{
|
88
|
+
scanner_data_t* data = (scanner_data_t*) yyget_extra(yyscanner);
|
89
|
+
mustache_token_t* token = create_token(type, text);
|
90
|
+
|
91
|
+
if (data->head_token) {
|
92
|
+
token->next = data->head_token;
|
93
|
+
}
|
94
|
+
|
95
|
+
data->head_token = token;
|
96
|
+
}
|
97
|
+
|
98
|
+
void push_text(yyscan_t yyscanner)
|
99
|
+
{
|
100
|
+
// Get the accumulated text
|
101
|
+
scanner_data_t* data = (scanner_data_t*) yyget_extra(yyscanner);
|
102
|
+
|
103
|
+
// If the buffer contains text, push the token and reset buffer
|
104
|
+
if (data->buffer[0]) {
|
105
|
+
push_token(TOKEN_TEXT, data->buffer, yyscanner);
|
106
|
+
memset(data->buffer, '\0', data->buffer_size);
|
107
|
+
data->buffer_index = 0;
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
void push_comment(yyscan_t yyscanner)
|
112
|
+
{
|
113
|
+
// Get the accumulated text
|
114
|
+
scanner_data_t* data = (scanner_data_t*) yyget_extra(yyscanner);
|
115
|
+
|
116
|
+
// If the buffer contains text, push the token and reset buffer
|
117
|
+
if (data->buffer[0]) {
|
118
|
+
push_token(TOKEN_COMMENT, data->buffer, yyscanner);
|
119
|
+
memset(data->buffer, '\0', data->buffer_size);
|
120
|
+
data->buffer_index = 0;
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
void push_error(yyscan_t yyscanner)
|
125
|
+
{
|
126
|
+
return;
|
127
|
+
}
|
128
|
+
|
129
|
+
int get_tokens(char* input, mustache_token_t** tokens)
|
130
|
+
{
|
131
|
+
yyscan_t scanner;
|
132
|
+
scanner_data_t data;
|
133
|
+
data.head_token = NULL;
|
134
|
+
data.buffer_size = sizeof(char) * strlen(input) + 1;
|
135
|
+
data.buffer = malloc(data.buffer_size);
|
136
|
+
memset(data.buffer, '\0', data.buffer_size);
|
137
|
+
data.buffer_index = 0;
|
138
|
+
data.statement_start = "{{";
|
139
|
+
data.statement_end = "}}";
|
140
|
+
data.next_statement_end = "";
|
141
|
+
|
142
|
+
yylex_init_extra(&data, &scanner);
|
143
|
+
yy_scan_string(input, scanner);
|
144
|
+
yylex(scanner);
|
145
|
+
yylex_destroy(scanner);
|
146
|
+
*tokens = data.head_token;
|
147
|
+
free(data.buffer);
|
148
|
+
reverse(tokens);
|
149
|
+
|
150
|
+
return true;
|
151
|
+
}
|