Skip to content
This repository was archived by the owner on Apr 8, 2024. It is now read-only.

Commit c14bb84

Browse files
authored
Merge pull request #17 from qmx/full_fixed
Implement (possibly?) the full Rust Grammar
2 parents 5c88166 + 2c71df8 commit c14bb84

14 files changed

+538
-33
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ version = "0.1.0"
44
authors = ["The Rust Project Developers"]
55

66
[dependencies]
7-
gll = "0.0.2"
7+
gll = { git = "https://github.com/lykenware/gll" }
88
proc-macro2 = "0.4.0"
99
structopt = "0.2.12"
1010
walkdir = "2.2.6"
1111

1212
[build-dependencies]
13-
gll = "0.0.2"
13+
gll = { git = "https://github.com/lykenware/gll" }
1414
walkdir = "2.2.6"

build.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,22 @@ fn main() {
2121
// Start with the builtin rules for proc-macro grammars.
2222
let mut grammar = gll::proc_macro::builtin();
2323

24+
// HACK(eddyb) inject a custom builtin - this should be upstreamed to gll!
25+
{
26+
use gll::proc_macro::{FlatTokenPat, Pat};
27+
28+
grammar.define(
29+
"LIFETIME",
30+
gll::grammar::eat(Pat(vec![
31+
FlatTokenPat::Punct {
32+
ch: Some('\''),
33+
joint: Some(true),
34+
},
35+
FlatTokenPat::Ident(None),
36+
])),
37+
);
38+
}
39+
2440
// Add in each grammar fragment to the grammar.
2541
for fragment in fragments {
2642
let path = fragment.into_path();

grammar/abi.lyg

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// FIXME(eddyb) implement more specific literal support in `gll::proc_macro`
2+
Abi = LITERAL?;
3+
4+
/*
5+
// HACK(eddyb) taken from `librustc_target/spec/abi.rs`
6+
Abi =
7+
// Defaults to "C"
8+
| {}
9+
// Platform-specific ABIs
10+
| "\"cdecl\""
11+
| "\"stdcall\""
12+
| "\"fastcall\""
13+
| "\"vectorcall\""
14+
| "\"thiscall\""
15+
| "\"aapcs\""
16+
| "\"win64\""
17+
| "\"sysv64\""
18+
| "\"ptx-kernel\""
19+
| "\"msp430-interrupt\""
20+
| "\"x86-interrupt\""
21+
| "\"amdgpu-kernel\""
22+
// Cross-platform ABIs
23+
| "\"Rust\""
24+
| "\"C\""
25+
| "\"system\""
26+
| "\"rust-intrinsic\""
27+
| "\"rust-call\""
28+
| "\"platform-intrinsic\""
29+
| "\"unadjusted\""
30+
;
31+
*/

grammar/attr.lyg

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
OuterAttr = "#" attr:Attr;
2-
InnerAttr = "#!" attr:Attr;
2+
InnerAttr = "#" "!" attr:Attr;
33
Attr = "[" path:Path input:AttrInput "]";
44
AttrInput =
5-
{} |
6-
"=" LITERAL |
7-
"(" TOKEN_TREE* ")" |
8-
"[" TOKEN_TREE* "]" |
9-
"{" TOKEN_TREE* "}";
5+
| {}
6+
| "=" TOKEN_TREE
7+
| MacroInput
8+
;

grammar/expr.lyg

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
Expr = attrs:OuterAttr* kind:ExprKind;
2+
ExprKind =
3+
| Literal:LITERAL
4+
| Paren:{ "(" attrs:InnerAttr* expr:Expr ")" }
5+
| Borrow:{ "&" mutable:"mut"? expr:Expr }
6+
| Box:{ "box" expr:Expr }
7+
| Unary:{ op:UnaryOp expr:Expr }
8+
| Try:{ expr:Expr "?" }
9+
| Binary:{ left:Expr op:BinaryOp right:Expr }
10+
| Assign:{ left:Expr { "=" | op:BinaryAssignOp } right:Expr }
11+
| Range:{ start:Expr? ".." end:Expr? }
12+
| RangeInclusive:{ start:Expr? "..=" end:Expr }
13+
// unstable(type_ascription):
14+
| Type:{ expr:Expr ":" ty:Type }
15+
| Cast:{ expr:Expr "as" ty:Type }
16+
| Field:{ base:Expr "." field:FieldName }
17+
| Index:{ base:Expr "[" index:Expr "]" }
18+
| Array:{ "[" attrs:InnerAttr* exprs:Expr* % "," ","? "]" }
19+
| Repeat:{ "[" attrs:InnerAttr* elem:Expr ";" count:Expr "]" }
20+
| Tuple:{ "(" attrs:InnerAttr* exprs:Expr* % "," ","? ")" }
21+
| Path:QPath
22+
| Call:{ callee:Expr "(" args:Expr* % "," ","? ")" }
23+
| MethodCall:{ receiver:Expr "." method:PathSegment "(" args:Expr* % "," ","? ")" }
24+
| Struct:{ path:Path "{" attrs:InnerAttr* fields:StructExprFieldsAndBase "}" }
25+
| Block:{ { label:Label ":" }? unsafety:"unsafe"? block:Block }
26+
// ustable(async_await):
27+
| AsyncBlock:{ "async" block:Block }
28+
// unstable(try_block):
29+
| TryBlock:{ "try" block:Block }
30+
| Continue:{ "continue" label:Label? }
31+
| Break:{ "break" label:Label? value:Expr? }
32+
| Return:{ "return" value:Expr? }
33+
// unstable(generators):
34+
| Yield:{ "yield" value:Expr? }
35+
| If:If
36+
| Match:{ "match" expr:Expr "{" attrs:InnerAttr* arms:MatchArm* "}" }
37+
| Loop:{ { label:Label ":" }? "loop" body:Block }
38+
| While:{ { label:Label ":" }? "while" cond:Cond body:Block }
39+
| For:{ { label:Label ":" }? "for" pat:Pat "in" expr:Expr body:Block }
40+
| Closure:{
41+
// unstable(generators):
42+
generator_static:"static"?
43+
// unstable(async_await):
44+
asyncness:"async"?
45+
by_val:"move"?
46+
"|" args:ClosureArg* % "," ","? "|" { "->" ret_ty:Type }? body:Expr
47+
}
48+
| MacroCall:MacroCall
49+
;
50+
51+
UnaryOp =
52+
| Not:"!"
53+
| Neg:"-"
54+
| Deref:"*";
55+
56+
BinaryOp =
57+
// Arithmetic & bitwise (these also have `BinaryAssignOp` forms)
58+
| Add:"+"
59+
| Sub:"-"
60+
| Mul:"*"
61+
| Div:"/"
62+
| Rem:"%"
63+
| BitXor:"^"
64+
| BitAnd:"&"
65+
| BitOr:"|"
66+
| Shl:"<<"
67+
| Shr:">>"
68+
// Logic (short-circuiting)
69+
| LogicAnd:"&&"
70+
| LogicOr:"||"
71+
// Comparisons
72+
| Eq:"=="
73+
| Lt:"<"
74+
| Le:"<="
75+
| Ne:"!="
76+
| Gt:">"
77+
| Ge:">="
78+
;
79+
80+
// FIXME(eddyb) figure out how to deduplicate this with `BinaryOp`
81+
// The problem is something like `BinaryOp "="` allows a space in between,
82+
// as the last token inside each `BinaryOp` case does not require being
83+
// joint, but each token before the `=` here does impose that requirement.
84+
BinaryAssignOp =
85+
| Add:"+="
86+
| Sub:"-="
87+
| Mul:"*="
88+
| Div:"/="
89+
| Rem:"%="
90+
| BitXor:"^="
91+
| BitAnd:"&="
92+
| BitOr:"|="
93+
| Shl:"<<="
94+
| Shr:">>="
95+
;
96+
97+
FieldName =
98+
| Ident:IDENT
99+
// FIXME(eddyb) restrict this to only integer literals
100+
| Numeric:LITERAL
101+
;
102+
103+
// FIXME(eddyb) find a way to express this `A* B?` pattern better
104+
StructExprFieldsAndBase =
105+
| Fields:{ fields:StructExprField* % "," ","? }
106+
| Base:{ ".." base:Expr }
107+
| FieldsAndBase:{ fields:StructExprField+ % "," "," ".." base:Expr }
108+
;
109+
110+
StructExprField = attrs:OuterAttr* kind:StructExprFieldKind;
111+
StructExprFieldKind =
112+
| Shorthand:IDENT
113+
| Explicit:{ field:FieldName ":" expr:Expr }
114+
;
115+
116+
Label = LIFETIME;
117+
118+
If = "if" cond:Cond then:Block { "else" else_expr:ElseExpr }?;
119+
Cond =
120+
| Bool:Expr
121+
| Let:{ "let" pat:Pat "=" expr:Expr }
122+
;
123+
ElseExpr =
124+
| Block:Block
125+
| If:If
126+
;
127+
128+
MatchArm = attrs:OuterAttr* "|"? pats:Pat+ % "|" { "if" guard:Expr }? "=>" body:Expr ","?;
129+
130+
ClosureArg = pat:Pat { ":" ty:Type }?;

grammar/generics.lyg

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Generics = "<" params:GenericParam* % "," ","? ">";
2+
GenericParam = attrs:OuterAttr* kind:GenericParamKind;
3+
GenericParamKind =
4+
| Lifetime:{ name:LIFETIME { ":" bounds:LifetimeBound* % "+" "+"? }? }
5+
| Type:{ name:IDENT { ":" bounds:TypeBound* % "+" "+"? }? { "=" default:Type }? }
6+
;
7+
8+
ForAllBinder = "for" generics:Generics;
9+
10+
WhereClause = "where" bounds:WhereBound* % "," ","?;
11+
WhereBound =
12+
| Lifetime:{ lt:LIFETIME ":" bounds:LifetimeBound* % "+" "+"? }
13+
| Type:{ binder:ForAllBinder? ty:Type ":" bounds:TypeBound* % "+" "+"? }
14+
// unstable(#20041):
15+
| TypeEq:{ binder:ForAllBinder? left:Type { "=" | "==" } right:Type }
16+
;
17+
18+
LifetimeBound = outlives:LIFETIME;
19+
TypeBound =
20+
| Outlives:LIFETIME
21+
| Trait:TypeTraitBound
22+
| TraitParen:{ "(" bound:TypeTraitBound ")" }
23+
;
24+
TypeTraitBound = unbound:"?"? binder:ForAllBinder? path:Path;
25+
26+
GenericArgs =
27+
| AngleBracket:{ "<" args_and_bindings:AngleBracketGenericArgsAndBindings? ","? ">" }
28+
| Paren:{ "(" inputs:Type* % "," ","? ")" { "->" output:Type }? }
29+
;
30+
31+
// FIXME(eddyb) find a way to express this `A* B*` pattern better
32+
AngleBracketGenericArgsAndBindings =
33+
| Args:GenericArg+ % ","
34+
| Bindings:TypeBinding+ % ","
35+
| ArgsAndBindings:{ args:GenericArg+ % "," "," bindings:TypeBinding+ % "," }
36+
;
37+
38+
GenericArg =
39+
| Lifetime:LIFETIME
40+
| Type:Type
41+
;
42+
TypeBinding = name:IDENT "=" ty:Type;

grammar/item.lyg

Lines changed: 117 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,118 @@
1-
ModuleContents = attrs:InnerAttr* items:ItemWithOuterAttr*;
1+
ModuleContents = attrs:InnerAttr* items:Item*;
22

3-
ItemWithOuterAttr = attrs:OuterAttr* item:Item;
4-
// TODO other items
5-
Item =
6-
ExternCrate:{ "extern" "crate" name:IDENT { "as" rename:IDENT }? ";" } |
7-
Use:{ "use" path:Path { "as" rename:IDENT }? ";" }; // TODO use trees
3+
Item = attrs:OuterAttr* vis:Vis? kind:ItemKind;
4+
ItemKind =
5+
| Use:{ "use" use_tree:UseTree ";" }
6+
| ExternCrate:{ "extern" "crate" name:IDENT { "as" rename:IDENT }? ";" }
7+
| Mod:{ "mod" name:IDENT { ";" | "{" contents:ModuleContents "}" } }
8+
| ForeignMod:{ "extern" abi:Abi "{" attrs:InnerAttr* items:ForeignItem* "}" }
9+
| Static:{ "static" mutable:"mut"? name:IDENT ":" ty:Type "=" value:Expr ";" }
10+
| Const:{ "const" name:IDENT ":" ty:Type "=" value:Expr ";" }
11+
| Fn:{ header:FnHeader "fn" decl:FnDecl body:Block }
12+
| TypeAlias:{ "type" name:IDENT generics:Generics? where_clause:WhereClause? "=" ty:Type ";" }
13+
// unstable(existential_type):
14+
| ExistentialType:{ "existential" "type" name:IDENT generics:Generics? where_clause:WhereClause? ":" bounds:TypeBound* % "+" "+"? ";" }
15+
| Enum:{ "enum" name:IDENT generics:Generics? where_clause:WhereClause? "{" variants:EnumVariant* % "," ","? "}" }
16+
| Struct:{ "struct" name:IDENT generics:Generics? body:StructBody }
17+
| Union:{ "union" name:IDENT generics:Generics? where_clause:WhereClause? "{" fields:RecordField* % "," ","? "}" }
18+
| Trait:{
19+
unsafety:"unsafe"?
20+
// unstable(optin_builtin_traits):
21+
auto:"auto"?
22+
"trait" name:IDENT generics:Generics?
23+
{ ":" superbounds:TypeBound* % "+" "+"? }?
24+
where_clause:WhereClause? "{" trait_items:TraitItem* "}"
25+
}
26+
// unstable(trait_alias):
27+
| TraitAlias:{
28+
"trait" name:IDENT generics:Generics?
29+
{ ":" superbounds:TypeBound* % "+" "+"? }?
30+
where_clause:WhereClause? "=" bounds:TypeBound* % "+" "+"? ";"
31+
}
32+
| Impl:{
33+
// unstable(specialization):
34+
defaultness:"default"?
35+
unsafety:"unsafe"? "impl" generics:Generics?
36+
{ negate:"!"? trait_path:Path "for" }? ty:Type
37+
where_clause:WhereClause? "{" attrs:InnerAttr* impl_items:ImplItem* "}"
38+
}
39+
// unstable(decl_macro):
40+
| Macro:{ "macro" name:IDENT { "(" TOKEN_TREE* ")" }? "{" TOKEN_TREE* "}" }
41+
| MacroCall:ItemMacroCall
42+
;
43+
44+
UseTree =
45+
| Glob:{ prefix:UseTreePrefix? "*" }
46+
| Nested:{ prefix:UseTreePrefix? "{" children:UseTree* % "," ","? "}" }
47+
| Simple:{ path:Path { "as" rename:IDENT }? }
48+
;
49+
UseTreePrefix =
50+
| Path:{ path:Path "::" }
51+
| Global:"::"
52+
;
53+
54+
ForeignItem = attrs:OuterAttr* vis:Vis? kind:ForeignItemKind;
55+
ForeignItemKind =
56+
| Static:{ "static" mutable:"mut"? name:IDENT ":" ty:Type ";" }
57+
| Fn:{ "fn" decl:FnDecl ";" }
58+
// unstable(extern_types):
59+
| Type:{ "type" name:IDENT ";" }
60+
// unstable(macros_in_extern):
61+
| MacroCall:ItemMacroCall
62+
;
63+
64+
TraitItem = attrs:OuterAttr* kind:TraitItemKind;
65+
TraitItemKind =
66+
| Const:{ "const" name:IDENT ":" ty:Type { "=" default:Expr }? ";" }
67+
| Fn:{ header:FnHeader "fn" decl:FnDecl { default_body:Block | ";" } }
68+
| Type:{ "type" name:IDENT generics:Generics? { ":" bounds:TypeBound* % "+" "+"? }? where_clause:WhereClause? { "=" default:Type }? ";" }
69+
| MacroCall:ItemMacroCall
70+
;
71+
72+
ImplItem =
73+
attrs:OuterAttr*
74+
// unstable(specialization):
75+
defaultness:"default"?
76+
vis:Vis? kind:ImplItemKind
77+
;
78+
ImplItemKind =
79+
| Const:{ "const" name:IDENT ":" ty:Type "=" value:Expr ";" }
80+
| Fn:{ header:FnHeader "fn" decl:FnDecl body:Block }
81+
| Type:{ "type" name:IDENT generics:Generics? where_clause:WhereClause? "=" ty:Type ";" }
82+
// unstable(existential_type):
83+
| ExistentialType:{ "existential" "type" name:IDENT generics:Generics? where_clause:WhereClause? ":" bounds:TypeBound* % "+" "+"? ";" }
84+
| MacroCall:ItemMacroCall
85+
;
86+
87+
FnHeader = constness:"const"? unsafety:"unsafe"? asyncness:"async"? { "extern" abi:Abi }?;
88+
FnDecl = name:IDENT generics:Generics? "(" args:FnArgs? ","? ")" { "->" ret_ty:Type }? where_clause:WhereClause?;
89+
90+
// FIXME(eddyb) find a way to express this `A* B?` pattern better
91+
FnArgs =
92+
| Regular:FnArg+ % ","
93+
| Variadic:"..."
94+
| RegularAndVariadic:{ args:FnArg+ % "," "," "..." }
95+
;
96+
FnArg =
97+
| SelfValue:{ mutable:"mut"? "self" }
98+
| SelfRef:{ "&" lt:LIFETIME? mutable:"mut"? "self" }
99+
| Regular:FnSigInput
100+
;
101+
102+
EnumVariant = attrs:OuterAttr* name:IDENT kind:EnumVariantKind { "=" discr:Expr }?;
103+
EnumVariantKind =
104+
| Unit:{}
105+
| Tuple:{ "(" fields:TupleField* % "," ","? ")" }
106+
| Record:{ "{" fields:RecordField* % "," ","? "}" }
107+
;
108+
109+
// FIXME(eddyb) could maybe be shared more with `EnumVariantKind`?
110+
// The problem is the semicolons for `Unit` and `Tuple`, and the where clauses.
111+
StructBody =
112+
| Unit:{ where_clause:WhereClause? ";" }
113+
| Tuple:{ "(" fields:TupleField* % "," ","? ")" where_clause:WhereClause? ";" }
114+
| Record:{ where_clause:WhereClause? "{" fields:RecordField* % "," ","? "}" }
115+
;
116+
117+
TupleField = attrs:OuterAttr* vis:Vis? ty:Type;
118+
RecordField = attrs:OuterAttr* vis:Vis? name:IDENT ":" ty:Type;

grammar/macro.lyg

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
MacroCall = path:Path "!" ident_input:IDENT? input:MacroInput;
2+
MacroInput =
3+
| "(" TOKEN_TREE* ")"
4+
| "[" TOKEN_TREE* "]"
5+
| "{" TOKEN_TREE* "}"
6+
;
7+
8+
// FIXME(eddyb) could maybe be shared more with `MacroInput`?
9+
// The problem is the semicolons for the `()` and `[]` cases.
10+
ItemMacroCall = path:Path "!" ident_input:IDENT? input:ItemMacroInput;
11+
ItemMacroInput =
12+
| "(" TOKEN_TREE* ")" ";"
13+
| "[" TOKEN_TREE* "]" ";"
14+
| "{" TOKEN_TREE* "}"
15+
;

0 commit comments

Comments
 (0)