Skip to content

Commit

Permalink
Merge pull request #1884 from tgehr/fix17798
Browse files Browse the repository at this point in the history
fix Issue 17798 - [2.076] "static foreach" not documented
merged-on-behalf-of: Petar Kirov <ZombineDev@users.noreply.github.com>
  • Loading branch information
dlang-bot committed Oct 7, 2017
2 parents 827fe07 + 4caec8e commit c190c0c
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 8 deletions.
3 changes: 3 additions & 0 deletions spec/declaration.dd
Expand Up @@ -10,6 +10,9 @@ $(GNAME Declaration):
$(GLINK2 struct, AggregateDeclaration)
$(GLINK2 enum, EnumDeclaration)
$(GLINK2 module, ImportDeclaration)
$(GLINK2 version, ConditionalDeclaration)
$(GLINK2 version, StaticForeachDeclaration)
$(GLINK2 version, StaticAssert)
)

$(GRAMMAR
Expand Down
31 changes: 28 additions & 3 deletions spec/grammar.dd
Expand Up @@ -579,6 +579,7 @@ $(GNAME NonEmptyStatementNoCaseNoDefault):
$(GLINK MixinStatement)
$(GLINK ForeachRangeStatement)
$(GLINK ConditionalStatement)
$(GLINK StaticForeachStatement)
$(GLINK StaticAssert)
$(GLINK TemplateMixin)
$(GLINK ImportDeclaration)
Expand Down Expand Up @@ -666,8 +667,11 @@ $(GNAME Increment):
)

$(GRAMMAR
$(GNAME AggregateForeach):
$(I Foreach) $(D $(LPAREN)) $(GLINK ForeachTypeList) $(D ;) $(GLINK ForeachAggregate) $(D $(RPAREN))

$(GNAME ForeachStatement):
$(I Foreach) $(D $(LPAREN)) $(GLINK ForeachTypeList) $(D ;) $(GLINK ForeachAggregate) $(D $(RPAREN)) $(PS0)
$(GLINK AggregateForeach) $(PS0)

$(GNAME Foreach):
$(D foreach)
Expand All @@ -680,6 +684,7 @@ $(GNAME ForeachTypeList):
$(GNAME ForeachType):
$(GLINK ForeachTypeAttributes)$(OPT) $(GLINK2 declaration, BasicType) $(GLINK2 declaration, Declarator)
$(GLINK ForeachTypeAttributes)$(OPT) $(I Identifier)
$(GLINK ForeachTypeAttributes)$(OPT) $(D alias) $(I Identifier)

$(GNAME ForeachTypeAttributes)
$(GLINK ForeachTypeAttribute)
Expand All @@ -688,20 +693,24 @@ $(GNAME ForeachTypeAttributes)
$(GNAME ForeachTypeAttribute):
$(D ref)
$(GLINK2 declaration, TypeCtor)
$(D enum)

$(GNAME ForeachAggregate):
$(EXPRESSION)
)

$(GRAMMAR
$(GNAME ForeachRangeStatement):
$(GLINK Foreach) $(D $(LPAREN)) $(GLINK ForeachType) $(D ;) $(GLINK LwrExpression) $(D ..) $(GLINK UprExpression) $(D $(RPAREN)) $(PSSCOPE)
$(GNAME RangeForeach):
$(GLINK Foreach) $(D $(LPAREN)) $(GLINK ForeachType) $(D ;) $(GLINK LwrExpression) $(D ..) $(GLINK UprExpression) $(D $(RPAREN))

$(GNAME LwrExpression):
$(EXPRESSION)

$(GNAME UprExpression):
$(EXPRESSION)

$(GNAME ForeachRangeStatement):
$(GLINK RangeForeach) $(PSSCOPE)
)

$(GRAMMAR
Expand Down Expand Up @@ -1016,6 +1025,9 @@ $(GNAME Declaration):
$(GLINK AggregateDeclaration)
$(GLINK EnumDeclaration)
$(GLINK ImportDeclaration)
$(GLINK2 version, ConditionalDeclaration)
$(GLINK2 version, StaticForeachDeclaration)
$(GLINK2 version, StaticAssert)
)

