tree-sitter / tree-sitter-c

C grammar for tree-sitter
MIT License
223 stars 100 forks source link

Error parsing statement expressions #46

Open genotrance opened 4 years ago

genotrance commented 4 years ago

Source:

static inline void* sx__aligned_alloc(const sx_alloc* alloc, size_t size, uint32_t align,
                                      const char* file, const char* func, uint32_t line)
{
    align = ({ typeof((int)align) var__a = ((int)align); typeof(8) var__b = (8); (void)(&var__a == &var__b); var__a > 8 ? var__a : var__b; });
    const size_t total = size + align + sizeof(uint32_t);
    uint8_t* ptr = (uint8_t*)sx__malloc(alloc, total, 0, file, func, line);
    ;
    uint8_t* aligned = (uint8_t*)sx_align_ptr(ptr, sizeof(uint32_t), align);
    uint32_t* header = (uint32_t*)aligned - 1;
    *header = (uint32_t)(uintptr_t)(aligned - ptr);
    return aligned;
}

Results in error:

(translation_unit 2 1 662
 (function_definition 2 1 321
  (storage_class_specifier 2 1 6 "static")
  (storage_class_specifier 2 8 6 "inline")
  (primitive_type 2 15 4 "void")
  (pointer_declarator 2 19 160
   (function_declarator 2 21 158
    (identifier 2 21 17 "sx__aligned_alloc")
    (parameter_list 2 38 141
     (parameter_declaration 2 39 21
      (type_qualifier 2 39 5 "const")
      (type_identifier 2 45 8 "sx_alloc")
      (pointer_declarator 2 53 7
       (identifier 2 55 5 "alloc")
      )
     )
     (parameter_declaration 2 62 11
      (primitive_type 2 62 6 "size_t")
      (identifier 2 69 4 "size")
     )
     (parameter_declaration 2 75 14
      (primitive_type 2 75 8 "uint32_t")
      (identifier 2 84 5 "align")
     )
     (parameter_declaration 3 39 16
      (type_qualifier 3 39 5 "const")
      (primitive_type 3 45 4 "char")
      (pointer_declarator 3 49 6
       (identifier 3 51 4 "file")
      )
     )
     (parameter_declaration 3 57 16
      (type_qualifier 3 57 5 "const")
      (primitive_type 3 63 4 "char")
      (pointer_declarator 3 67 6
       (identifier 3 69 4 "func")
      )
     )
     (parameter_declaration 3 75 13
      (primitive_type 3 75 8 "uint32_t")
      (identifier 3 84 4 "line")
     )
    )
   )
  )
  (compound_statement 4 1 142
   (expression_statement 5 5 52
    (assignment_expression 5 5 51
     (identifier 5 5 5 "align")
     (parenthesized_expression 5 13 43
      (ERROR 5 14 20
       (call_expression 5 16 18 "typeof((int)align)"
        (identifier 5 16 6 "typeof")
        (argument_list 5 22 12 "((int)align)"
         (cast_expression 5 23 10 "(int)align"
          (type_descriptor 5 24 3 "int"
           (primitive_type 5 24 3 "int")
          )
          (identifier 5 28 5 "align")
         )
        )
       )
      )
      (assignment_expression 5 35 21
       (identifier 5 35 6 "var__a")
       (parenthesized_expression 5 44 12 "((int)align)"
        (cast_expression 5 45 10 "(int)align"
         (type_descriptor 5 46 3 "int"
          (primitive_type 5 46 3 "int")
         )
         (identifier 5 50 5 "align")
        )
       )
      )
     )
    )
   )
   (expression_statement 5 58 23
    (assignment_expression 5 58 22
     (call_expression 5 58 9 "typeof(8)"
      (identifier 5 58 6 "typeof")
      (argument_list 5 64 3 "(8)"
       (number_literal 5 65 1 "8")
      )
     )
     (ERROR 5 68 6 "var__b"
      (identifier 5 68 6 "var__b")
     )
     (parenthesized_expression 5 77 3 "(8)"
      (number_literal 5 78 1 "8")
     )
    )
   )
   (expression_statement 5 82 27
    (cast_expression 5 82 26
     (type_descriptor 5 83 4 "void"
      (primitive_type 5 83 4 "void")
     )
     (parenthesized_expression 5 88 20
      (binary_expression 5 89 18
       (pointer_expression 5 89 7 "&var__a"
        (identifier 5 90 6 "var__a")
       )
       (pointer_expression 5 100 7 "&var__b"
        (identifier 5 101 6 "var__b")
       )
      )
     )
    )
   )
   (expression_statement 5 110 29
    (conditional_expression 5 110 28
     (binary_expression 5 110 10
      (identifier 5 110 6 "var__a")
      (number_literal 5 119 1 "8")
     )
     (identifier 5 123 6 "var__a")
     (identifier 5 132 6 "var__b")
    )
   )
  )
 )
 (ERROR 5 141 1 ")")
 (expression_statement 5 142 1 ";")
 (declaration 6 5 53
  (type_qualifier 6 5 5 "const")
  (primitive_type 6 11 6 "size_t")
  (init_declarator 6 18 39
   (identifier 6 18 5 "total")
   (binary_expression 6 26 31
    (binary_expression 6 26 12
     (identifier 6 26 4 "size")
     (identifier 6 33 5 "align")
    )
    (sizeof_expression 6 41 16 "sizeof(uint32_t)"
     (type_descriptor 6 48 8 "uint32_t"
      (primitive_type 6 48 8 "uint32_t")
     )
    )
   )
  )
 )
 (declaration 7 5 71
  (primitive_type 7 5 7 "uint8_t")
  (init_declarator 7 12 63
   (pointer_declarator 7 12 5
    (identifier 7 14 3 "ptr")
   )
   (cast_expression 7 20 55
    (type_descriptor 7 21 8 "uint8_t*"
     (primitive_type 7 21 7 "uint8_t")
     (abstract_pointer_declarator 7 28 1 "*")
    )
    (call_expression 7 30 45
     (identifier 7 30 10 "sx__malloc")
     (argument_list 7 40 35
      (identifier 7 41 5 "alloc")
      (identifier 7 48 5 "total")
      (number_literal 7 55 1 "0")
      (identifier 7 58 4 "file")
      (identifier 7 64 4 "func")
      (identifier 7 70 4 "line")
     )
    )
   )
  )
 )
 (expression_statement 8 5 1 ";")
 (declaration 9 5 72
  (primitive_type 9 5 7 "uint8_t")
  (init_declarator 9 12 64
   (pointer_declarator 9 12 9
    (identifier 9 14 7 "aligned")
   )
   (cast_expression 9 24 52
    (type_descriptor 9 25 8 "uint8_t*"
     (primitive_type 9 25 7 "uint8_t")
     (abstract_pointer_declarator 9 32 1 "*")
    )
    (call_expression 9 34 42
     (identifier 9 34 12 "sx_align_ptr")
     (argument_list 9 46 30
      (identifier 9 47 3 "ptr")
      (sizeof_expression 9 52 16 "sizeof(uint32_t)"
       (type_descriptor 9 59 8 "uint32_t"
        (primitive_type 9 59 8 "uint32_t")
       )
      )
      (identifier 9 70 5 "align")
     )
    )
   )
  )
 )
 (declaration 10 5 42
  (primitive_type 10 5 8 "uint32_t")
  (init_declarator 10 13 33
   (pointer_declarator 10 13 8
    (identifier 10 15 6 "header")
   )
   (binary_expression 10 24 22
    (cast_expression 10 24 18 "(uint32_t*)aligned"
     (type_descriptor 10 25 9 "uint32_t*"
      (primitive_type 10 25 8 "uint32_t")
      (abstract_pointer_declarator 10 33 1 "*")
     )
     (identifier 10 35 7 "aligned")
    )
    (number_literal 10 45 1 "1")
   )
  )
 )
 (expression_statement 11 5 47
  (assignment_expression 11 5 46
   (pointer_expression 11 5 7 "*header"
    (identifier 11 6 6 "header")
   )
   (cast_expression 11 15 36
    (type_descriptor 11 16 8 "uint32_t"
     (primitive_type 11 16 8 "uint32_t")
    )
    (cast_expression 11 25 26
     (type_descriptor 11 26 9 "uintptr_t"
      (primitive_type 11 26 9 "uintptr_t")
     )
     (parenthesized_expression 11 36 15
      (binary_expression 11 37 13
       (identifier 11 37 7 "aligned")
       (identifier 11 47 3 "ptr")
      )
     )
    )
   )
  )
 )
 (return_statement 12 5 15
  (identifier 12 12 7 "aligned")
 )
 (ERROR 13 1 1 "}")
)

