-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgrammar-design.pest
More file actions
129 lines (107 loc) · 4.78 KB
/
grammar-design.pest
File metadata and controls
129 lines (107 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// =====================================================================
// 1. Whitespace & Source
// =====================================================================
COMMENT = _{ "#" ~ (!NEWLINE ~ ANY)* }
WHITESPACE = _{ " " | "\t" | NEWLINE }
source = { SOI ~ WHITESPACE* ~ nix_expression ~ WHITESPACE* ~ EOI }
// =====================================================================
// 2. Keywords
// =====================================================================
// A single source of truth for all reserved words.
// We can add `if`, `then`, `else`, etc. here as needed.
keywords = _{ "rec" | "let" | "in" | "with" | "inherit" | "true" | "false" | "null" }
// =====================================================================
// 3. Expressions (Hierarchical)
// =====================================================================
// The top-level rule for any expression. Order is important for precedence.
nix_expression = { let_in_expr | with_expr | function_expr | primary_expr } // if_expr would go here too
// -- Complex Expressions --
// let ... in:
let_in_expr = { "let" ~ attr_bindings_block ~ "in" ~ nix_expression }
// with ...; ...
with_expr = { "with" ~ nix_expression ~ ";" ~ nix_expression }
// NOTE: functions are not in scope yet, but show how it would fit
function_expr = { identifier_simple ~ ":" ~ nix_expression }
// -- Primary Expressions --
// Represents a single, non-keyword-led value or a grouped expression.
primary_expr = {
literal |
attrset |
list |
path_types |
identifier |
"(" ~ nix_expression ~ ")" // Grouping expressions
}
// =====================================================================
// 4. Building Blocks & Literals
// =====================================================================
// -- Identifiers --
identifier_simple = @{ !keywords ~ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_" | "-")* }
identifier_part = { identifier_simple | string }
identifier = { identifier_part ~ ("." ~ identifier_part)* }
// -- Literals --
literal = { string | float | integer | boolean | null }
integer = @{ ("-")? ~ ASCII_DIGIT+ }
float = @{ ("-")? ~ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ }
boolean = @{ "true" | "false" }
null = @{ "null" }
// -- Paths --
path_types = { search_path | path }
search_path = { "<" ~ identifier_simple ~ ">" }
path = @{
( "~/" | "../" | "./" | "/" ) ~ ( ( !( WHITESPACE | ";" ) ~ ANY )* ) |
identifier_simple ~ ( "/" ~ ( !( WHITESPACE | ";" ) ~ ANY )* )+
}
// -- Collections and Bindings --
list = { "[" ~ nix_expression* ~ "]" }
attrset = { rec? ~ "{" ~ attr_bindings_block? ~ "}" }
// A block of bindings for `attrset` and `let`
attr_bindings_block = { attr_binding+ }
attr_binding = { binding | inherit_binding }
binding = { identifier ~ "=" ~ nix_expression ~ ";" }
inherit_binding = { "inherit" ~ WHITESPACE* ~ ("(" ~ nix_expression ~ ")")? ~ WHITESPACE* ~ identifier_simple+ ~ ";" }
// -- Strings and Interpolations --
string = { "\"" ~ string_content* ~ "\"" }
interpolation = { "${" ~ nix_expression ~ "}" }
escaped_quote = @{ "\\" ~ "\"" }
escaped_interpolation = @{ "''${" }
string_literal_part = @{ ( !("\"" | "$" | "\\" | "'") ~ ANY )+ }
dollar_literal = @{ "$" ~ !("{") }
single_quote_literal = @{ "'" ~ !"'" }
string_content = {
escaped_quote |
escaped_interpolation |
interpolation |
string_literal_part |
dollar_literal |
single_quote_literal
}
// =====================================================================
// 4. Building Blocks & Literals
// =====================================================================
// -- Identifiers --
// Now checks against the `keywords` rule.
identifier_simple = @{ !keywords ~ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_" | "-")* }
identifier_part = { identifier_simple | string }
identifier = { identifier_part ~ ("." ~ identifier_part)* }
// -- Literals --
literal = { string | float | integer | boolean | null }
integer = @{ ("-")? ~ ASCII_DIGIT+ }
float = @{ ("-")? ~ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ }
boolean = @{ "true" | "false" }
null = @{ "null" }
// -- Paths --
path_types = { search_path | path }
search_path = { "<" ~ identifier_simple ~ ">" }
path = @{
( "~/" | "../" | "./" | "/" ) ~ ( ( !( WHITESPACE | ";" ) ~ ANY )* ) |
identifier_simple ~ ( "/" ~ ( !( WHITESPACE | ";" ) ~ ANY )* )+
}
// -- Collections and Bindings --
list = { "[" ~ nix_expression* ~ "]" }
attrset = { rec? ~ "{" ~ attr_bindings_block? ~ "}" }
// A block of bindings for `attrset` and `let`
attr_bindings_block = { attr_binding+ }
attr_binding = { binding | inherit_binding }
binding = { identifier ~ "=" ~ nix_expression ~ ";" }
inherit_binding = { "inherit" ~ WHITESPACE* ~ ("(" ~ nix_expression ~ ")")? ~ WHITESPACE* ~ identifier_simple+ ~ ";" }