@@ -277,6 +277,26 @@ private List<TopLevelItem> parseTopLevelItem(List<CppLexerToken> leadingComments
277277 }
278278
279279 List <String > templateParams = List .of ();
280+ // extern "C" / extern "C++" linkage specification -- consume verbatim
281+ if (checkKeyword ("extern" ) && pos + 1 < tokens .size ()
282+ && tokens .get (pos + 1 ).type () == CppLexerTokenType .STRING_LITERAL ) {
283+ advance (); advance (); // consume extern "C++"
284+ if (checkPunct ("{" )) {
285+ // extern "C++" { ... } block -- parse contents as top-level items
286+ advance (); // consume {
287+ List <TopLevelItem > result = new ArrayList <>();
288+ while (!isAtEnd () && !checkPunct ("}" )) {
289+ List <CppLexerToken > innerComments = consumeLeadingComments ();
290+ if (checkPunct ("}" )) break ;
291+ result .addAll (parseTopLevelItem (innerComments ));
292+ }
293+ matchPunct ("}" );
294+ return result ;
295+ } else {
296+ // extern "C++" single-declaration
297+ return parseTopLevelItem (leadingComments );
298+ }
299+ }
280300 if (matchKeyword ("template" )) {
281301 // Explicit template instantiation: "template class Foo<int>;" (no < after template)
282302 if (!checkOp ("<" )) {
@@ -684,22 +704,33 @@ private TypeDef parseTypeDef(List<CppLexerToken> leadingComments, List<String> t
684704 CppLexerToken start = peek ();
685705 String kind = checkKeyword ("class" ) ? "class" : "struct" ;
686706 advance ();
707+ // alignas specifier: "struct alignas(64) CacheLine"
708+ if (checkKeyword ("alignas" ) && pos + 1 < tokens .size () && tokens .get (pos + 1 ).isPunct ("(" )) {
709+ advance (); advance (); int _ad =1 ;
710+ while (!isAtEnd () && _ad > 0 ) { if (checkPunct ("(" )) _ad ++; else if (checkPunct (")" )) _ad --; advance (); }
711+ }
712+ // Also consume [[attributes]] before the name
713+ consumeAttributes ();
687714 String name = expectIdentifier ().text ();
688715
689716 // Partial or explicit specialization: "template<typename T> struct Foo<T*>"
690717 // or "template<> struct TypeName<int>" -- capture the specialization arg
691718 // text and fold it into the name so CodeGen emits "TypeName<int>" correctly.
692- if (checkOp ("<" ) && looksLikeTemplateArgList ()) {
719+ if (checkOp ("<" )) {
720+ // Specialization args: "Foo<T, N, false>" -- scan to matching > manually
693721 int argStart = pos ;
694- try { parseTemplateArgList (); } catch (ParseException ignored ) {}
722+ advance (); // consume <
723+ int depth = 1 ;
724+ while (!isAtEnd () && depth > 0 ) {
725+ if (checkOp ("<" )) { depth ++; advance (); }
726+ else if (checkOp (">" )) { depth --; if (depth > 0 ) advance (); else advance (); }
727+ else if (checkOp (">>" )) { depth -= 2 ; splitTrailingShiftIntoTwoCloseAngles (); if (depth > 0 ) advance (); else advance (); }
728+ else advance ();
729+ }
695730 int argEnd = pos ;
696731 // Reconstruct the specialization suffix verbatim from tokens
697- StringBuilder spec = new StringBuilder ("<" );
698- for (int i = argStart + 1 ; i < argEnd - 1 ; i ++) {
699- if (i > argStart + 1 ) spec .append (tokens .get (i -1 ).text ().matches ("[<>:,(]" ) ? "" : " " );
700- spec .append (tokens .get (i ).text ());
701- }
702- spec .append (">" );
732+ StringBuilder spec = new StringBuilder ();
733+ for (int i = argStart ; i < argEnd ; i ++) spec .append (tokens .get (i ).text ());
703734 name = name + spec .toString ();
704735 }
705736
@@ -849,6 +880,34 @@ private List<TopLevelItem> parseClassMember(List<CppLexerToken> leadingComments,
849880 // Constructor dispatch: identifier matching the enclosing class name,
850881 // directly followed by '(' with no return type preceding it.
851882 // Also handle "constexpr ClassName(...)" -- consume constexpr first.
883+ // friend declaration: "friend class Foo;" or "friend Box<U> makeBox(U v);"
884+ if (checkKeyword ("friend" )) {
885+ int startPos = pos ; advance (); // consume friend
886+ // Consume to ; skipping over <> and ()
887+ int _fd = 0 ;
888+ while (!isAtEnd ()) {
889+ if (checkPunct ("(" ) || checkOp ("<" )) { _fd ++; advance (); }
890+ else if (checkPunct (")" ) || checkOp (">" )) { _fd --; advance (); }
891+ else if (checkOp (">>" )) { _fd -= 2 ; advance (); }
892+ else if (checkPunct (";" ) && _fd == 0 ) { advance (); break ; }
893+ else if (checkPunct ("{" ) && _fd == 0 ) {
894+ // friend function with body
895+ int bd = 1 ; advance ();
896+ while (!isAtEnd () && bd > 0 ) { if (checkPunct ("{" )) bd ++; else if (checkPunct ("}" )) bd --; advance (); }
897+ break ;
898+ }
899+ else advance ();
900+ }
901+ return List .of (new PreprocessorLine ("// friend" , tokens .get (startPos ).line (), tokens .get (startPos ).col (), leadingComments ));
902+ }
903+ // explicit(...): conditional explicit specifier (C++20)
904+ if (checkKeyword ("explicit" ) && pos + 1 < tokens .size () && tokens .get (pos + 1 ).isPunct ("(" )) {
905+ advance (); // consume explicit
906+ advance (); int _ed =1 ; // consume (
907+ while (!isAtEnd () && _ed > 0 ) { if (checkPunct ("(" )) _ed ++; else if (checkPunct (")" )) _ed --; advance (); }
908+ } else {
909+ matchKeyword ("explicit" ); // plain explicit
910+ }
852911 boolean isConstexprCtor = false ;
853912 if (checkKeyword ("constexpr" ) && pos + 1 < tokens .size ()
854913 && tokens .get (pos + 1 ).type () == CppLexerTokenType .IDENTIFIER
@@ -857,7 +916,9 @@ private List<TopLevelItem> parseClassMember(List<CppLexerToken> leadingComments,
857916 advance (); // consume constexpr
858917 isConstexprCtor = true ;
859918 }
860- if (check (CppLexerTokenType .IDENTIFIER ) && peek ().text ().equals (enclosingClassName ) && tokens .get (pos + 1 ).isPunct ("(" )) {
919+ // Constructor: match enclosingClassName OR just its base name (for specializations like Grid<T,N,false>)
920+ String enclosingBase = enclosingClassName .contains ("<" ) ? enclosingClassName .substring (0 , enclosingClassName .indexOf ("<" )) : enclosingClassName ;
921+ if (check (CppLexerTokenType .IDENTIFIER ) && (peek ().text ().equals (enclosingClassName ) || peek ().text ().equals (enclosingBase )) && tokens .get (pos + 1 ).isPunct ("(" )) {
861922 return List .of (parseFunctionOrConstructorOrDestructor (leadingComments , templateParams ));
862923 }
863924 return parseFunctionOrVariable (leadingComments , templateParams , false );
@@ -1658,14 +1719,17 @@ private boolean isIntegerTypeModifierOrBase(String s) {
16581719 */
16591720 private void parseTemplateDefaultValue () {
16601721 int depth = 0 ;
1722+ int braceDepth = 0 ; // track {} so < inside lambdas doesn't affect angle depth
16611723 while (!isAtEnd ()) {
1724+ if (checkPunct ("{" )) { braceDepth ++; advance (); continue ; }
1725+ if (checkPunct ("}" )) { if (braceDepth > 0 ) { braceDepth --; advance (); continue ; } break ; }
16621726 if (checkPunct ("(" ) || checkPunct ("[" )) { depth ++; advance (); }
16631727 else if (checkPunct (")" ) || checkPunct ("]" )) {
16641728 if (depth == 0 ) break ;
16651729 depth --; advance ();
16661730 }
1667- else if (checkOp ("<" )) { depth ++; advance (); }
1668- else if (checkOp (">" )) {
1731+ else if (checkOp ("<" ) && braceDepth == 0 ) { depth ++; advance (); }
1732+ else if (checkOp (">" ) && braceDepth == 0 ) {
16691733 if (depth == 0 ) break ;
16701734 depth --; advance ();
16711735 }
@@ -2956,10 +3020,19 @@ private Block parseBlock() {
29563020 private List <Statement > parseStatementOrMultiDecl (List <CppLexerToken > leadingComments ) {
29573021 if (isStructuredBindingStart ()) return List .of (parseStructuredBinding (leadingComments ));
29583022 // Local struct/class definition: "struct Point { float x, y; }; Point p{...}"
3023+ // Also handle forward decl: "struct LocalFwd;" -- consume and skip
29593024 if ((checkKeyword ("struct" ) || checkKeyword ("class" ))
29603025 && pos + 1 < tokens .size ()
29613026 && (tokens .get (pos + 1 ).type () == CppLexerTokenType .IDENTIFIER
29623027 || tokens .get (pos + 1 ).isPunct ("{" ))) {
3028+ // Forward declaration: "struct Foo;" -- just consume and emit empty
3029+ if (tokens .get (pos + 1 ).type () == CppLexerTokenType .IDENTIFIER
3030+ && pos + 2 < tokens .size () && tokens .get (pos + 2 ).isPunct (";" )) {
3031+ CppLexerToken sk = peek (); advance (); advance (); advance (); // struct Name ;
3032+ return List .of (new ExprStatement (
3033+ new Identifier ("" , sk .line (), sk .col (), List .of ()),
3034+ sk .line (), sk .col (), leadingComments ));
3035+ }
29633036 TypeDef td = parseTypeDef (leadingComments , List .of ());
29643037 matchPunct (";" );
29653038 // Emit struct as verbatim text via CodeGen
0 commit comments