cxxheaderparser 1.7.4__tar.gz → 1.8.0__tar.gz

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.
Files changed (23) hide show
  1. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/PKG-INFO +1 -1
  2. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/lexer.py +4 -0
  3. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/parser.py +88 -14
  4. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/types.py +11 -5
  5. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/version.py +2 -2
  6. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/.gitignore +0 -0
  7. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/LICENSE.txt +0 -0
  8. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/README.md +0 -0
  9. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/__init__.py +0 -0
  10. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/__main__.py +0 -0
  11. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/_ply/__init__.py +0 -0
  12. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/_ply/lex.py +0 -0
  13. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/dump.py +0 -0
  14. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/errors.py +0 -0
  15. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/gentest.py +0 -0
  16. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/options.py +0 -0
  17. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/parserstate.py +0 -0
  18. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/preprocessor.py +0 -0
  19. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/py.typed +0 -0
  20. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/simple.py +0 -0
  21. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/tokfmt.py +0 -0
  22. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/cxxheaderparser/visitor.py +0 -0
  23. {cxxheaderparser-1.7.4 → cxxheaderparser-1.8.0}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cxxheaderparser
3
- Version: 1.7.4
3
+ Version: 1.8.0
4
4
  Summary: Modern C++ header parser
5
5
  Project-URL: Source code, https://github.com/robotpy/cxxheaderparser
6
6
  Author-email: Dustin Spicuzza <robotpy@googlegroups.com>
@@ -111,6 +111,10 @@ class PlyLexer:
111
111
  "__inline",
112
112
  "inline",
113
113
  "int",
114
+ "__int8",
115
+ "__int16",
116
+ "__int32",
117
+ "__int64",
114
118
  "long",
115
119
  "mutable",
116
120
  "namespace",
@@ -273,6 +273,40 @@ class CxxParser:
273
273
  if next_end:
274
274
  match_stack.append(next_end)
275
275
 
276
+ def _consume_balanced_tokens_with_inner(
277
+ self,
278
+ *init_tokens: LexToken,
279
+ token_map: typing.Optional[typing.Dict[str, str]] = None,
280
+ ) -> typing.Tuple[LexTokenList, LexTokenList]:
281
+ toks = self._consume_balanced_tokens(*init_tokens, token_map=token_map)
282
+ inner_toks = toks[1:-1]
283
+
284
+ # Redundant declarator grouping is valid: int ((*p))(int),
285
+ # int ((*p))[3], and void ((f))(int). Strip only parens that
286
+ # enclose the whole inner token list.
287
+ while (
288
+ len(inner_toks) >= 2
289
+ and inner_toks[0].type == "("
290
+ and inner_toks[-1].type == ")"
291
+ ):
292
+ depth = 0
293
+ encloses_all = True
294
+ for i, itok in enumerate(inner_toks):
295
+ if itok.type == "(":
296
+ depth += 1
297
+ elif itok.type == ")":
298
+ depth -= 1
299
+ if depth == 0 and i != len(inner_toks) - 1:
300
+ encloses_all = False
301
+ break
302
+
303
+ if not encloses_all or depth != 0:
304
+ break
305
+
306
+ inner_toks = inner_toks[1:-1]
307
+
308
+ return toks, inner_toks
309
+
276
310
  def _discard_contents(self, start_type: str, end_type: str) -> None:
277
311
  # use this instead of consume_balanced_tokens because
278
312
  # we don't care at all about the internals
@@ -1677,6 +1711,10 @@ class CxxParser:
1677
1711
  "float",
1678
1712
  "double",
1679
1713
  "char",
1714
+ "__int8",
1715
+ "__int16",
1716
+ "__int32",
1717
+ "__int64",
1680
1718
  }
1681
1719
 
