From 8c21e6b9936299bce5b1a0b19a0c7ea09d3009b1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Jun 2026 14:21:59 +0000
Subject: [PATCH 1/4] Initial plan
From 479f7928aaf50f630ef9d4a433b2ca48944aedc9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Jun 2026 14:32:52 +0000
Subject: [PATCH 2/4] docs(spec): document directive syntax in language grammar
- Add LineTerminator and LineTerminatorSequence productions to lexical
grammar, separate from WhiteSpace (matching how the scanner emits
Token.NewLine vs Token.Whitespace)
- Update Trivia to include LineTerminatorSequence alongside Comment and
WhiteSpace
- Fix the incorrect comment claiming newlines have no language-semantic
impact; directives are terminated by newlines so they ARE significant
- Add DirectiveList, DirectiveExpression, DirectiveArguments, and
DirectiveArgument productions to the syntactic grammar with notes on
newline-aware termination and currently supported directive names
(#suppress, #deprecated)
- Add DirectiveList? before DecoratorList? in all statement/declaration
productions that accept annotations
Closes #949
Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
---
packages/spec/src/spec.emu.html | 105 +++++++++++++++++++++-----------
1 file changed, 68 insertions(+), 37 deletions(-)
diff --git a/packages/spec/src/spec.emu.html b/packages/spec/src/spec.emu.html
index 1a74c894e72..22145713e43 100644
--- a/packages/spec/src/spec.emu.html
+++ b/packages/spec/src/spec.emu.html
@@ -30,6 +30,7 @@
Lexical Grammar
Trivia :
Comment
WhiteSpace
+ LineTerminatorSequence
Keyword :
BooleanLiteral
@@ -207,21 +208,12 @@ Lexical Grammar
`|` `?` `=` `&` `:` `,` `;` `.` `<` `>` `(` `)` `{` `}` `[` `]` `@` `...` `#`
///
-// Note that whitespace could also be specified equivalently as "Any Unicode
-// code point with property value Pattern_White_Space=True"
-//
-// However, see http://www.unicode.org/reports/tr31/#Stability
-//
-// "The [...] Pattern_White_Space characters are immutable and will not
-// change over successive versions of Unicode". This is therefore a fixed set
-// of characters, which are simply listed below to serve as a more direct
-// reference:
+// WhiteSpace covers non-line-terminator whitespace characters. The
+// Pattern_White_Space property from Unicode TR31 defines the full set:
//
// - U+0009 TAB HORIZONTAL TAB
-// - U+000A LF LINE FEED
// - U+000B VT VERTICAL TAB
// - U+000C FF FORM FEED
-// - U+000D CR CARRIAGE RETURN
// - U+0020 SP SPACE
// - U+0085 NEL NEXT LINE
// - U+200E LRM LEFT-TO-RIGHT MARK
@@ -229,19 +221,13 @@ Lexical Grammar
// - U+2028 LS LINE SEPARATOR
// - U+2029 PS PARAGRAPH SEPARATOR
//
-// It is deliberately left unspecified which whitespace sequences are
-// considered newlines as no language semantics are impacted by that choice.
-// Only line and column numbers associated with diagnostics are impacted. In
-// practice, only CR ("MAC"), LF ("UNIX"), and CRLF ("DOS") line endings are
-// currently recognized by our implementation. Additional line endings may be
-// recognized in the future.
+// Note: U+000A (LF), U+000D (CR), and the CR+LF sequence are line terminators
+// and are covered by LineTerminatorSequence instead of WhiteSpace.
///
WhiteSpace :
-
-
@@ -249,6 +235,21 @@ Lexical Grammar
+///
+// LineTerminatorSequence covers the sequences that are recognized as line
+// endings. Only CR (U+000D), LF (U+000A), and the CRLF pair are currently
+// recognized. Unlike WhiteSpace, line terminators are syntactically
+// significant: they terminate directive expressions (see DirectiveExpression).
+///
+LineTerminator : one of
+
+
+
+LineTerminatorSequence :
+
+ [lookahead != ]
+
+
Comment :
MultiLineComment
SingleLineComment
@@ -298,7 +299,7 @@ Syntactic Grammar
Statement
BlocklessNamespaceStatement :
- DecoratorList? `namespace` IdentifierOrMemberExpression `;`
+ DirectiveList? DecoratorList? `namespace` IdentifierOrMemberExpression `;`
ImportStatement :
`import` StringLiteral `;`
@@ -325,15 +326,15 @@ Syntactic Grammar
`using` IdentifierOrMemberExpression `;`
ModelStatement :
- DecoratorList? `model` Identifier TemplateParameters? IsModelHeritage `;`
- DecoratorList? `model` Identifier TemplateParameters? ModelHeritage? `{` ModelBody? `}`
+ DirectiveList? DecoratorList? `model` Identifier TemplateParameters? IsModelHeritage `;`
+ DirectiveList? DecoratorList? `model` Identifier TemplateParameters? ModelHeritage? `{` ModelBody? `}`
IsModelHeritage :
`is` Expression
ScalarStatement :
- DecoratorList? `scalar` Identifier TemplateParameters? ScalarExtends? `;`
- DecoratorList? `scalar` Identifier TemplateParameters? ScalarExtends? `{` ScalarBody? `}`
+ DirectiveList? DecoratorList? `scalar` Identifier TemplateParameters? ScalarExtends? `;`
+ DirectiveList? DecoratorList? `scalar` Identifier TemplateParameters? ScalarExtends? `{` ScalarBody? `}`
ScalarExtends :
`extends` Expression
@@ -366,14 +367,14 @@ Syntactic Grammar
ModelProperty :
ModelSpreadProperty
- DecoratorList? Identifier `?`? `:` Expression
- DecoratorList? StringLiteral `?`? `:` Expression
+ DirectiveList? DecoratorList? Identifier `?`? `:` Expression
+ DirectiveList? DecoratorList? StringLiteral `?`? `:` Expression
ModelSpreadProperty :
`...` ReferenceExpression
InterfaceStatement :
- DecoratorList? `interface` Identifier TemplateParameters? InterfaceHeritage? `{` InterfaceBody? `}`
+ DirectiveList? DecoratorList? `interface` Identifier TemplateParameters? InterfaceHeritage? `{` InterfaceBody? `}`
InterfaceHeritage :
`extends` ReferenceExpressionList;
@@ -386,11 +387,11 @@ Syntactic Grammar
InterfaceMemberList `;` InterfaceMember
InterfaceMember :
- `op`? Identifier OperationSignature
+ DirectiveList? DecoratorList? `op`? Identifier OperationSignature
UnionStatement :
- DecoratorList? `union` Identifier TemplateParameters? `{` UnionBody? `}`
+ DirectiveList? DecoratorList? `union` Identifier TemplateParameters? `{` UnionBody? `}`
UnionBody :
UnionVariantList `;`?
@@ -400,12 +401,12 @@ Syntactic Grammar
UnionVariantList `;` UnionVariant
UnionVariant :
- DecoratorList? Identifier `:` Expression
- DecoratorList? StringLiteral `:` Expression
- DecoratorList? Expression
+ DirectiveList? DecoratorList? Identifier `:` Expression
+ DirectiveList? DecoratorList? StringLiteral `:` Expression
+ DirectiveList? DecoratorList? Expression
EnumStatement :
- DecoratorList? `enum` Identifier `{` EnumBody? `}`
+ DirectiveList? DecoratorList? `enum` Identifier `{` EnumBody? `}`
EnumBody :
EnumMemberList `,`?
@@ -418,8 +419,8 @@ Syntactic Grammar
EnumMember :
EnumSpreadMember
- DecoratorList? Identifier EnumMemberValue?
- DecoratorList? StringLiteral EnumMemberValue?
+ DirectiveList? DecoratorList? Identifier EnumMemberValue?
+ DirectiveList? DecoratorList? StringLiteral EnumMemberValue?
EnumSpreadMember :
`...` ReferenceExpression
@@ -457,7 +458,7 @@ Syntactic Grammar
IdentifierList `,` Identifier
NamespaceStatement :
- DecoratorList? `namespace` IdentifierOrMemberExpression `{` StatementList? `}`
+ DirectiveList? DecoratorList? `namespace` IdentifierOrMemberExpression `{` StatementList? `}`
OperationSignatureDeclaration :
`(` ModelPropertyList? `)` `:` Expression
@@ -470,7 +471,7 @@ Syntactic Grammar
OperationSignatureReference
OperationStatement :
- DecoratorList? `op` Identifier TemplateParameters? OperationSignature `;`
+ DirectiveList? DecoratorList? `op` Identifier TemplateParameters? OperationSignature `;`
Expression :
UnionExpressionOrHigher
@@ -588,6 +589,36 @@ Syntactic Grammar
DecoratorArguments :
`(` ExpressionList? `)`
+///
+// DirectiveExpression covers the #suppress and #deprecated directives.
+// Unlike most constructs, a directive is terminated by a LineTerminatorSequence
+// (or end of file) rather than a delimiter such as `;`. This means line
+// terminators are syntactically significant inside directives: all arguments
+// to the directive must appear on the same line as the `#` token.
+//
+// Currently recognized directive names are `suppress` and `deprecated`.
+// #suppress -- suppresses a specific diagnostic (2 arguments)
+// #deprecated -- marks a declaration as deprecated (1 argument)
+//
+// The number of required arguments is validated during semantic analysis, not
+// by this grammar. The second alternative for DirectiveExpression handles the
+// case where the directive appears at the very end of the file with no trailing
+// line terminator.
+///
+DirectiveList :
+ DirectiveList? DirectiveExpression
+
+DirectiveExpression :
+ `#` Identifier DirectiveArguments? LineTerminatorSequence
+ `#` Identifier DirectiveArguments?
+
+DirectiveArguments :
+ DirectiveArgument DirectiveArguments?
+
+DirectiveArgument :
+ StringLiteral
+ Identifier
+
CallExpression :
IdentifierOrMemberExpression `(` ExpressionList? `)`
From 303675db22ee51e8fc7addcc826462bf17b44cd6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Jun 2026 14:51:55 +0000
Subject: [PATCH 3/4] fix(spec): remove LineTerminator definition to fix
ecmarkup OOM
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Defining `LineTerminator` caused ecmarkup to try expanding the
"SourceCharacter but not ... or LineTerminator" productions in
BacktickedIdentifierChar, StringCharacter, and SingleLineCommentChar.
This triggered a memory blowup that crashed the build at 4GB heap.
Since LineTerminator was already referenced-but-undefined in those
three productions before this PR, keep it undefined. Define only
`LineTerminatorSequence` (using / character literals directly)
since it is the production that needs to appear in Trivia.
Also remove the two-alternative form of DirectiveExpression that used
`LineTerminatorSequence` as a syntactic-grammar terminal — directive
termination is explained in prose instead.
Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
---
packages/spec/src/spec.emu.html | 28 +++++++++++-----------------
1 file changed, 11 insertions(+), 17 deletions(-)
diff --git a/packages/spec/src/spec.emu.html b/packages/spec/src/spec.emu.html
index 22145713e43..7bbd278c9d3 100644
--- a/packages/spec/src/spec.emu.html
+++ b/packages/spec/src/spec.emu.html
@@ -236,15 +236,11 @@ Lexical Grammar
///
-// LineTerminatorSequence covers the sequences that are recognized as line
-// endings. Only CR (U+000D), LF (U+000A), and the CRLF pair are currently
-// recognized. Unlike WhiteSpace, line terminators are syntactically
-// significant: they terminate directive expressions (see DirectiveExpression).
+// LineTerminatorSequence covers the three sequences recognised as line endings:
+// a lone LF (U+000A), a lone CR (U+000D) not followed by LF, or the CRLF pair.
+// Unlike WhiteSpace, line terminators are syntactically significant: they
+// terminate directive expressions (see DirectiveExpression).
///
-LineTerminator : one of
-
-
-
LineTerminatorSequence :
[lookahead != ]
@@ -591,25 +587,23 @@ Syntactic Grammar
///
// DirectiveExpression covers the #suppress and #deprecated directives.
-// Unlike most constructs, a directive is terminated by a LineTerminatorSequence
-// (or end of file) rather than a delimiter such as `;`. This means line
-// terminators are syntactically significant inside directives: all arguments
-// to the directive must appear on the same line as the `#` token.
+// A directive is terminated by a line terminator (CR, LF, or CRLF) or end of
+// input. Because line terminators are classified as Trivia and are normally
+// transparent to the syntactic grammar, the termination rule is enforced
+// contextually by the parser rather than expressed as a formal production: all
+// DirectiveArguments must appear on the same source line as the `#` token.
//
-// Currently recognized directive names are `suppress` and `deprecated`.
+// Currently recognised directive names are `suppress` and `deprecated`.
// #suppress -- suppresses a specific diagnostic (2 arguments)
// #deprecated -- marks a declaration as deprecated (1 argument)
//
// The number of required arguments is validated during semantic analysis, not
-// by this grammar. The second alternative for DirectiveExpression handles the
-// case where the directive appears at the very end of the file with no trailing
-// line terminator.
+// by this grammar.
///
DirectiveList :
DirectiveList? DirectiveExpression
DirectiveExpression :
- `#` Identifier DirectiveArguments? LineTerminatorSequence
`#` Identifier DirectiveArguments?
DirectiveArguments :
From 9914542736a6a1336b0f0c0ffdca94110ddb590b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 19 Jun 2026 16:00:22 +0000
Subject: [PATCH 4/4] =?UTF-8?q?docs(spec):=20fix=20spelling=20recognised?=
=?UTF-8?q?=20=E2=86=92=20recognized?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com>
---
packages/spec/src/spec.emu.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/spec/src/spec.emu.html b/packages/spec/src/spec.emu.html
index 7bbd278c9d3..5230dacc946 100644
--- a/packages/spec/src/spec.emu.html
+++ b/packages/spec/src/spec.emu.html
@@ -236,7 +236,7 @@ Lexical Grammar
///
-// LineTerminatorSequence covers the three sequences recognised as line endings:
+// LineTerminatorSequence covers the three sequences recognized as line endings:
// a lone LF (U+000A), a lone CR (U+000D) not followed by LF, or the CRLF pair.
// Unlike WhiteSpace, line terminators are syntactically significant: they
// terminate directive expressions (see DirectiveExpression).
@@ -593,7 +593,7 @@ Syntactic Grammar
// contextually by the parser rather than expressed as a formal production: all
// DirectiveArguments must appear on the same source line as the `#` token.
//
-// Currently recognised directive names are `suppress` and `deprecated`.
+// Currently recognized directive names are `suppress` and `deprecated`.
// #suppress -- suppresses a specific diagnostic (2 arguments)
// #deprecated -- marks a declaration as deprecated (1 argument)
//