Skip to content

Commit 2d7f93f

Browse files
authored
Update AGR language extension syntax highlighting (#2087)
## Summary Updates the VS Code AGR language extension to support all current grammar features with proper syntax coloring. ### Syntax highlighting additions - **Block comments** (`/* ... */`) — previously only line comments were supported - **`export` keyword** — for exported rule definitions - **`[spacing=...]` annotations** — `required`, `optional`, `auto`, `none` with distinct scopes - **Value type annotations** — `: TypeName | TypeName` after rule names - **Source-less entity imports** — `import { Ordinal, CalendarDate };` (no `from` clause) - **Value expression operators** — `===`, `!==`, `??`, `?.`, `||`, `&&`, ternary `? :`, `typeof`, arithmetic, member access - **Template literals** — `\`text \${expr} text\`` with recursive expression highlighting inside `\${}` - **Spread operator** — `...` in value positions - **Capture quantifiers** — `?`, `*`, `+` on captures and rule references - **Grouped expressions** — `(expr)` and function call arguments in value context ### Bug fixes - **Single-quote handling** — Apostrophes in expression context (e.g. `what('s | is)`) are now treated as literal characters, not string delimiters. Previously this broke all highlighting from that point onward. - **Action object values** — Replaced embedded `source.js` grammar with native AGR value syntax for correct highlighting of AGR-specific constructs. ### Other changes - **language-configuration.json** — Added `blockComment` support for `/* */` toggle - **grammarRuleParser.ts** — Added comprehensive BNF for value expressions to the parser documentation comment - **sample.agr** — Updated with examples demonstrating all new features ### Files changed - `extensions/agr-language/syntaxes/agr.tmLanguage.json` - `extensions/agr-language/language-configuration.json` - `extensions/agr-language/sample.agr` - `packages/actionGrammar/src/grammarRuleParser.ts`
1 parent d2170f4 commit 2d7f93f

File tree

4 files changed

+577
-69
lines changed

4 files changed

+577
-69
lines changed

ts/extensions/agr-language/language-configuration.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"comments": {
3-
"lineComment": "//"
3+
"lineComment": "//",
4+
"blockComment": ["/*", "*/"]
45
},
56
"brackets": [
67
["{", "}"],

ts/extensions/agr-language/sample.agr

Lines changed: 136 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,30 @@
44
// Sample Action Grammar file demonstrating syntax highlighting
55
// This file shows all the major syntax elements
66

7-
// Import syntax
7+
/* Block comment:
8+
The grammar supports both line comments (//) and block comments.
9+
*/
10+
11+
// ─── Import syntax ────────────────────────────────────────────────────────────
12+
13+
// Named imports from .agr files
814
import { Cardinal, TrackName, ArtistName } from "./base.agr";
15+
16+
// Wildcard import from .agr files
917
import * from "./shared.agr";
18+
19+
// Imports from .ts schema files
1020
import { GreetAction, PlayAction, PauseAction } from "./schema.ts";
1121

12-
// Simple rule definition
22+
// Source-less entity imports (no "from" clause — built-in entities)
23+
import { Ordinal, CalendarDate };
24+
25+
// ─── Simple rule definition ───────────────────────────────────────────────────
26+
1327
<Start> = <Greeting> | <Command>;
1428

15-
// Rule with captures and value type annotation
29+
// ─── Rule with value type annotation ──────────────────────────────────────────
30+
1631
<Greeting> : GreetAction =
1732
hello $(name:PersonName) -> {
1833
actionName: "greet",
@@ -22,7 +37,8 @@ import { GreetAction, PlayAction, PauseAction } from "./schema.ts";
2237
}
2338
| hi there -> { actionName: "greet" };
2439

25-
// Rule with optional elements (union value type)
40+
// ─── Union value type annotation ──────────────────────────────────────────────
41+
2642
<Command> : PlayAction | PauseAction =
2743
play (the)? $(track:TrackName)
2844
by $(artist:ArtistName) -> {
@@ -34,7 +50,25 @@ import { GreetAction, PlayAction, PauseAction } from "./schema.ts";
3450
}
3551
| pause (the)? music? -> { actionName: "pause" };
3652

37-
// Rule with multiple patterns
53+
// ─── Exported rule ────────────────────────────────────────────────────────────
54+
55+
export <PublicRule> = hello | goodbye;
56+
57+
// ─── Spacing annotations ─────────────────────────────────────────────────────
58+
59+
<Hashtag> [spacing=none] = \# $(tag:word) -> { actionName: "hashtag", parameters: { tag } };
60+
61+
<SearchPhrase> [spacing=required] = search for $(query:string) -> {
62+
actionName: "search",
63+
parameters: { query }
64+
};
65+
66+
<CJKMixed> [spacing=auto] = $(text:string) -> text;
67+
68+
<Adjacent> [spacing=optional] = $(a:word) $(b:word) -> { a, b };
69+
70+
// ─── Multiple patterns with bare results ─────────────────────────────────────
71+
3872
<Volume> =
3973
(turn | set) (the)? volume to $(level:number) -> {
4074
actionName: "setVolume",
@@ -43,7 +77,7 @@ import { GreetAction, PlayAction, PauseAction } from "./schema.ts";
4377
| volume up -> { actionName: "volumeUp" }
4478
| volume down -> { actionName: "volumeDown" };
4579

46-
// Bare -> results (non-object): string literal, number, or variable reference
80+
// Bare -> results: string literal, number, or variable reference
4781
<PromptSpec> = (
4882
('ask me' | 'confirm' | 'please confirm') -> "true" |
4983
("don't ask" | 'without asking' | 'skip') -> "false"
@@ -55,7 +89,8 @@ import { GreetAction, PlayAction, PauseAction } from "./schema.ts";
5589
'all' -> "all"
5690
);
5791

58-
// Numeric patterns
92+
// ─── Numeric patterns ────────────────────────────────────────────────────────
93+
5994
<Cardinal> =
6095
$(x:number)
6196
| one -> 1
@@ -64,15 +99,26 @@ import { GreetAction, PlayAction, PauseAction } from "./schema.ts";
6499
| four -> 4
65100
| five -> 5;
66101

67-
// String type references
102+
// ─── Entity type captures ────────────────────────────────────────────────────
103+
104+
<ScheduleEvent> =
105+
schedule $(desc:string) on $(date:CalendarDate) -> {
106+
actionName: "schedule",
107+
parameters: { description: desc, date }
108+
};
109+
110+
<PlayNth> =
111+
play (the)? $(n:Ordinal) (track | song)? -> {
112+
actionName: "playFromQueue",
113+
parameters: { trackNumber: n }
114+
};
115+
116+
// ─── Capture with rule references ─────────────────────────────────────────────
117+
68118
<TrackName> = $(x:string);
69119
<ArtistName> = $(x:string);
70120
<PersonName> = $(x:string);
71121

72-
// Complex nested rule
73-
<PlayCommand> =
74-
<PlayTrack> | <PlayAlbum> | <PlayArtist>;
75-
76122
<PlayTrack> =
77123
play track $(n:<Cardinal>) -> {
78124
actionName: "playTrackNumber",
@@ -96,7 +142,83 @@ import { GreetAction, PlayAction, PauseAction } from "./schema.ts";
96142

97143
<AlbumName> = $(x:string);
98144

99-
// Operators demonstration
145+
// ─── Spread operator in values ────────────────────────────────────────────────
146+
147+
<MergeAction> =
148+
merge $(src:string) into $(dest:string) -> {
149+
actionName: "merge",
150+
parameters: { ...src, destination: dest }
151+
};
152+
153+
// ─── Escape sequences in string expressions ──────────────────────────────────
154+
155+
<Status> = (what('s | is) | show) (playing | status)?
156+
-> { actionName: "status" };
157+
158+
<EscapeDemo> = hello\ world -> "hello world";
159+
160+
// ─── Operators and grouping ──────────────────────────────────────────────────
161+
100162
<Operators> =
101163
one? two* three+ four // optional, zero-or-more, one-or-more
102-
| (first | second | third) // alternation with grouping;
164+
| (first | second | third) // alternation with grouping
165+
| (item)+ // one-or-more group
166+
| (prefix)* suffix; // zero-or-more group
167+
168+
// ─── Optional capture quantifiers ────────────────────────────────────────────
169+
170+
<ItemList> =
171+
add $(item:word)+ to $(list:string) -> {
172+
actionName: "addItems",
173+
parameters: { items: [item], listName: list }
174+
};
175+
176+
// ─── Value expressions (enableExpressions mode) ──────────────────────────────
177+
178+
// Ternary operator
179+
<Toggle> =
180+
toggle $(flag:word) -> flag === "on" ? true : false;
181+
182+
// Logical and nullish coalescing operators
183+
<Fallback> =
184+
set $(key:word) to $(val:string) -> {
185+
actionName: "set",
186+
parameters: {
187+
key,
188+
value: val ?? "default",
189+
enabled: val !== "" && val !== "off"
190+
}
191+
};
192+
193+
// Arithmetic and comparison in values
194+
<Repeat> =
195+
repeat $(n:number) times -> {
196+
actionName: "repeat",
197+
parameters: {
198+
count: n,
199+
doubled: n * 2,
200+
isMany: n > 5 || n === 0
201+
}
202+
};
203+
204+
// Member access and optional chaining
205+
<Lookup> =
206+
lookup $(obj:word) -> obj.value?.name;
207+
208+
// Template literals
209+
<Greet> =
210+
greet $(name:string) -> `Hello, ${name}!`;
211+
212+
// Unary operators
213+
<Negate> =
214+
negate $(x:number) -> -x;
215+
216+
<Check> =
217+
check $(val:word) -> !val ? "empty" : typeof val;
218+
219+
// Method calls and computed access
220+
<Transform> =
221+
transform $(data:word) -> data.items[0]?.toString();
222+
223+
/* End of sample — this block comment demonstrates
224+
that multi-line block comments are highlighted. */

0 commit comments

Comments
 (0)