Skip to content

Commit 1be0428

Browse files
committed
Round 11: namespace alias, constexpr lambda, if consteval, using enum, pack indexing
Parser: - Namespace alias: namespace geo = math::detail; - constexpr/consteval after lambda params - if consteval (C++23) no-parens form - Explicit object parameter: this Counter& self - Pack indexing (C++26): args...[0] - using enum X; (C++20) - static_assert inside class body - Trailing requires clause on lambda - Multi-dimensional subscript: arr[r, c] - operator keyword excluded from cast-operator path AST: - NamedType: added isRvalueRef field (&&) - IfStatement: added isConstexpr field - Param: added isVariadic field
1 parent f5dff78 commit 1be0428

4 files changed

Lines changed: 76 additions & 22 deletions

File tree

mode/CppMode.jar

296 Bytes
Binary file not shown.

src/java/AstCore.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,12 @@ record NamedType(
8585
List<TypeRef> templateArgs,
8686
int pointerDepth,
8787
boolean isReference,
88-
boolean isConst
88+
boolean isConst,
89+
boolean isRvalueRef
8990
) implements TypeRef {
9091

9192
public static NamedType simple(String baseName) {
92-
return new NamedType(baseName, List.of(), 0, false, false);
93+
return new NamedType(baseName, List.of(), 0, false, false, false);
9394
}
9495

9596
@Override
@@ -184,9 +185,9 @@ public String describe() {
184185
* them on a lambda either).
185186
*/
186187

187-
record Param(TypeRef type, String name, Expr defaultValue, List<Integer> innerArrayDims) {
188+
record Param(TypeRef type, String name, Expr defaultValue, List<Integer> innerArrayDims, boolean isVariadic) {
188189
Param(TypeRef type, String name, Expr defaultValue) {
189-
this(type, name, defaultValue, List.of());
190+
this(type, name, defaultValue, List.of(), false);
190191
}
191192
}
192193

src/java/AstStmt.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ record IfStatement(
135135
Expr condition,
136136
Statement thenBranch,
137137
Statement elseBranch,
138+
boolean isConstexpr,
138139
int line,
139140
int col,
140141
List<CppLexerToken> leadingComments

src/java/Parser.java

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,14 @@ private List<TopLevelItem> parseClassMember(List<CppLexerToken> leadingComments,
861861
if (checkKeyword("enum")) {
862862
return List.of(parseEnumDecl(leadingComments));
863863
}
864+
// static_assert inside class body
865+
if (checkKeyword("static_assert")) {
866+
int startPos = pos; advance();
867+
expectPunct("("); int _d=1;
868+
while (!isAtEnd() && _d > 0) { if (checkPunct("(")) _d++; else if (checkPunct(")")) _d--; advance(); }
869+
matchPunct(";");
870+
return List.of(new PreprocessorLine("// static_assert", tokens.get(startPos).line(), tokens.get(startPos).col(), leadingComments));
871+
}
864872
// using X = Type; inside a struct/class body -- consume verbatim
865873
if (checkKeyword("using") && !tokens.get(pos + 1).isKeyword("namespace")) {
866874
int startPos = pos;
@@ -1229,7 +1237,7 @@ && looksLikeParamList()) {
12291237
TypeRef declaratorType = type;
12301238
if (type instanceof NamedType nt) {
12311239
declaratorType = new NamedType(nt.baseName(), nt.templateArgs(),
1232-
extraPointerDepth, extraIsReference, nt.isConst());
1240+
extraPointerDepth, extraIsReference, nt.isConst(), false);
12331241
}
12341242
result.add(parseOneTopLevelDeclarator(declaratorType, nextName, isConst, isStatic, List.of(), start, List.of()));
12351243
}
@@ -1372,6 +1380,7 @@ private String parseFunctionOrVariableName() {
13721380
if (check(CppLexerTokenType.KEYWORD) && !checkKeyword("const") && !checkKeyword("override")
13731381
&& !checkKeyword("virtual") && !checkKeyword("static")
13741382
&& !checkKeyword("inline") && !checkKeyword("explicit")
1383+
&& !checkKeyword("operator")
13751384
&& !PSEUDO_TYPE_KEYWORDS_USABLE_AS_NAMES.contains(peek().text())) {
13761385
CppLexerToken castTok = advance();
13771386
String suffix = "";
@@ -1541,6 +1550,12 @@ private NamespaceDecl parseNamespaceDecl(List<CppLexerToken> leadingComments) {
15411550
StringBuilder nameBuilder = new StringBuilder(expectIdentifier().text());
15421551
while (checkPunct("::")) { advance(); nameBuilder.append("::").append(expectIdentifier().text()); }
15431552
String name = nameBuilder.toString();
1553+
if (matchOp("=")) {
1554+
StringBuilder alias = new StringBuilder();
1555+
while (!isAtEnd() && !checkPunct(";")) { alias.append(peek().text()); advance(); }
1556+
matchPunct(";");
1557+
return new NamespaceDecl(name, false, List.of(), start.line(), start.col(), leadingComments);
1558+
}
15441559
expectPunct("{");
15451560
List<TopLevelItem> items = new ArrayList<>();
15461561
while (!checkPunct("}")) {
@@ -1614,7 +1629,7 @@ private TypeRef parseTypeRefAfterConst(boolean isConst) {
16141629
else { dtExpr.append(peek().text()); advance(); }
16151630
}
16161631
dtExpr.append(")");
1617-
return new NamedType(dtExpr.toString(), List.of(), 0, false, isConst);
1632+
return new NamedType(dtExpr.toString(), List.of(), 0, false, isConst, false);
16181633
}
16191634

16201635
String baseName = parseQualifiedTypeName();
@@ -1808,30 +1823,30 @@ private void splitTrailingShiftIntoTwoCloseAngles() {
18081823
private TypeRef parseTemplateArg() {
18091824
if (checkKeyword("true") || checkKeyword("false")) {
18101825
String val = advance().text();
1811-
return new NamedType(val, List.of(), 0, false, false);
1826+
return new NamedType(val, List.of(), 0, false, false, false);
18121827
}
18131828
if (check(CppLexerTokenType.INT_LITERAL) || check(CppLexerTokenType.FLOAT_LITERAL)
18141829
|| check(CppLexerTokenType.CHAR_LITERAL)) {
18151830
String val = advance().text();
1816-
return new NamedType(val, List.of(), 0, false, false);
1831+
return new NamedType(val, List.of(), 0, false, false, false);
18171832
}
18181833
if (checkOp("-") && pos + 1 < tokens.size() &&
18191834
(tokens.get(pos + 1).type() == CppLexerTokenType.INT_LITERAL ||
18201835
tokens.get(pos + 1).type() == CppLexerTokenType.FLOAT_LITERAL)) {
18211836
advance(); String val = "-" + advance().text();
1822-
return new NamedType(val, List.of(), 0, false, false);
1837+
return new NamedType(val, List.of(), 0, false, false, false);
18231838
}
18241839
// Address-of non-type template argument: "&Widget::value", "&Class::method"
18251840
if (checkOp("&")) {
18261841
advance(); // consume &
18271842
String name = parseQualifiedTypeName(); // Widget::value
1828-
return new NamedType("&" + name, List.of(), 0, false, false);
1843+
return new NamedType("&" + name, List.of(), 0, false, false, false);
18291844
}
18301845
// Logical negation: "!std::is_integral<T>::value" in enable_if<!...>
18311846
if (checkOp("!")) {
18321847
advance(); // consume '!'
18331848
parseTemplateDefaultValue(); // consume the rest of the expression
1834-
return new NamedType("!...", List.of(), 0, false, false);
1849+
return new NamedType("!...", List.of(), 0, false, false, false);
18351850
}
18361851
// decltype as template argument: "Pair<decltype(x), decltype(z)>"
18371852
// Must be handled before parseTypeRef() which would consume "decltype" as a type.
@@ -1846,13 +1861,13 @@ private TypeRef parseTemplateArg() {
18461861
else { dt.append(peek().text()); advance(); }
18471862
}
18481863
dt.append(")");
1849-
return new NamedType(dt.toString(), List.of(), 0, false, false);
1864+
return new NamedType(dt.toString(), List.of(), 0, false, false, false);
18501865
}
18511866
// Pack expansion "..." trailing a type: "Ts..." in template args
18521867
// Also handles standalone "..." as a variadic marker
18531868
if (checkPunct("...")) {
18541869
advance();
1855-
return new NamedType("...", List.of(), 0, false, false);
1870+
return new NamedType("...", List.of(), 0, false, false, false);
18561871
}
18571872
// sizeof expression: sizeof(T) or sizeof...(Args)
18581873
if (checkKeyword("sizeof")) {
@@ -1862,7 +1877,7 @@ private TypeRef parseTemplateArg() {
18621877
advance(); int d = 1;
18631878
while (!isAtEnd() && d > 0) { if (checkPunct("(")) d++; else if (checkPunct(")")) d--; advance(); }
18641879
}
1865-
return new NamedType("sizeof(...)", List.of(), 0, false, false);
1880+
return new NamedType("sizeof(...)", List.of(), 0, false, false, false);
18661881
}
18671882
TypeRef maybeReturnType = parseTypeRef();
18681883
if (checkPunct("(")) {
@@ -1879,7 +1894,7 @@ private TypeRef parseTemplateArg() {
18791894
}
18801895
}
18811896
if (expr.length() > nt.baseName().length()) {
1882-
return new NamedType(expr.toString(), List.of(), 0, false, false);
1897+
return new NamedType(expr.toString(), List.of(), 0, false, false, false);
18831898
}
18841899
}
18851900
return maybeReturnType;
@@ -2260,6 +2275,9 @@ private Expr parseNew() {
22602275

22612276
private Expr parsePostfix() {
22622277
Expr expr = parsePrimary();
2278+
if (checkPunct("...") && pos + 1 < tokens.size() && tokens.get(pos + 1).isPunct("[")) {
2279+
advance(); // pack indexing: args...[0]
2280+
}
22632281
while (true) {
22642282
if (checkPunct("::")) {
22652283
// Static member / scope resolution in expression context:
@@ -2336,6 +2354,7 @@ private Expr parsePostfix() {
23362354
} else if (checkPunct("[")) {
23372355
CppLexerToken t = advance();
23382356
Expr index = parseExpr();
2357+
while (matchPunct(",")) parseExpr(); // multi-dim subscript C++23
23392358
expectPunct("]");
23402359
expr = new IndexExpr(expr, index, t.line(), t.col(), List.of());
23412360
} else if (checkOp("++") || checkOp("--")) {
@@ -2664,7 +2683,7 @@ private Statement parseStructuredBinding(List<CppLexerToken> leadingComments) {
26642683
Expr initializer = parseExpr();
26652684
expectPunct(";");
26662685
String bindingName = "[" + String.join(", ", names) + "]";
2667-
return new DeclStatement(new NamedType("auto", List.of(), 0, false, false),
2686+
return new DeclStatement(new NamedType("auto", List.of(), 0, false, false, false),
26682687
bindingName, List.of(), initializer, false, false,
26692688
start.line(), start.col(), leadingComments);
26702689
}
@@ -2771,6 +2790,8 @@ private Expr parseLambda() {
27712790

27722791
// mutable, noexcept, attributes
27732792
boolean isMutable = matchKeyword("mutable");
2793+
matchKeyword("constexpr");
2794+
matchKeyword("consteval");
27742795
if (checkKeyword("noexcept")) { advance(); if(checkPunct("(")){advance();int _d=1;while(!isAtEnd()&&_d>0){if(checkPunct("("))_d++;else if(checkPunct(")"))_d--;advance();}} }
27752796
consumeAttributes();
27762797

@@ -2779,6 +2800,17 @@ private Expr parseLambda() {
27792800
returnType = parseTypeRef();
27802801
}
27812802

2803+
if (check(CppLexerTokenType.IDENTIFIER) && peek().text().equals("requires")) {
2804+
advance();
2805+
int _rd = 0;
2806+
while (!isAtEnd()) {
2807+
if (checkPunct("(") || checkOp("<")) _rd++;
2808+
else if (checkPunct(")") || checkOp(">")) _rd--;
2809+
else if (checkOp(">>")) _rd -= 2;
2810+
else if (checkPunct("{") && _rd == 0) break;
2811+
advance();
2812+
}
2813+
}
27822814
Block body = parseBlock();
27832815
return new LambdaExpr(captures, params, returnType, isMutable, body, start.line(), start.col(), List.of());
27842816
}
@@ -2844,9 +2876,10 @@ private Param parseParam() {
28442876
// C-style variadic: bare "..." as a parameter (e.g. "void f(int, ...)")
28452877
if (checkPunct("...")) {
28462878
advance();
2847-
return new Param(new NamedType("...", List.of(), 0, false, false), "...", null, List.of(), false);
2879+
return new Param(new NamedType("...", List.of(), 0, false, false, false), "...", null, List.of(), false);
28482880
}
28492881

2882+
if (checkKeyword("this")) advance(); // explicit object param (C++23)
28502883
TypeRef type = parseTypeRef();
28512884
boolean isTypePackExpansion = matchPunct("..."); // pack expansion after type: "Rest... rest"
28522885

@@ -2974,7 +3007,7 @@ private Param parseParam() {
29743007
}
29753008
// Represent as a pointer type
29763009
if (type instanceof NamedType nt) {
2977-
type = new NamedType(nt.baseName(), nt.templateArgs(), nt.pointerDepth() + 1, false, nt.isConst());
3010+
type = new NamedType(nt.baseName(), nt.templateArgs(), nt.pointerDepth() + 1, false, nt.isConst(), false);
29783011
}
29793012
}
29803013
Expr defaultValue = null;
@@ -2986,7 +3019,7 @@ private Param parseParam() {
29863019

29873020
private TypeRef bumpPointerDepth(TypeRef type) {
29883021
if (type instanceof NamedType nt) {
2989-
return new NamedType(nt.baseName(), nt.templateArgs(), nt.pointerDepth() + 1, nt.isReference(), nt.isConst());
3022+
return new NamedType(nt.baseName(), nt.templateArgs(), nt.pointerDepth() + 1, nt.isReference(), nt.isConst(), false);
29903023
}
29913024
// Function-pointer/function-signature types can't sensibly gain a
29923025
// C-style array-parameter pointer bump this way; not encountered by
@@ -3127,6 +3160,15 @@ private Statement parseStatement(List<CppLexerToken> leadingComments) {
31273160
if (checkKeyword("while")) return parseWhile(leadingComments);
31283161
if (checkKeyword("do")) return parseDoWhile(leadingComments);
31293162
if (checkKeyword("switch")) return parseSwitch(leadingComments);
3163+
if (checkKeyword("using") && pos + 1 < tokens.size() && tokens.get(pos + 1).isKeyword("enum")) {
3164+
int startPos = pos;
3165+
while (!isAtEnd() && !checkPunct(";")) advance();
3166+
matchPunct(";");
3167+
StringBuilder raw = new StringBuilder();
3168+
for (int i = startPos; i < pos - 1; i++) { if (i > startPos) raw.append(" "); raw.append(tokens.get(i).text()); }
3169+
raw.append(";");
3170+
return new ExprStatement(new Identifier(raw.toString(), tokens.get(startPos).line(), tokens.get(startPos).col(), List.of()), tokens.get(startPos).line(), tokens.get(startPos).col(), leadingComments);
3171+
}
31303172
if (checkKeyword("return")) return parseReturn(leadingComments);
31313173
if (checkKeyword("break")) return parseBreak(leadingComments);
31323174
if (checkKeyword("continue")) return parseContinue(leadingComments);
@@ -3145,6 +3187,16 @@ private Statement parseStatement(List<CppLexerToken> leadingComments) {
31453187
private Statement parseIf(List<CppLexerToken> leadingComments) {
31463188
CppLexerToken start = expectKeyword("if");
31473189
boolean isConstexpr = matchKeyword("constexpr"); // C++17 if constexpr
3190+
if (checkKeyword("consteval") || (checkOp("!") && pos + 1 < tokens.size() && tokens.get(pos+1).isKeyword("consteval"))) {
3191+
if (checkOp("!")) advance();
3192+
advance(); // consume consteval
3193+
Statement thenBr = parseStatement(consumeLeadingComments());
3194+
Statement elseBr = null;
3195+
consumeLeadingComments();
3196+
if (checkKeyword("else")) { advance(); elseBr = parseStatement(consumeLeadingComments()); }
3197+
return new IfStatement(new Identifier("true", start.line(), start.col(), List.of()),
3198+
thenBr, elseBr, false, start.line(), start.col(), leadingComments);
3199+
}
31483200
expectPunct("(");
31493201
// C++17 if-init-statement: if (init; cond) -- collect init decls,
31503202
// wrap the IfStatement in a Block so the init vars are in scope.
@@ -3193,14 +3245,14 @@ private Statement parseForOrRangeFor(List<CppLexerToken> leadingComments) {
31933245
Expr sbIterable = parseExpr(); expectPunct(")");
31943246
Statement sbBody = parseStatement(consumeLeadingComments());
31953247
String sbName = "[" + String.join(", ", sbNames) + "]";
3196-
return new RangeForStatement(new NamedType("auto",List.of(),0,false,false), sbName, isRef, sbIterable, sbBody, start.line(), start.col(), leadingComments);
3248+
return new RangeForStatement(new NamedType("auto",List.of(),0,false,false, false), sbName, isRef, sbIterable, sbBody, start.line(), start.col(), leadingComments);
31973249
}
31983250
if (looksLikeRangeFor()) {
31993251
TypeRef declType = parseTypeRef();
32003252
boolean isReference = false;
32013253
if (declType instanceof NamedType nt && nt.isReference()) {
32023254
isReference = true;
3203-
declType = new NamedType(nt.baseName(), nt.templateArgs(), nt.pointerDepth(), false, nt.isConst());
3255+
declType = new NamedType(nt.baseName(), nt.templateArgs(), nt.pointerDepth(), false, nt.isConst(), false);
32043256
}
32053257
String declName = expectIdentifier().text();
32063258
expectPunct(":");
@@ -3559,7 +3611,7 @@ private List<DeclStatement> parseDeclStatementsDesugared(List<CppLexerToken> lea
35593611
TypeRef declaratorType = type;
35603612
if (type instanceof NamedType nt) {
35613613
declaratorType = new NamedType(nt.baseName(), nt.templateArgs(),
3562-
extraPointerDepth, extraIsReference, nt.isConst());
3614+
extraPointerDepth, extraIsReference, nt.isConst(), false);
35633615
}
35643616
result.add(parseOneDeclarator(declaratorType, isStatic, isConst, start, List.of()));
35653617
}

0 commit comments

Comments
 (0)