stash 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,267 @@
1
+ #include "intern.h"
2
+
3
+ /* forward declare helper functions */
4
+ static void append_node(mustache_node_t* parent, mustache_node_t* src);
5
+ static mustache_error_t* create_error(mustache_token_t* last_token, enum mustache_token_type expected_token, char* error_text);
6
+
7
+ /*
8
+
9
+ template := block
10
+ block := statement | block
11
+ statement := [text] | [newline] | command
12
+ command := variable | section | inverse_section | partial | comment
13
+ variable := [raw] [identifier] | [identifier]
14
+ section := [section_start] [identifier] block [section_end]
15
+ inverse_section := [inverse_section_start] [identifier] block [section_end]
16
+ partial := [partial] [identifier]
17
+
18
+ */
19
+
20
+ void build_template(mustache_token_t* tokens, mustache_node_t* root, mustache_error_t** error)
21
+ {
22
+ root->type = NODE_BLOCK;
23
+ root->execute = execute_block;
24
+ root->optimize = optimize_block;
25
+ append_node(root, build_block(&tokens, error));
26
+
27
+ if (tokens) {
28
+ *error = create_error(tokens, TOKEN_ERROR, tokens->text);
29
+ }
30
+ }
31
+
32
+ mustache_node_t* build_block(mustache_token_t** tokens, mustache_error_t** error)
33
+ {
34
+ mustache_node_t* block;
35
+ mustache_node_t* next;
36
+
37
+ block = mustache_create_node();
38
+ block->type = NODE_BLOCK;
39
+ block->execute = execute_block;
40
+ block->optimize = optimize_block;
41
+
42
+ while ((next = build_statement(tokens, error))) {
43
+ append_node(block, next);
44
+ }
45
+
46
+ return block;
47
+ }
48
+
49
+ mustache_node_t* build_statement(mustache_token_t** tokens, mustache_error_t** error)
50
+ {
51
+ mustache_node_t* next = build_text(tokens, error);
52
+
53
+ if (!next) {
54
+ next = build_newline(tokens, error);
55
+ }
56
+
57
+ if (!next) {
58
+ next = build_command(tokens, error);
59
+ }
60
+
61
+ return next;
62
+ }
63
+
64
+ mustache_node_t* build_text(mustache_token_t** tokens, mustache_error_t** error)
65
+ {
66
+ mustache_node_t* next;
67
+
68
+ if (!is_token(*tokens, TOKEN_TEXT)) {
69
+ return NULL;
70
+ }
71
+
72
+ next = mustache_create_node();
73
+ next->type = NODE_TEXT;
74
+ next->token = pop_token(tokens);
75
+ next->execute = execute_text;
76
+ next->optimize = optimize_text;
77
+ return next;
78
+ }
79
+
80
+ mustache_node_t* build_newline(mustache_token_t** tokens, mustache_error_t** error)
81
+ {
82
+ mustache_node_t* next;
83
+
84
+ if (!is_token(*tokens, TOKEN_NEWLINE)) {
85
+ return NULL;
86
+ }
87
+
88
+ next = mustache_create_node();
89
+ next->type = NODE_NEWLINE;
90
+ next->token = pop_token(tokens);
91
+ next->execute = execute_newline;
92
+ next->optimize = optimize_newline;
93
+ return next;
94
+ }
95
+
96
+ mustache_node_t* build_command(mustache_token_t** tokens, mustache_error_t** error)
97
+ {
98
+ mustache_node_t* next = build_raw_variable(tokens, error);
99
+
100
+ if (!next) {
101
+ next = build_variable(tokens, error);
102
+ }
103
+
104
+ if (!next) {
105
+ next = build_section(tokens, error);
106
+ }
107
+
108
+ if (!next) {
109
+ next = build_partial(tokens, error);
110
+ }
111
+
112
+ if (!next) {
113
+ next = build_comment(tokens, error);
114
+ }
115
+
116
+ return next;
117
+ }
118
+
119
+ mustache_node_t* build_raw_variable(mustache_token_t** tokens, mustache_error_t** error)
120
+ {
121
+ mustache_node_t* next;
122
+
123
+ if (!is_token(*tokens, TOKEN_RAW)) {
124
+ return NULL;
125
+ }
126
+
127
+ free_token(pop_token(tokens));
128
+
129
+ if (!is_token(*tokens, TOKEN_IDENTIFIER)) {
130
+ *error = create_error(*tokens, TOKEN_IDENTIFIER, "Expected identifier");
131
+ }
132
+
133
+ next = mustache_create_node();
134
+ next->type = NODE_RAW_VARIABLE;
135
+ next->token = pop_token(tokens);
136
+ next->execute = execute_raw_variable;
137
+ next->optimize = optimize_variable;
138
+ return next;
139
+ }
140
+
141
+ mustache_node_t* build_variable(mustache_token_t** tokens, mustache_error_t** error)
142
+ {
143
+ mustache_node_t* next;
144
+
145
+ if (!is_token(*tokens, TOKEN_IDENTIFIER)) {
146
+ return NULL;
147
+ }
148
+
149
+ next = mustache_create_node();
150
+ next->type = NODE_VARIABLE;
151
+ next->token = pop_token(tokens);
152
+ next->execute = execute_variable;
153
+ next->optimize = optimize_variable;
154
+ return next;
155
+ }
156
+
157
+ mustache_node_t* build_section(mustache_token_t** tokens, mustache_error_t** error)
158
+ {
159
+ mustache_node_t* section;
160
+ mustache_token_t* token;
161
+ bool is_inverted;
162
+
163
+ if (!is_token(*tokens, TOKEN_SECTION_START) &&
164
+ !is_token(*tokens, TOKEN_ISECTION_START)) {
165
+ return NULL;
166
+ }
167
+
168
+ token = pop_token(tokens);
169
+ is_inverted = token->type == TOKEN_ISECTION_START;
170
+ free_token(token);
171
+
172
+ if (!is_token(*tokens, TOKEN_IDENTIFIER)) {
173
+ *error = create_error(*tokens, TOKEN_IDENTIFIER, "Expected identifier");
174
+ return NULL;
175
+ }
176
+
177
+ section = mustache_create_node();
178
+ section->type = is_inverted ? NODE_INVERTED_SECTION : NODE_SECTION;
179
+ section->token = pop_token(tokens);
180
+ section->execute = execute_section;
181
+ section->optimize = optimize_section;
182
+ append_node(section, build_block(tokens, error));
183
+
184
+ if (!is_token(*tokens, TOKEN_SECTION_END)) {
185
+ *error = create_error(*tokens, TOKEN_SECTION_END, "Expected section end");
186
+ return NULL;
187
+ }
188
+
189
+ free_token(pop_token(tokens));
190
+
191
+ if (!is_token(*tokens, TOKEN_IDENTIFIER)) {
192
+ *error = create_error(*tokens, TOKEN_IDENTIFIER, "Expected identifier");
193
+ return NULL;
194
+ }
195
+
196
+ free_token(pop_token(tokens));
197
+
198
+ return section;
199
+ }
200
+
201
+ mustache_node_t* build_partial(mustache_token_t** tokens, mustache_error_t** error)
202
+ {
203
+ mustache_node_t* node;
204
+
205
+ if (!is_token(*tokens, TOKEN_PARTIAL)) {
206
+ return NULL;
207
+ }
208
+
209
+ free_token(pop_token(tokens));
210
+
211
+ if (!is_token(*tokens, TOKEN_IDENTIFIER)) {
212
+ *error = create_error(*tokens, TOKEN_IDENTIFIER, "Expected identifier");
213
+ return NULL;
214
+ }
215
+
216
+ node = mustache_create_node();
217
+ node->type = NODE_PARTIAL;
218
+ node->token = pop_token(tokens);
219
+ node->execute = execute_partial;
220
+ node->optimize = optimize_partial;
221
+ return node;
222
+ }
223
+
224
+ mustache_node_t* build_comment(mustache_token_t** tokens, mustache_error_t** error)
225
+ {
226
+ mustache_node_t* node;
227
+
228
+ if (!is_token(*tokens, TOKEN_COMMENT)) {
229
+ return NULL;
230
+ }
231
+
232
+ node = mustache_create_node();
233
+ node->type = NODE_COMMENT;
234
+ node->token = pop_token(tokens);
235
+ node->execute = execute_comment;
236
+ node->optimize = optimize_comment;
237
+ return node;
238
+ }
239
+
240
+
241
+ /* Helper functions */
242
+
243
+ static void append_node(mustache_node_t* parent, mustache_node_t* src)
244
+ {
245
+ mustache_node_t* child = parent->first_child;
246
+
247
+ if (!child) {
248
+ parent->first_child = src;
249
+ }
250
+ else {
251
+ while (child->next_sibling) {
252
+ child = child->next_sibling;
253
+ }
254
+ child->next_sibling = src;
255
+ src->prv_sibling = child;
256
+ }
257
+
258
+ src->parent = parent;
259
+ }
260
+
261
+ static mustache_error_t* create_error(mustache_token_t* last_token, enum mustache_token_type expected_token, char* error_text)
262
+ {
263
+ mustache_error_t* error = mustache_malloc(sizeof(mustache_error_t));
264
+ error->last_token = last_token;
265
+ error->error_text = error_text;
266
+ return error;
267
+ }
@@ -0,0 +1,248 @@
1
+ #include "intern.h"
2
+
3
+ /* forward declare helper functions */
4
+ static bool html_encode(char* non_terminated_input, size_t length, mustache_context_t* ctx);
5
+ static mustache_value_t* get_variable_value(char* key, mustache_context_t* ctx);
6
+ static mustache_value_t* get_value(char* key, mustache_context_t* ctx);
7
+ bool is_whitespace(mustache_node_t* text_node);
8
+
9
+ bool execute_block(mustache_node_t* node, mustache_context_t* ctx)
10
+ {
11
+ mustache_node_t* child = node->first_child;
12
+
13
+ while (child) {
14
+ if (!child->execute(child, ctx)) {
15
+ return false;
16
+ }
17
+ child = child->next_sibling;
18
+ }
19
+ return true;
20
+ }
21
+
22
+ bool execute_text(mustache_node_t* node, mustache_context_t* ctx)
23
+ {
24
+ return mustache_write_to_buffer(ctx, node->token->text, strlen(node->token->text));
25
+ }
26
+
27
+ bool execute_newline(mustache_node_t* node, mustache_context_t* ctx)
28
+ {
29
+ if (!mustache_write_to_buffer(ctx, node->token->text, strlen(node->token->text))) {
30
+ return false;
31
+ }
32
+
33
+ if (*ctx->prefix && node->next_sibling) {
34
+ if (!mustache_write_to_buffer(ctx, ctx->prefix, strlen(ctx->prefix))) {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ return true;
40
+ }
41
+
42
+ bool execute_raw_variable(mustache_node_t* node, mustache_context_t* ctx)
43
+ {
44
+ mustache_value_t* value = get_variable_value(node->token->text, ctx);
45
+ if (value) {
46
+ if (value->type == VALUE_VALUE) {
47
+ if (!mustache_write_to_buffer(ctx, value->data.value, value->length)) {
48
+ value->destroy(value);
49
+ return false;
50
+ }
51
+ }
52
+ value->destroy(value);
53
+ }
54
+
55
+ return true;
56
+ }
57
+
58
+ bool execute_variable(mustache_node_t* node, mustache_context_t* ctx)
59
+ {
60
+ mustache_value_t* value = get_variable_value(node->token->text, ctx);
61
+ if (value) {
62
+ if (value->type == VALUE_VALUE) {
63
+ if (!html_encode(value->data.value, value->length, ctx)) {
64
+ printf("html_encode failed\n");
65
+ value->destroy(value);
66
+ return false;
67
+ }
68
+ }
69
+ value->destroy(value);
70
+ }
71
+
72
+ return true;
73
+ }
74
+ size_t foo = 0;
75
+
76
+ bool execute_section(mustache_node_t* node, mustache_context_t* ctx)
77
+ {
78
+ mustache_value_t* value = get_variable_value(node->token->text, ctx);
79
+ mustache_context_t** list_contexts = NULL;
80
+ mustache_context_t* list_context = NULL;
81
+ bool response = true;
82
+
83
+ bool is_true;
84
+
85
+ // If the variable doesn't exist, don't execute the template
86
+ if (!value && node->type == NODE_SECTION) {
87
+ return true;
88
+ } else if (!value && node->type == NODE_INVERTED_SECTION) {
89
+ return node->first_child->execute(node->first_child, ctx);
90
+ }
91
+
92
+ switch (value->type) {
93
+ case VALUE_LIST:
94
+ list_contexts = value->data.list;
95
+
96
+ if (node->type == NODE_INVERTED_SECTION) {
97
+ if (value->length) {
98
+ return true;
99
+ } else {
100
+ return node->first_child->execute(node->first_child, ctx);
101
+ }
102
+ }
103
+
104
+ for (size_t i = 0; i < value->length; i++) {
105
+ list_context = list_contexts[i];
106
+ list_context->parent = ctx;
107
+ list_context->partials = ctx->partials;
108
+ list_context->get_partial = ctx->get_partial;
109
+ response = node->first_child->execute(node->first_child, list_context);
110
+
111
+ if (!response) {
112
+ break;
113
+ }
114
+ }
115
+
116
+ break;
117
+ case VALUE_OBJECT:
118
+ is_true = value->data.object != NULL;
119
+ if (is_true == (node->type == NODE_SECTION)) {
120
+ value->data.object->parent = ctx;
121
+ response = node->first_child->execute(node->first_child, value->data.object);
122
+ value->data.object->parent = NULL;
123
+ }
124
+ break;
125
+ case VALUE_VALUE:
126
+ is_true = value->length > 0;
127
+ if (is_true == (node->type == NODE_SECTION)) {
128
+ response = node->first_child->execute(node->first_child, ctx);
129
+ } else {
130
+ response = true;
131
+ }
132
+ break;
133
+ }
134
+
135
+ value->destroy(value);
136
+
137
+ if (!response) {
138
+ // TODO: truncate
139
+ }
140
+ return true;
141
+ }
142
+
143
+ bool execute_partial(mustache_node_t* node, mustache_context_t* ctx)
144
+ {
145
+ mustache_node_t* partial = ctx->get_partial(node->token->text, ctx->partials);
146
+
147
+ // add indentation
148
+ char* indentation = NULL;
149
+
150
+ if (node->prv_sibling &&
151
+ node->prv_sibling->type == NODE_TEXT &&
152
+ is_whitespace(node->prv_sibling) &&
153
+ (!node->prv_sibling->prv_sibling || node->prv_sibling->prv_sibling->type == NODE_NEWLINE)) {
154
+
155
+ // Save existing indentation, it will be replaced after partial execution
156
+ indentation = ctx->prefix;
157
+ size_t current_length = *ctx->prefix ? strlen(ctx->prefix) : 0;
158
+ size_t sibling_length = strlen(node->prv_sibling->token->text);
159
+
160
+ ctx->prefix = malloc(sizeof(char) * (current_length + sibling_length + 1));
161
+
162
+ if (current_length) {
163
+ strncpy(ctx->prefix, ctx->prefix, current_length);
164
+ }
165
+ strncpy(ctx->prefix + current_length, node->prv_sibling->token->text, sibling_length);
166
+ }
167
+
168
+ bool ret_val = true;
169
+ if (partial) {
170
+ ret_val = partial->execute(partial, ctx);
171
+ }
172
+
173
+ // restore indentation
174
+ if (indentation) {
175
+ free(ctx->prefix);
176
+ ctx->prefix = indentation;
177
+ }
178
+
179
+ return ret_val;
180
+ }
181
+
182
+ bool execute_comment(mustache_node_t* node, mustache_context_t* ctx)
183
+ {
184
+ return true;
185
+ }
186
+
187
+ /* helper functions */
188
+
189
+ static bool html_encode(
190
+ char* non_terminated_input,
191
+ size_t length,
192
+ mustache_context_t* ctx)
193
+ {
194
+ char current;
195
+ char* replacement;
196
+ size_t replacement_length;
197
+
198
+ for (int i = 0; i < length; i++) {
199
+ current = non_terminated_input[i];
200
+
201
+ switch (current) {
202
+ case '&': replacement = "&amp;"; replacement_length = 5; break;
203
+ case '"': replacement = "&quot;"; replacement_length = 6; break;
204
+ case '<': replacement = "&lt;"; replacement_length = 4; break;
205
+ case '>': replacement = "&gt;"; replacement_length = 4; break;
206
+ default:
207
+ replacement = &current;
208
+ replacement_length = 1;
209
+ break;
210
+ }
211
+
212
+ if (!mustache_write_to_buffer(ctx, replacement, replacement_length)) {
213
+ return false;
214
+ }
215
+ }
216
+
217
+ return true;
218
+ }
219
+
220
+ static mustache_value_t* get_variable_value(char* key, mustache_context_t* ctx)
221
+ {
222
+ // special case for implicit variables
223
+ if (key[0] == '.') {
224
+ return ctx->get_data(key, ctx->data, ctx, ctx);
225
+ }
226
+
227
+ char* context_identifier = strtok(key, ".");
228
+ mustache_value_t* result = NULL;
229
+ while (context_identifier) {
230
+ result = get_value(context_identifier, ctx);
231
+ if (result && result->type == VALUE_OBJECT) {
232
+ ctx = result->data.object;
233
+ }
234
+ context_identifier = strtok(NULL, ".");
235
+ }
236
+ return result;
237
+ }
238
+
239
+ static mustache_value_t* get_value(char* key, mustache_context_t* ctx)
240
+ {
241
+ mustache_value_t* value = ctx->get_data(key, ctx->data, ctx, ctx);
242
+ mustache_context_t* current_context = ctx;
243
+ while (!value && current_context->parent) {
244
+ current_context = current_context->parent;
245
+ value = current_context->get_data(key, current_context->data, current_context, ctx);
246
+ }
247
+ return value;
248
+ }