First line of function itself fails by itself.

maxbrunsfeld commented 4 years ago

Can you try to reduce this down to make it easier to identify the problem?

genotrance commented 4 years ago

The first line of the function itself fails. Reducing it even further:

align = ({ typeof((int)align) var__a = ((int)align);});
(translation_unit 2 1 57
 (expression_statement 2 1 56
  (assignment_expression 2 1 55
   (identifier 2 1 5 "align")
   (parenthesized_expression 2 9 47
    (ERROR 2 10 20
     (call_expression 2 12 18 "typeof((int)align)"
      (identifier 2 12 6 "typeof")
      (argument_list 2 18 12 "((int)align)"
       (cast_expression 2 19 10 "(int)align"
        (type_descriptor 2 20 3 "int"
         (primitive_type 2 20 3 "int")
        )
        (identifier 2 24 5 "align")
       )
      )
     )
    )
    (assignment_expression 2 31 21
     (identifier 2 31 6 "var__a")
     (parenthesized_expression 2 40 12 "((int)align)"
      (cast_expression 2 41 10 "(int)align"
       (type_descriptor 2 42 3 "int"
        (primitive_type 2 42 3 "int")
       )
       (identifier 2 46 5 "align")
      )
     )
    )
    (ERROR 2 52 3)
   )
  )
 )
)
maxbrunsfeld commented 4 years ago

That doesn’t look like standard C. What is that syntax called?

genotrance commented 4 years ago

I found this in the sx library:

align = sx_max((int)align, SX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT);

// https://github.com/septag/sx/blob/master/include/sx/allocator.h#L136

gets expanded to the following after preprocessing (gcc -E):

align = ({ typeof((int)align) var__a = ((int)align); typeof(8) var__b = (8); (void)(&var__a == &var__b); var__a > 8 ? var__a : var__b; });

This is because they define sx_max() as follows:

#ifndef __cplusplus
#    if SX_COMPILER_GCC || SX_COMPILER_CLANG
#        define sx_max(a, b)                  \
            ({                                \
                typeof(a) var__a = (a);       \
                typeof(b) var__b = (b);       \
                (void)(&var__a == &var__b);   \
                var__a > b ? var__a : var__b; \
            })

// https://github.com/septag/sx/blob/master/include/sx/sx.h#L78

Looks like a block syntax using {}, gcc doesn't mind.

dcreager commented 4 years ago

This example uses a couple of GCC extensions: typeof and statement expressions. Not sure what our policy is for supporting syntax extensions in the grammar — if we do, we should add these. typeof should be handled similarly to sizeof (i.e. it's an operator with an alphabetic name, not a standard function or macro being called).