Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_compile_parse_template.c
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Adaptive Framework Compiler Parser
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
14 #include "afw_internal.h"
15 
16 
17 
18 /*ebnf>>>
19  *
20  * Substitution ::= '${' Script '}'
21  *
22  *<<<ebnf*/
24 afw_compile_parse_Substitution(afw_compile_parser_t *parser)
25 {
26  const afw_value_t *result;
27 
28  afw_compile_get_token();
29 
30  if (afw_compile_token_is(substitute_start)) {
31  result = afw_compile_parse_list_of_statements(parser,
32  true, true);
33  }
34 
35  else {
36  AFW_COMPILE_THROW_ERROR_Z("Internal error");
37  }
38 
39  /* Return result. */
40  return result;
41 }
42 
43 
44 
45 /*ebnf>>>
46  *
47  * Template ::=
48  * (
49  * (Char - '$') | ( '\$' ) | '$' (Char - '{') | Substitution
50  * )*
51  *
52  *<<<ebnf*/
54 afw_compile_parse_Template(afw_compile_parser_t *parser)
55 {
56  const afw_utf8_t *string;
57  apr_array_header_t *values;
58  afw_size_t start_offset;
59  afw_size_t string_cursor;
60  afw_size_t previous_cursor;
62  afw_boolean_t substitution;
63  afw_size_t len;
65 
66  values = apr_array_make(parser->apr_p, 5, sizeof(afw_value_t *));
67 
68  /* Loop parsing template. */
69  afw_compile_save_cursor(start_offset);
70  afw_compile_save_cursor(string_cursor);
71  for (substitution = false;;) {
72 
73  /* Save cursor and get next code point. */
74  afw_compile_save_cursor(previous_cursor);
75  cp = afw_compile_get_code_point();
76 
77  /* If '\$' change to '$'. */
78  if (cp == '\\') {
79  cp = afw_compile_get_code_point();
80  if (cp == '$') {
81  len = afw_compile_source_buffer_length_from(string_cursor) - 1;
82  s = afw_pool_malloc(parser->p, len, parser->xctx);
83  s[len - 1] = '$';
84  if (len > 1) {
85  memcpy(s,
86  afw_compile_source_buffer_at(string_cursor),
87  len - 1);
88  }
89  string = afw_utf8_create(s, len, parser->p, parser->xctx);
90  APR_ARRAY_PUSH(values, const afw_value_t *) =
91  afw_value_create_string(string, parser->p, parser->xctx);
92  afw_compile_save_cursor(string_cursor);
93  continue;
94  }
95  afw_compile_restore_cursor(previous_cursor);
96  cp = afw_compile_get_code_point();
97  }
98 
99  /* If '${', indicate substitution and restore cursor. */
100  if (cp == '$') {
101  cp = afw_compile_get_code_point();
102  if (cp == '{') {
103  afw_compile_restore_cursor(previous_cursor);
104  substitution = true;
105  }
106  }
107 
108  /* If substitution or end and string is not empty, push string value. */
109  if ((substitution || cp < 0) &&
110  !afw_compile_cursor_equal(string_cursor))
111  {
112  string = afw_utf8_create_copy(
113  afw_compile_source_buffer_at(string_cursor),
114  afw_compile_source_buffer_length_from(string_cursor),
115  parser->p, parser->xctx);
116  APR_ARRAY_PUSH(values, const afw_value_t *) =
117  afw_value_create_string(string, parser->p, parser->xctx);
118  }
119 
120  /* If end, break out of loop. */
121  if (cp < 0) break;
122 
123  /* If substitution, parse substitution and push value. */
124  if (substitution) {
125  APR_ARRAY_PUSH(values, const afw_value_t *) =
126  afw_compile_parse_Substitution(parser);
127  substitution = false;
128  afw_compile_save_cursor(string_cursor);
129  }
130  }
131 
132  /* If no elements, return empty string. */
133  if (values->nelts == 0) {
134  return afw_value_empty_string;
135  }
136 
137  /* If only one element and it is a string, return string value. */
138  if (values->nelts == 1 &&
139  afw_value_is_string(*((afw_value_t * *)values->elts)))
140  {
141  return *((afw_value_t * *)values->elts);
142  }
143 
144  /* Return template value. */
146  afw_compile_create_contextual_to_cursor(start_offset),
147  values->nelts,
148  (const afw_value_t * const *)values->elts,
149  parser->p, parser->xctx);
150 }
151 
152 
153 
154 /*ebnf>>>
155  *
156  * TemplateString ::= '`' + Template + '`'
157  *
158  *<<<ebnf*/
160 afw_compile_parse_TemplateString(afw_compile_parser_t *parser)
161 {
162  const afw_utf8_t *string;
163  apr_array_header_t *values;
164  afw_size_t start_offset;
165  afw_size_t previous_cursor;
166  afw_size_t previous_cursor2;
167  afw_code_point_t cp, cp2;
168  afw_boolean_t substitution;
169 
170  afw_compile_get_token_and_save_offset(start_offset);
171 
172  if (!afw_compile_token_is(grave)) {
173  AFW_COMPILE_THROW_ERROR_Z("Expecting template string");
174  }
175 
176  values = apr_array_make(parser->apr_p, 5, sizeof(afw_value_t *));
177 
178  /* Clear array used for building string. */
179  apr_array_clear(parser->s);
180 
181  /* Loop parsing template. */
182  afw_compile_save_cursor(start_offset);
183  for (substitution = false;;) {
184 
185  /* Save cursor and get next code point. */
186  afw_compile_save_cursor(previous_cursor);
187  cp = afw_compile_get_unescaped_code_point();
188 
189  /* If '${', indicate substitution and restore cursor. */
190  if (cp == '$') {
191  afw_compile_save_cursor(previous_cursor2);
192  cp2 = afw_compile_get_code_point();
193  if (cp2 == '{') {
194  afw_compile_restore_cursor(previous_cursor);
195  substitution = true;
196  }
197  else {
198  afw_compile_restore_cursor(previous_cursor2);
199  afw_compile_internal_s_push_code_point(parser, cp);
200  }
201  }
202  else if (cp < 0) {
203  AFW_COMPILE_THROW_ERROR_Z("Expecting grave symbol ('`')");
204  }
205  else if (cp != '`') {
206  afw_compile_internal_s_push_code_point(parser, cp);
207  }
208 
209  /* If substitution or end and string is not empty, push string value. */
210  if ((substitution || cp == '`') && parser->s->nelts > 0)
211  {
212  string = afw_utf8_create_copy(
213  (afw_utf8_octet_t *)parser->s->elts, parser->s->nelts,
214  parser->p, parser->xctx);
215  APR_ARRAY_PUSH(values, const afw_value_t *) =
216  afw_value_create_string(string, parser->p, parser->xctx);
217  apr_array_clear(parser->s);
218  }
219 
220  /* Finished if grave symbol. */
221  if (cp == '`') {
222  break;
223  };
224 
225  /* If substitution, parse substitution and push value. */
226  if (substitution) {
227  APR_ARRAY_PUSH(values, const afw_value_t *) =
228  afw_compile_parse_Substitution(parser);
229  substitution = false;
230  apr_array_clear(parser->s);
231  }
232  }
233 
234  /* If no elements, return empty string. */
235  if (values->nelts == 0) {
236  return afw_value_empty_string;
237  }
238 
239  /* If only one element and it is a string, return string value. */
240  if (values->nelts == 1 &&
241  afw_value_is_string(*((afw_value_t * *)values->elts)))
242  {
243  return *((afw_value_t * *)values->elts);
244  }
245 
246  /* Return template value. */
248  afw_compile_create_contextual_to_cursor(start_offset),
249  values->nelts,
250  (const afw_value_t * const *)values->elts,
251  parser->p, parser->xctx);
252 }
253 
254 
255 
256 /*ebnf>>>
257  *
258  * NamedTemplateString ::= '`' + ((Char - '$') | ('\$') | ('$' (Char - '{')) | '${' PropertyName '}') * '`'
259  *
260  *<<<ebnf*/
#define AFW_DEFINE_INTERNAL(type)
Define an internal function for /src/afw/ source*.c files.
Adaptive Framework Core Internal.
afw_value_create_string(const afw_utf8_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type string value.
#define afw_value_is_string(A_VALUE)
Macro to determine if value is evaluated string.
_Bool afw_boolean_t
Definition: afw_common.h:373
afw_int32_t afw_code_point_t
Unicode code point.
Definition: afw_common.h:205
char afw_utf8_octet_t
8 bits of utf-8 codepoint.
Definition: afw_common.h:236
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
#define AFW_COMPILE_THROW_ERROR_Z(message_z)
#define afw_pool_malloc(instance, size, xctx)
Call method malloc of interface afw_pool.
#define afw_utf8_create_copy(s, len, p, xctx)
Make a utf-8 sting from chars in pool specified.
Definition: afw_utf8.h:369
#define afw_utf8_create(s, len, p, xctx)
Create utf-8 string without copy unless necessary in pool specified.
Definition: afw_utf8.h:239
const afw_value_t * afw_value_template_definition_create(const afw_compile_value_contextual_t *contextual, afw_size_t count, const afw_value_t *const *values, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for template definition value.
afw_value_empty_string
Adaptive value empty string.
Definition: afw_value.h:342
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Interface afw_value public struct.