1682
1720
  _fundamentals = _compound_fundamentals | {
@@ -1967,6 +2005,14 @@ class CxxParser:
1967
2005
  if tok:
1968
2006
  param_name = tok.value
1969
2007
 
2008
+ # Function parameter declarations can use function declarator syntax,
2009
+ # e.g. ``bool predicate(const T&)``. In parameter lists, function types
2010
+ # are adjusted to pointers to functions, matching the explicit
2011
+ # ``bool (*predicate)(const T&)`` spelling.
2012
+ if param_name and self.lex.token_if("("):
2013
+ fn_params, vararg, _ = self._parse_parameters(False, False)
2014
+ dtype = Pointer(FunctionType(dtype, fn_params, vararg))
2015
+
1970
2016
  # optional array parameter
1971
2017
  tok = self.lex.token_if("[")
1972
2018
  if tok:
@@ -2460,8 +2506,8 @@ class CxxParser:
2460
2506
  if not gtok:
2461
2507
  break
2462
2508
 
2463
- toks = self._consume_balanced_tokens(gtok)
2464
- self.lex.return_tokens(toks[1:-1])
2509
+ _, inner_toks = self._consume_balanced_tokens_with_inner(gtok)
2510
+ self.lex.return_tokens(inner_toks)
2465
2511
 
2466
2512
  fn_params, vararg, _ = self._parse_parameters(False, False)
2467
2513
 
@@ -2478,14 +2524,26 @@ class CxxParser:
2478
2524
  if msvc_convention_tok:
2479
2525
  msvc_convention = msvc_convention_tok.value
2480
2526
 
2527
+ # this might be a grouping paren, so consume it and inspect it
2528
+ toks, inner_toks = self._consume_balanced_tokens_with_inner(tok)
2529
+ member_ptr_idx = next(
2530
+ (
2531
+ i
2532
+ for i, itok in enumerate(inner_toks)
2533
+ if itok.type == "*"
2534
+ and i > 0
2535
+ and inner_toks[i - 1].type == "DBL_COLON"
2536
+ ),
2537
+ None,
2538
+ )
2539
+
2481
2540
  # Check to see if this is a grouping paren or something else
2482
- if not self.lex.token_peek_if("*", "&"):
2483
- self.lex.return_token(tok)
2541
+ if not inner_toks or (
2542
+ inner_toks[0].type not in ("*", "&") and member_ptr_idx is None
2543
+ ):
2544
+ self.lex.return_tokens(toks)
2484
2545
  break
2485
2546
 
2486
- # this is a grouping paren, so consume it
2487
- toks = self._consume_balanced_tokens(tok)
2488
-
2489
2547
  # Now check to see if we have either an array or a function pointer
2490
2548
  aptok = self.lex.token_if("[", "(")
2491
2549
  if aptok:
@@ -2502,14 +2560,30 @@ class CxxParser:
2502
2560
  dtype, fn_params, vararg, msvc_convention=msvc_convention
2503
2561
  )
2504
2562
 
2505
- # the inner tokens must either be a * or a pqname that ends
2506
- # with ::* (member function pointer)
2507
- # ... TODO member function pointer :(
2563
+ if isinstance(dtype, FunctionType) and member_ptr_idx is not None:
2564
+ # Keep the * and declarator name for the normal pointer/name
2565
+ # parsing below, and store the qualified class name on the
2566
+ # function type.
2567
+ class_toks = inner_toks[: member_ptr_idx - 1] + [PhonyEnding]
2568
+ old_lex = self.lex
2569
+ try:
2570
+ self.lex = lexer.BoundedTokenStream(class_toks)
2571
+ classname, _ = self._parse_pqname(
2572
+ None, compound_ok=False, fn_ok=False, fund_ok=False
2573
+ )
2574
+ self._next_token_must_be(PhonyEnding.type)
2575
+ finally:
2576
+ self.lex = old_lex
2577
+
2578
+ dtype.classname = classname
2579
+ inner_toks = [inner_toks[member_ptr_idx]] + inner_toks[
2580
+ member_ptr_idx + 1 :
2581
+ ]
2508
2582
 
2509
2583
  # return the inner toks and recurse
2510
2584
  # -> this could return some weird results for invalid code, but
2511
2585
  # we don't support that anyways so it's fine?
2512
- self.lex.return_tokens(toks[1:-1])
2586
+ self.lex.return_tokens(inner_toks)
2513
2587
  dtype = self._parse_cv_ptr_or_fn(dtype, nonptr_fn)
