Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_compile_parse_value.c
Go to the documentation of this file.
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  *# Expression must produce a value of data type list.
21  * ListExpression ::= Expression
22  *
23  * List ::=
24  * '['
25  * ( Json (',' Json)* )?
26  * ']'
27  *
28  * RelaxedList ::=
29  * '['
30  * ( RelaxedJson (',' RelaxedJson)* )? ','?
31  * ']'
32  *
33  * ListLiteral ::=
34  * '['
35  * ( Literal (',' Literal )* )? ','?
36  * ']'
37  *
38  * ListValue ::=
39  * '['
40  * (
41  * ( Expression | ( '...' ListExpression ) )
42  * (',' ( Expression | ( '...' ListExpression ) ) )*
43  * )?
44  * ','?
45  * ']'
46  *
47  *<<<ebnf*/
48 /* Parse a JSON array. Input cursor must point to a [. */
50 afw_compile_parse_List(
51  afw_compile_parser_t *parser,
52  afw_boolean_t allow_expression,
53  afw_boolean_t allow_enhanced_literals)
54 {
55  const afw_list_t *list;
56  const afw_value_t *entry;
57  const afw_value_t *value;
58  const afw_value_t *result;
59  afw_compile_args_t *args;
60  const afw_value_t **argv;
61  afw_size_t argc;
62  afw_size_t start_offset;
63  const afw_iterator_t *iterator;
64 
65  /* Return NULL if next token is not '['. */
66  afw_compile_save_cursor(start_offset);
67  afw_compile_get_token();
68  if (!afw_compile_token_is(open_bracket)) {
69  afw_compile_reuse_token();
70  return NULL;
71  }
72 
73  /* Create result list. */
74  list = NULL;
75  args = NULL;
76 
77  /* Process array values until ']'. */
78  afw_compile_get_token();
79  if (!afw_compile_token_is(close_bracket)) {
80  afw_compile_reuse_token();
81  for (;;) {
82 
83  /* Spread operator. */
84  afw_compile_get_token();
85  if (allow_expression && afw_compile_token_is(ellipsis)) {
86  if ((parser)->compile_type == afw_compile_type_json ||
87  (parser)->compile_type == afw_compile_type_relaxed_json)
88  {
90  "'...' is not allowed as json list entry");
91  }
92 
93  /* Entry is list expression. */
95  afw_compile_create_contextual_to_cursor(start_offset),
96  afw_compile_parse_Expression(parser),
97  parser->p, parser->xctx);
98  }
99 
100  /* Not spread operator. */
101  else {
102  afw_compile_reuse_token();
103 
104  /* Next should be a value. */
105  if (allow_expression) {
106  entry = afw_compile_parse_Expression(parser);
107  }
108  else if (allow_enhanced_literals) {
109  entry = afw_compile_parse_Literal(parser,
110  NULL, true, false);
111  }
112  else {
113  entry = afw_compile_parse_Json(parser);
114  }
115  }
116 
117  /*
118  * If not already building list constructor and this is not an
119  * evaluated value, start building its args.
120  */
121  if (!args && !afw_value_is_defined_and_evaluated(entry)) {
122  args = afw_compile_args_create(parser);
123  afw_compile_args_add_value(args,
125 
126  /* Add previous list entries as args for constructor. */
127  if (list) {
128  for (iterator = NULL;;) {
129  value = afw_list_get_next_value(list, &iterator,
130  parser->p, parser->xctx);
131  if (!value) {
132  break;
133  }
134  afw_compile_args_add_value(args, value);
135  }
136  }
137  list = NULL;
138  }
139 
140  /* If building constructor, add entry as arg. */
141  if (args) {
142  afw_compile_args_add_value(args, entry);
143  }
144 
145  /* If all values so far are evaluated, add entry to list. */
146  else {
147  if (!list) {
148  list = afw_list_create_generic(parser->p, parser->xctx);
149  }
150 
151  /* Add value to list. */
152  afw_list_add_value(list, entry, parser->xctx);
153  }
154 
155  /*
156  * If next token is ',' continue if strict mode or next tokens is
157  * not ']'.
158  */
159  afw_compile_get_token();
160  if (afw_compile_token_is(comma)) {
161  if (!parser->strict) {
162  afw_compile_get_token();
163  if (afw_compile_token_is(close_bracket)) {
164  break;
165  }
166  afw_compile_reuse_token();
167  }
168  continue;
169  }
170 
171  /* Or if it is a ']', it's end of array. */
172  if (afw_compile_token_is(close_bracket)) {
173  break;
174  }
175 
176  /* Anything else is an error. */
178  "Array values must be separated with a comma");
179  }
180  }
181 
182  /* If there is a spread, a result is call to add_entries(). */
183  if (args) {
184  afw_compile_args_finalize(args, &argc, &argv);
186  afw_compile_create_contextual_to_cursor(start_offset),
187  argc - 1, argv, parser->p, parser->xctx);
188  }
189 
190  /* Else if no entries yet, result is empty list. */
191  else if (!list) {
192  list = afw_list_create_generic(parser->p, parser->xctx);
193  result = afw_value_create_list(list, parser->p, parser->xctx);
194  }
195 
196  /* Else result is an evaluated list value. */
197  else {
198  result = afw_value_create_list(list, parser->p, parser->xctx);
199  }
200 
201  /* Return list value or call to add_entries. */
202  return result;
203 }
204 
205 
206 
207 /*ebnf>>>
208  *
209  *# Expression must produce a value of data type object.
210  * ObjectExpression ::= Expression
211  *
212  * Object ::=
213  * '{'
214  * (
215  * ( String ':' Json )
216  * (',' String ':' Json )*
217  * )?
218  * '}'
219  *
220  * RelaxedObject ::=
221  * '{'
222  * (
223  * ( ( String | Identifier ) ':' RelaxedJson )
224  * (',' ( String | Identifier ) ':' RelaxedJson )*
225  * ','?
226  * )?
227  * ','?
228  * '}'
229  *
230  * ObjectLiteral ::=
231  * '{'
232  * (
233  * ( ( String | Identifier ) ':' Literal )
234  * ( ',' ( String | Identifier ) ':' Literal )*
235  * )?
236  * ','?
237  * '}'
238  *
239  * ObjectValue ::=
240  * '{'
241  * (
242  * (
243  * ( ( String | Identifier ) ':' Expression ) |
244  * ('...' ObjectExpression )
245  * )
246  * ( ','
247  * (
248  * ( ( String | Identifier ) ':' Expression ) |
249  * ('...' ObjectExpression )
250  * )
251  * )*
252  * )?
253  * ','?
254  * '}'
255  *
256  *
257  *<<<ebnf*/
259 afw_compile_parse_Object(
260  afw_compile_parser_t *parser,
261  afw_boolean_t allow_expression,
262  afw_boolean_t allow_enhanced_literals)
263 {
264  const afw_object_t *obj;
265  const afw_value_t *v;
266  const afw_object_t *embedding_object;
267  const afw_utf8_t *property_name;
268  const afw_object_t *_meta_;
269  afw_compile_args_t *args;
270  const afw_value_t **argv;
271  const afw_value_t *result;
272  afw_size_t argc;
273  afw_size_t start_offset;
274  afw_boolean_t save_doing_object_spread;
275  afw_boolean_t is_object_expression;
276 
277  /* Return NULL if next token is not '{'. */
278  afw_compile_save_cursor(start_offset);
279  afw_compile_get_token();
280  if (!afw_compile_token_is(open_brace)) {
281  afw_compile_reuse_token();
282  return NULL;
283  }
284 
285  /* Create new memory object.*/
287  obj,
288  parser->embedding_object,
289  parser->property_name,
290  parser->doing_object_spread,
291  parser->cede_p, parser->p, parser->xctx);
292  _meta_ = NULL;
293  args = NULL;
294  result = NULL;
295  is_object_expression = false;
296 
297  /*
298  * Save parser->embedding_object and set to new object.
299  *
300  * Save parser->property_name and set to NULL.
301  */
302  embedding_object = parser->embedding_object;
303  parser->embedding_object = obj;
304  property_name = parser->property_name;
305  parser->property_name = NULL;
306 
307  /* Process name/value pairs until '}'. */
308  afw_compile_get_token();
309  if (!afw_compile_token_is(close_brace)) {
310  afw_compile_reuse_token();
311  for (;;) {
312 
313  afw_compile_get_token();
314  parser->property_name = NULL;
315 
316  if (parser->strict) {
317  if (afw_compile_token_is(utf8_string) &&
318  parser->token->string_quote_character == '"')
319  {
320  parser->property_name = parser->token->string;
321  }
322  }
323 
324  else if (afw_compile_token_is(utf8_string)) {
325  parser->property_name = parser->token->string;
326  }
327 
328  else if (afw_compile_token_is(identifier) &&
329  !parser->token->identifier_qualifier)
330  {
331  parser->property_name = parser->token->identifier_name;
332  }
333 
334  /* If spread operator. */
335  if (allow_expression && afw_compile_token_is(ellipsis)) {
336 
337  /*
338  * If this is first spread, start making args for add_entries().
339  */
340  if (!args) {
341  args = afw_compile_args_create(parser);
342  afw_compile_args_add_value(args,
344  if (is_object_expression) {
346  afw_compile_create_contextual_to_cursor(start_offset),
347  obj, parser->p, parser->xctx);
348  }
349  else {
350  result = afw_value_create_object(obj, parser->p, parser->xctx);
351  }
352  afw_compile_args_add_value(args, result);
353  is_object_expression = false;
354  }
355 
356  /* Add spread object expression to args. */
357  save_doing_object_spread = parser->doing_object_spread;
358  parser->doing_object_spread = true;
359  v = afw_compile_parse_Expression(parser);
360  parser->doing_object_spread = save_doing_object_spread;
361  afw_compile_args_add_value(args, v);
362 
363  /* A new object will be started if needed. */
364  obj = NULL;
365  }
366 
367  /* If not spread */
368  else {
369  if (!parser->property_name) {
370  AFW_COMPILE_THROW_ERROR_Z("Invalid property name");
371  }
372 
373  /* Next should be a colon. */
374  afw_compile_get_token();
375  if (!afw_compile_token_is(colon)) {
377  "Name of an object value must be followed by a colon");
378  }
379 
380  /* Next should be a value. */
381  if (allow_expression) {
382  v = afw_compile_parse_Expression(parser);
383  }
384  else if (allow_enhanced_literals) {
385  v = afw_compile_parse_Literal(parser,
386  NULL, true, false);
387  }
388  else {
389  v = afw_compile_parse_Json(parser);
390  }
391 
392  /* If this is _meta_ property, set meta in object. */
393  if (afw_utf8_equal(parser->property_name, &afw_s__meta_)) {
394  if (!afw_value_is_object(v)) {
396  "_meta_ property must be an object");
397  }
398  _meta_ = ((const afw_value_object_t *)v)->internal;
399  }
400 
401  /*
402  * If not _meta_ property, set property in new object to this
403  * value if it's not an object. Object will already have been
404  * added by afw_object_create_embedded().
405  */
406  else if (!afw_value_is_object(v)) {
407  if (!obj) {
408  obj = afw_object_create(
409  parser->p, parser->xctx);
410  afw_compile_args_add_value(args,
412  parser->p, parser->xctx));
413  }
414  afw_object_set_property(obj, parser->property_name, v,
415  parser->xctx);
417  is_object_expression = true;
418  }
419  }
420 
421  }
422 
423  /*
424  * If next token is ',' continue if strict mode or next tokens is
425  * not '}'.
426  */
427  afw_compile_get_token();
428  if (afw_compile_token_is(comma)) {
429  if (!parser->strict) {
430  afw_compile_get_token();
431  if (afw_compile_token_is(close_brace)) {
432  break;
433  }
434  afw_compile_reuse_token();
435  }
436  continue;
437  }
438 
439  /* Or if it is '}', it's end of object. */
440  if (afw_compile_token_is(close_brace)) break;
441 
442  /* Anything else is an error. */
444  "Name/Value pairs must be separated with a comma");
445  }
446  }
447 
448  /* If there were spread operators, result is call to add_properties(). */
449  if (args) {
450  afw_compile_args_finalize(args, &argc, &argv);
452  afw_compile_create_contextual_to_cursor(start_offset),
453  argc - 1, argv, parser->p, parser->xctx);
454  }
455 
456  /* Else if object expression, result is object expression value. */
457  else if (is_object_expression) {
459  afw_compile_create_contextual_to_cursor(start_offset),
460  obj, parser->p, parser->xctx);
461  }
462 
463  /* Else result is object value. */
464  else {
465  afw_object_meta_set_meta_object(obj, _meta_, parser->xctx);
466  result = afw_value_create_object(obj, parser->p, parser->xctx);
467  }
468 
469  /* Restore saved embedding object and property name. */
470  parser->embedding_object = embedding_object;
471  parser->property_name = property_name;
472 
473  /* Return object value. */
474  return result;
475 }
476 
477 
478 
479 /*ebnf>>>
480  *
481  * Json ::= Double | Integer | List | Object | String | 'true' | 'false' | 'null'
482  *
483  * RelaxedJson ::= Double | Integer | RelaxedList | RelaxedObject | String | 'true' | 'false' | 'null'
484  *
485  *<<<ebnf*/
487 afw_compile_parse_Json(afw_compile_parser_t *parser)
488 {
489  /* parser->strict false causes RelaxedJson to be used. */
490 
491  const afw_value_t *value = NULL;
492 
493  afw_compile_get_token();
494 
495  switch (parser->token->type) {
496 
497  case afw_compile_token_type_end:
498  AFW_COMPILE_THROW_ERROR_Z("Expecting Value");
499 
500  case afw_compile_token_type_open_brace:
501  afw_compile_reuse_token();
502  value = afw_compile_parse_Object(parser, false, false);
503  break;
504 
505  case afw_compile_token_type_open_bracket:
506  afw_compile_reuse_token();
507  value = afw_compile_parse_List(parser, false, false);
508  break;
509 
510  case afw_compile_token_type_boolean:
511  value = (parser->token->boolean)
513  : afw_value_false;
514  break;
515 
516  case afw_compile_token_type_integer:
517  value = afw_value_create_integer(
518  parser->token->integer,
519  parser->p, parser->xctx);
520  break;
521 
522  case afw_compile_token_type_number:
523  value = afw_value_create_double(
524  parser->token->number,
525  parser->p, parser->xctx);
526  break;
527 
528  case afw_compile_token_type_utf8_string:
529  value = afw_value_create_string(parser->token->string,
530  parser->p, parser->xctx);
531  break;
532 
533  case afw_compile_token_type_null:
534  value = afw_value_null;
535  break;
536 
537  case afw_compile_token_type_invalid:
538  default:
539  AFW_COMPILE_THROW_ERROR_Z("Invalid token type");
540  }
541 
542  /* If value was not assigned, reuse token. */
543  if (!value) {
544  afw_compile_reuse_token();
545  }
546 
547  /* Return value. */
548  return value;
549 }
550 
551 
552 /*ebnf>>>
553  *
554  * ScalarLiteral ::= Double | Integer | String | 'true' | 'false' | 'null'
555  *
556  *# This may want to include Datatype(Literal) at some point too.
557  * Literal ::= ListLiteral | ObjectLiteral | ScalarLiteral | 'undefined'
558  *
559  *<<<ebnf*/
561 afw_compile_parse_Literal(
562  afw_compile_parser_t *parser,
563  afw_boolean_t *is_Literal,
564  afw_boolean_t must_be_literal,
565  afw_boolean_t scalar_only)
566 {
567  const afw_value_t *value;
568  afw_boolean_t matches_production;
569 
570  matches_production = false;
571  value = NULL;
572 
573  afw_compile_get_token();
574 
575  switch (parser->token->type) {
576 
577  case afw_compile_token_type_end:
578  AFW_COMPILE_THROW_ERROR_Z("Expecting Value");
579 
580  case afw_compile_token_type_open_brace:
581  afw_compile_reuse_token();
582  if (scalar_only) {
583  break;
584  }
585  matches_production = true;
586  value = afw_compile_parse_Object(parser, false, true);
587  break;
588 
589  case afw_compile_token_type_open_bracket:
590  afw_compile_reuse_token();
591  if (scalar_only) {
592  break;
593  }
594  matches_production = true;
595  value = afw_compile_parse_List(parser, false, true);
596  break;
597 
598  case afw_compile_token_type_boolean:
599  matches_production = true;
600  value = (parser->token->boolean)
602  : afw_value_false;
603  break;
604 
605  case afw_compile_token_type_integer:
606  matches_production = true;
607  value = afw_value_create_integer(
608  parser->token->integer,
609  parser->p, parser->xctx);
610  break;
611 
612  case afw_compile_token_type_number:
613  matches_production = true;
614  value = afw_value_create_double(
615  parser->token->number,
616  parser->p, parser->xctx);
617  break;
618 
619  case afw_compile_token_type_utf8_string:
620  matches_production = true;
621  value = afw_value_create_string(parser->token->string,
622  parser->p, parser->xctx);
623  break;
624 
625  case afw_compile_token_type_null:
626  matches_production = true;
627  value = afw_value_null;
628  break;
629 
630  case afw_compile_token_type_undefined:
631  matches_production = true;
632  value = NULL;
633  break;
634 
635  default:
636  break;
637  }
638 
639  /* If requested, return is_literal. */
640  if (is_Literal) {
641  *is_Literal = matches_production;
642  }
643 
644  /* If must be Literal, throw error if it's not. */
645  if (must_be_literal && !matches_production) {
646  AFW_COMPILE_THROW_ERROR_Z("Expecting a literal");
647  }
648 
649  /* If doesn't match production, reuse token. */
650  if (!matches_production) {
651  afw_compile_reuse_token();
652  }
653 
654  /* Return value. */
655  return value;
656 }
657 
658 
659 
660 /*ebnf>>>
661  *
662  *#
663  *# Evaluation must be before ParenthesizedExpression so Lambda has first shot
664  *# at parenthesis.
665  *#
666  *
667  * Value ::= ListValue |
668  * ObjectValue |
669  * ScalarLiteral |
670  * Evaluation |
671  * ParenthesizedExpression |
672  * TemplateString
673  *
674  *<<<ebnf*/
676 afw_compile_parse_Value(afw_compile_parser_t *parser)
677 {
678  const afw_value_t *value = NULL;
679  afw_boolean_t is_Literal;
680 
681  /* If ListValue, return its value. */
682  value = afw_compile_parse_List(parser, true, true);
683  if (value) {
684  return value;
685  }
686 
687  /* If ObjectValue, return its value. */
688  value = afw_compile_parse_Object(parser, true, true);
689  if (value) {
690  return value;
691  }
692 
693  /* If ScalarLiteral, return its value. */
694  value = afw_compile_parse_Literal(parser, &is_Literal, false, true);
695  if (is_Literal) {
696  return value;
697  }
698 
699  /* If evaluation, return its value. */
700  value = afw_compile_parse_Evaluation(parser);
701  if (value) {
702  return value;
703  }
704 
705  /* If next is '(', parse ParenthesizedExpression. */
706  if (afw_compile_peek_next_token_is(open_parenthesis)) {
707  value = afw_compile_parse_ParenthesizedExpression(parser);
708  return value;
709  }
710 
711  /* If next is '`', parse TemplateString. */
712  if (afw_compile_peek_next_token_is(grave)) {
713  value = afw_compile_parse_TemplateString(parser);
714  return value;
715  }
716 
717  /* Invalid. */
718  AFW_COMPILE_THROW_ERROR_Z("Expecting Value");
719 }
#define AFW_DEFINE_INTERNAL(type)
Define an internal function for /src/afw/ source*.c files.
Adaptive Framework Core Internal.
afw_value_create_double(double internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type double value.
afw_value_create_integer(afw_integer_t internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type integer value.
afw_value_create_list(const afw_list_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type list value.
#define afw_value_is_object(A_VALUE)
Macro to determine if value is evaluated object.
afw_value_create_object(const afw_object_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type object value.
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.
struct afw_iterator_s afw_iterator_t
_Bool afw_boolean_t
Definition: afw_common.h:373
struct afw_compile_internal_args_s afw_compile_args_t
apr_size_t afw_size_t
size_t.
Definition: afw_common.h:151
#define AFW_COMPILE_THROW_ERROR_Z(message_z)
afw_function_definition_list
Adaptive Function length<list>
afw_function_definition_add_properties
Function definition add_properties.
#define afw_list_get_next_value(instance, iterator, p, xctx)
Call method get_next_value of interface afw_list.
#define afw_list_create_generic(p, xctx)
Create an value list in memory.
Definition: afw_list.h:81
afw_list_add_value(const afw_list_t *instance, const afw_value_t *value, afw_xctx_t *xctx)
Call method add_value of interface afw_list_setter.
Definition: afw_list.c:104
afw_object_meta_set_meta_object(const afw_object_t *instance, const afw_object_t *meta, afw_xctx_t *xctx)
Set an object's meta from a meta object.
#define AFW_OBJECT_CREATE_ENTITY_OR_EMBEDDED(result, embedding_object, property_name, always_create_unmanaged, cede_p, entity_p, xctx)
Helper macro to create a new entity or embedded object.
Definition: afw_object.h:1015
#define afw_object_create(p, xctx)
Create an empty unmanaged object in memory.
Definition: afw_object.h:948
afw_object_set_property(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_value_t *value, afw_xctx_t *xctx)
Set the value of an object's property.
Definition: afw_object.c:46
afw_boolean_t afw_utf8_equal(const afw_utf8_t *s1, const afw_utf8_t *s2)
Check to see if a string equals another string.
afw_value_create_list_expression(const afw_compile_value_contextual_t *contextual, const afw_value_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for list expression value.
afw_value_false
Adaptive value false.
Definition: afw_value.h:354
#define afw_value_is_defined_and_evaluated(A_VALUE)
Macro to determine if value is defined and evaluated.
Definition: afw_value.h:481
const afw_value_t * afw_value_call_built_in_function_create(const afw_compile_value_contextual_t *contextual, afw_size_t argc, const afw_value_t *const *argv, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for call_built_in_function value.
afw_value_null
Adaptive value null.
Definition: afw_value.h:320
afw_value_create_object_expression(const afw_compile_value_contextual_t *contextual, const afw_object_t *internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for object expression value.
afw_value_true
Adaptive value true.
Definition: afw_value.h:348
Interface afw_list public struct.
Interface afw_object public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
struct for data type object values.
Interface afw_value public struct.