$(GRAMMAR
Expand Down Expand Up @@ -1731,6 +1743,19 @@ $(GNAME DebugSpecification):
$(D debug =) $(GLINK_LEX IntegerLiteral) $(D ;)
)

$(GRAMMAR
$(GNAME StaticForeach):
$(D static) $(GLINK2 statement, AggregateForeach)
$(D static) $(GLINK2 statement, RangeForeach)

$(GNAME StaticForeachDeclaration):
$(GLINK StaticForeach) $(GLINK2 attribute, DeclarationBlock)
$(GLINK StaticForeach) $(D :) $(GLINK2 module, DeclDefs)$(OPT)

$(GNAME StaticForeachStatement):
$(GLINK StaticForeach) $(GLINK2 statement, NoScopeNonEmptyStatement)
)

$(GRAMMAR
$(GNAME StaticAssert):
$(D static assert $(LPAREN)) $(ASSIGNEXPRESSION) $(D ,)$(OPT) $(D $(RPAREN);)
Expand Down
15 changes: 12 additions & 3 deletions spec/statement.dd
Expand Up @@ -55,6 +55,7 @@ $(GNAME NonEmptyStatementNoCaseNoDefault):
$(GLINK MixinStatement)
$(GLINK ForeachRangeStatement)
$(GLINK2 version, ConditionalStatement)
$(GLINK2 version, StaticForeachStatement)
$(GLINK2 version, StaticAssert)
$(GLINK2 template-mixin, TemplateMixin)
$(GLINK2 module, ImportDeclaration)
Expand Down Expand Up @@ -405,8 +406,11 @@ $(H2 $(LEGACY_LNAME2 ForeachStatement, foreach-statement, Foreach Statement))
$(P A `foreach` statement loops over the contents of an aggregate.)

$(GRAMMAR
$(GNAME AggregateForeach):
$(I Foreach) $(D $(LPAREN)) $(GLINK ForeachTypeList) $(D ;) $(GLINK ForeachAggregate) $(D $(RPAREN))

$(GNAME ForeachStatement):
$(I Foreach) $(D $(LPAREN)) $(GLINK ForeachTypeList) $(D ;) $(GLINK ForeachAggregate) $(D $(RPAREN)) $(PS0)
$(GLINK AggregateForeach) $(PS0)

$(GNAME Foreach):
$(D foreach)
Expand All @@ -419,6 +423,7 @@ $(GNAME ForeachTypeList):
$(GNAME ForeachType):
$(GLINK ForeachTypeAttributes)$(OPT) $(GLINK2 declaration, BasicType) $(GLINK2 declaration, Declarator)
$(GLINK ForeachTypeAttributes)$(OPT) $(I Identifier)
$(GLINK ForeachTypeAttributes)$(OPT) $(D alias) $(I Identifier)

$(GNAME ForeachTypeAttributes)
$(GLINK ForeachTypeAttribute)
Expand All @@ -427,6 +432,7 @@ $(GNAME ForeachTypeAttributes)
$(GNAME ForeachTypeAttribute):
$(D ref)
$(GLINK2 declaration, TypeCtor)
$(D enum)

$(GNAME ForeachAggregate):
$(EXPRESSION)
Expand Down Expand Up @@ -916,14 +922,17 @@ $(H2 $(LEGACY_LNAME2 ForeachRangeStatement, foreach-range-statement, Foreach Ran
$(P A foreach range statement loops over the specified range.)

$(GRAMMAR
$(GNAME ForeachRangeStatement):
$(GLINK Foreach) $(D $(LPAREN)) $(GLINK ForeachType) $(D ;) $(GLINK LwrExpression) $(D ..) $(GLINK UprExpression) $(D $(RPAREN)) $(PSSCOPE)
$(GNAME RangeForeach):
$(GLINK Foreach) $(D $(LPAREN)) $(GLINK ForeachType) $(D ;) $(GLINK LwrExpression) $(D ..) $(GLINK UprExpression) $(D $(RPAREN))

$(GNAME LwrExpression):
$(EXPRESSION)

$(GNAME UprExpression):
$(EXPRESSION)

$(GNAME ForeachRangeStatement):
$(GLINK RangeForeach) $(PSSCOPE)
)

$(P
Expand Down
128 changes: 126 additions & 2 deletions spec/version.dd
Expand Up @@ -108,7 +108,7 @@ else
}
------

$(P The $(D version(unittest)) is satisfied if and only if the code is
$(P The $(D version(unittest)) is satisfied if and only if the code is
compiled with unit tests enabled (the $(DDSUBLINK dmd, switch-unittest, $(TT -unittest)) option on $(TT dmd)).
)

Expand Down Expand Up @@ -189,8 +189,9 @@ class Foo
}
------

Various different version builds can be built with a parameter
$(P Various different version builds can be built with a parameter
to version:
)

------
version($(CODE_HIGHLIGHT n)) // add in version code if version level is >= n
Expand Down Expand Up @@ -539,6 +540,129 @@ INT!(17) c; // error, static assert trips
)
)

$(H2 $(LNAME2 staticforeach, Static Foreach))

$(GRAMMAR
$(GNAME StaticForeach):
$(D static) $(GLINK2 statement, AggregateForeach)
$(D static) $(GLINK2 statement, RangeForeach)

$(GNAME StaticForeachDeclaration):
$(GLINK StaticForeach) $(GLINK2 attribute, DeclarationBlock)
$(GLINK StaticForeach) $(D :) $(GLINK2 module, DeclDefs)$(OPT)

$(GNAME StaticForeachStatement):
$(GLINK StaticForeach) $(GLINK2 statement, NoScopeNonEmptyStatement)
)

$(P The aggregate/range bounds are evaluated at compile time and
turned into a sequence of compile-time entities by evaluating
corresponding code with a $(GLINK2 statement, ForeachStatement)/$(GLINK2 statement, ForeachRangeStatement)
at compile time. The body of the $(D static foreach) is then copied a
number of times that corresponds to the number of elements of the
sequence. Within the i-th copy, the name of the $(D static forecah)
variable is bound to the i-th entry of the sequence, either as an $(D enum)
variable declaration (for constants) or an $(D alias)
declaration (for symbols). (In particular, $(D static foreach)
variables are never runtime variables.)
)

------
static foreach(i; [0, 1, 2, 3])
{
pragma(msg, i);
}
------

$(P $(D static foreach) supports multiple variables in cases where the
corresponding $(D foreach) statement supports them. (In this case,
$(D static foreach) generates a compile-time sequence of tuples, and the
tuples are subsequently unpacked during iteration.)
)

------
static foreach(i, v; ['a', 'b', 'c', 'd'])
{
static assert(i + 'a' == v);
}
------

$(P Like bodies of $(GLINK ConditionalDeclaration)s, a $(D static foreach)
body does not introduce a new scope. Therefore, it can be
used to generate declarations:
)

------
import std.range : iota;
import std.algorithm : map;
import std.conv : text;
static foreach(i; iota(0, 3).map!text)
{
mixin(`enum x` ~ i ~ ` = i;`);
}

pragma(msg, x0, " ", x1," ", x2); // 0 1 2
------

$(P As $(D static foreach) is a code generation construct and not a
loop, $(D break) and $(D continue) cannot be used to change control
flow within it. Instead of breaking or continuing a suitable enclosing
statement, such an usage yields an error (this is to prevent
misunderstandings).
)

-------
int test(int x)
{
int r = -1;
switch(x)
{
static foreach(i; 0 .. 100)
{
case i:
r = i;
break; // error
}
default: break;
}
return r;
}

static foreach(i; 0 .. 200)
{
static assert(test(i) == (i<100 ? i : -1));
}
-------

$(P An explicit $(D break)/$(D continue) label can be used to
avoid this limitation. (Note that $(D static foreach) itself
cannot be broken nor continued even if it is explicitly
labeled.)
)

-------
int test(int x)
{
int r = -1;
Lswitch: switch(x)
{
static foreach(i; 0 .. 100)
{
case i:
r = i;
break Lswitch;
}
default: break;
}
return r;
}

static foreach(i; 0 .. 200)
{
static assert(test(i) == (i<100 ? i : -1));
}
-------


$(H2 $(LEGACY_LNAME2 StaticAssert, static-assert, Static Assert))

Expand Down

0 comments on commit c190c0c

Please sign in to comment.