2514
2588
  break
2515
2589
 
@@ -2668,7 +2742,7 @@ class CxxParser:
2668
2742
  is_friend: bool,
2669
2743
  attributes: typing.List[Attribute],
2670
2744
  ) -> bool:
2671
- toks = []
2745
+ toks: LexTokenList = []
2672
2746
 
2673
2747
  # On entry we only have the base type, decorate it
2674
2748
  dtype: typing.Optional[DecoratedType]
@@ -2730,7 +2804,7 @@ class CxxParser:
2730
2804
  if dtype:
2731
2805
  # if it's not a constructor/destructor, it could be a
2732
2806
  # grouping paren like "void (name(int x));"
2733
- toks = self._consume_balanced_tokens(tok)
2807
+ toks, inner_toks = self._consume_balanced_tokens_with_inner(tok)
2734
2808
 
2735
2809
  # check to see if the next token is an arrow, and thus a trailing return
2736
2810
  if self.lex.token_peek_if("ARROW"):
@@ -2740,7 +2814,7 @@ class CxxParser:
2740
2814
  is_guide = True
2741
2815
  else:
2742
2816
  # .. not sure what it's grouping, so put it back?
2743
- self.lex.return_tokens(toks[1:-1])
2817
+ self.lex.return_tokens(inner_toks)
2744
2818
 
2745
2819
  if dtype:
2746
2820
  msvc_convention = self.lex.token_if_val(*self._msvc_conventions)
@@ -272,9 +272,6 @@ class FunctionType:
272
272
  return_type: "DecoratedType"
273
273
  parameters: typing.List["Parameter"]
274
274
 
275
- #: If a member function pointer
276
- # TODO classname: typing.Optional[PQName]
277
-
278
275
  #: Set to True if ends with ``...``
279
276
  vararg: bool = False
280
277
 
@@ -293,6 +290,9 @@ class FunctionType:
293
290
  #: calling convention
294
291
  msvc_convention: typing.Optional[str] = None
295
292
 
293
+ #: If a member function pointer, the class that owns the member function.
294
+ classname: typing.Optional[PQName] = None
295
+
296
296
  def format(self) -> str:
297
297
  vararg = "..." if self.vararg else ""
298
298
  params = ", ".join(p.format() for p in self.parameters)
@@ -379,7 +379,9 @@ class Pointer:
379
379
  v = " volatile" if self.volatile else ""
380
380
  r = " __restrict__" if self.restrict else ""
381
381
  ptr_to = self.ptr_to
382
- if isinstance(ptr_to, (Array, FunctionType)):
382
+ if isinstance(ptr_to, FunctionType) and ptr_to.classname:
383
+ return ptr_to.format_decl(f"({ptr_to.classname.format()}::*{r}{c}{v})")
384
+ elif isinstance(ptr_to, (Array, FunctionType)):
383
385
  return ptr_to.format_decl(f"(*{r}{c}{v})")
384
386
  else:
385
387
  return f"{ptr_to.format()}*{r}{c}{v}"
@@ -390,7 +392,11 @@ class Pointer:
390
392
  v = " volatile" if self.volatile else ""
391
393
  r = " __restrict__" if self.restrict else ""
392
394
  ptr_to = self.ptr_to
393
- if isinstance(ptr_to, (Array, FunctionType)):
395
+ if isinstance(ptr_to, FunctionType) and ptr_to.classname:
396
+ return ptr_to.format_decl(
397
+ f"({ptr_to.classname.format()}::*{r}{c}{v} {name})"
398
+ )
399
+ elif isinstance(ptr_to, (Array, FunctionType)):
394
400
  return ptr_to.format_decl(f"(*{r}{c}{v} {name})")
395
401
  else:
396
402
  return f"{ptr_to.format()}*{r}{c}{v} {name}"
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '1.7.4'
22
- __version_tuple__ = version_tuple = (1, 7, 4)
21
+ __version__ = version = '1.8.0'
22
+ __version_tuple__ = version_tuple = (1, 8, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None