Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| { | |
| {-| | |
| Module : Language.Rust.Parser.Internal | |
| Description : Rust parser | |
| Copyright : (c) Alec Theriault, 2017-2018 | |
| License : BSD-style | |
| Maintainer : alec.theriault@gmail.com | |
| Stability : experimental | |
| Portability : GHC | |
| The parsers in this file are all re-exported to 'Language.Rust.Parser' via the 'Parse' class. The | |
| parsers are based off of: | |
| * primarily the reference @rustc@ [implementation][0] | |
| * some documentation on [rust-lang][2] | |
| * drawing a couple ideas from a slightly outdated [ANTLR grammar][1] | |
| To get information about transition states and such, run | |
| > happy --info=happyinfo.txt -o /dev/null src/Language/Rust/Parser/Internal.y | |
| [0]: https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs | |
| [1]: https://github.com/rust-lang/rust/blob/master/src/grammar/parser-lalr.y | |
| [2]: https://doc.rust-lang.org/grammar.html | |
| -} | |
| {-# OPTIONS_HADDOCK hide, not-home #-} | |
| {-# LANGUAGE OverloadedStrings #-} | |
| {-# LANGUAGE OverloadedLists #-} | |
| {-# LANGUAGE PartialTypeSignatures #-} | |
| module Language.Rust.Parser.Internal ( | |
| -- * Parsers | |
| parseAttr, | |
| parseBlock, | |
| parseExpr, | |
| parseGenerics, | |
| parseImplItem, | |
| parseItem, | |
| parseLifetimeDef, | |
| parseLit, | |
| parsePat, | |
| parseSourceFile, | |
| parseStmt, | |
| parseTokenStream, | |
| parseTraitItem, | |
| parseTt, | |
| parseTy, | |
| parseTyParam, | |
| parseWhereClause, | |
| ) where | |
| import Language.Rust.Syntax | |
| import Language.Rust.Data.Ident ( Ident(..), mkIdent ) | |
| import Language.Rust.Data.Position | |
| import Language.Rust.Parser.Lexer ( lexNonSpace, lexShebangLine ) | |
| import Language.Rust.Parser.ParseMonad ( pushToken, getPosition, P, parseError ) | |
| import Language.Rust.Parser.Literals ( translateLit ) | |
| import Language.Rust.Parser.Reversed | |
| import Data.Foldable ( toList ) | |
| import Data.List ( (\\), isSubsequenceOf, sort ) | |
| import Data.Semigroup ( (<>) ) | |
| import Text.Read ( readMaybe ) | |
| import Data.List.NonEmpty ( NonEmpty(..), (<|) ) | |
| import qualified Data.List.NonEmpty as N | |
| } | |
| -- in order to document the parsers, we have to alias them | |
| %name parseLit lit | |
| %name parseAttr export_attribute | |
| %name parseTy ty | |
| %name parsePat pat | |
| %name parseStmt stmt | |
| %name parseExpr expr | |
| %name parseItem mod_item | |
| %name parseSourceFileContents source_file | |
| %name parseBlock export_block | |
| %name parseImplItem impl_item | |
| %name parseTraitItem trait_item | |
| %name parseTt token_tree | |
| %name parseTokenStream token_stream | |
| %name parseTyParam ty_param | |
| %name parseLifetimeDef lifetime_def | |
| %name parseWhereClause where_clause | |
| %name parseGenerics generics | |
| %tokentype { Spanned Token } | |
| %lexer { lexNonSpace >>= } { Spanned Eof _ } | |
| %monad { P } { >>= } { return } | |
| %errorhandlertype explist | |
| %error { expParseError } | |
| %expect 0 | |
| %token | |
| -- Expression-operator symbols. | |
| '=' { Spanned Equal _ } | |
| '<' { Spanned Less _ } | |
| '>' { Spanned Greater _ } | |
| '!' { Spanned Exclamation _ } | |
| '~' { Spanned Tilde _ } | |
| '+' { Spanned Plus _ } | |
| '-' { Spanned Minus _ } | |
| '*' { Spanned Star _ } | |
| '/' { Spanned Slash _ } | |
| '%' { Spanned Percent _ } | |
| '^' { Spanned Caret _ } | |
| '&' { Spanned Ampersand _ } | |
| '|' { Spanned Pipe _ } | |
| -- Structural symbols. | |
| '@' { Spanned At _ } | |
| '...' { Spanned DotDotDot _ } | |
| '..=' { Spanned DotDotEqual _ } | |
| '..' { Spanned DotDot _ } | |
| '.' { Spanned Dot _ } | |
| ',' { Spanned Comma _ } | |
| ';' { Spanned Semicolon _ } | |
| '::' { Spanned ModSep _ } | |
| ':' { Spanned Colon _ } | |
| '->' { Spanned RArrow _ } | |
| '<-' { Spanned LArrow _ } | |
| '=>' { Spanned FatArrow _ } | |
| '#' { Spanned Pound _ } | |
| '$' { Spanned Dollar _ } | |
| '?' { Spanned Question _ } | |
| '#!' { Spanned Shebang _ } | |
| '||' { Spanned PipePipe _ } | |
| '&&' { Spanned AmpersandAmpersand _ } | |
| '>=' { Spanned GreaterEqual _ } | |
| '>>=' { Spanned GreaterGreaterEqual _ } | |
| '<<' { Spanned LessLess _ } | |
| '>>' { Spanned GreaterGreater _ } | |
| '==' { Spanned EqualEqual _ } | |
| '!=' { Spanned NotEqual _ } | |
| '<=' { Spanned LessEqual _ } | |
| '<<=' { Spanned LessLessEqual _ } | |
| '-=' { Spanned MinusEqual _ } | |
| '&=' { Spanned AmpersandEqual _ } | |
| '|=' { Spanned PipeEqual _ } | |
| '+=' { Spanned PlusEqual _ } | |
| '*=' { Spanned StarEqual _ } | |
| '/=' { Spanned SlashEqual _ } | |
| '^=' { Spanned CaretEqual _ } | |
| '%=' { Spanned PercentEqual _ } | |
| '(' { Spanned (OpenDelim Paren) _ } | |
| '[' { Spanned (OpenDelim Bracket) _ } | |
| '{' { Spanned (OpenDelim Brace) _ } | |
| ')' { Spanned (CloseDelim Paren) _ } | |
| ']' { Spanned (CloseDelim Bracket) _ } | |
| '}' { Spanned (CloseDelim Brace) _ } | |
| -- Literals. | |
| byte { Spanned (LiteralTok ByteTok{} _) _ } | |
| char { Spanned (LiteralTok CharTok{} _) _ } | |
| int { Spanned (LiteralTok IntegerTok{} _) _ } | |
| float { Spanned (LiteralTok FloatTok{} _) _ } | |
| str { Spanned (LiteralTok StrTok{} _) _ } | |
| byteStr { Spanned (LiteralTok ByteStrTok{} _) _ } | |
| rawStr { Spanned (LiteralTok StrRawTok{} _) _ } | |
| rawByteStr { Spanned (LiteralTok ByteStrRawTok{} _) _ } | |
| -- Strict keywords used in the language | |
| as { Spanned (IdentTok "as") _ } | |
| box { Spanned (IdentTok "box") _ } | |
| break { Spanned (IdentTok "break") _ } | |
| const { Spanned (IdentTok "const") _ } | |
| continue { Spanned (IdentTok "continue") _ } | |
| crate { Spanned (IdentTok "crate") _ } | |
| else { Spanned (IdentTok "else") _ } | |
| enum { Spanned (IdentTok "enum") _ } | |
| extern { Spanned (IdentTok "extern") _ } | |
| false { Spanned (IdentTok "false") _ } | |
| fn { Spanned (IdentTok "fn") _ } | |
| for { Spanned (IdentTok "for") _ } | |
| if { Spanned (IdentTok "if") _ } | |
| impl { Spanned (IdentTok "impl") _ } | |
| in { Spanned (IdentTok "in") _ } | |
| let { Spanned (IdentTok "let") _ } | |
| loop { Spanned (IdentTok "loop") _ } | |
| match { Spanned (IdentTok "match") _ } | |
| mod { Spanned (IdentTok "mod") _ } | |
| move { Spanned (IdentTok "move") _ } | |
| mut { Spanned (IdentTok "mut") _ } | |
| pub { Spanned (IdentTok "pub") _ } | |
| ref { Spanned (IdentTok "ref") _ } | |
| return { Spanned (IdentTok "return") _ } | |
| Self { Spanned (IdentTok "Self") _ } | |
| self { Spanned (IdentTok "self") _ } | |
| static { Spanned (IdentTok "static") _ } | |
| struct { Spanned (IdentTok "struct") _ } | |
| super { Spanned (IdentTok "super") _ } | |
| trait { Spanned (IdentTok "trait") _ } | |
| true { Spanned (IdentTok "true") _ } | |
| type { Spanned (IdentTok "type") _ } | |
| unsafe { Spanned (IdentTok "unsafe") _ } | |
| use { Spanned (IdentTok "use") _ } | |
| where { Spanned (IdentTok "where") _ } | |
| while { Spanned (IdentTok "while") _ } | |
| do { Spanned (IdentTok "do") _ } | |
| -- Keywords reserved for future use | |
| abstract { Spanned (IdentTok "abstract") _ } | |
| alignof { Spanned (IdentTok "alignof") _ } | |
| become { Spanned (IdentTok "become") _ } | |
| final { Spanned (IdentTok "final") _ } | |
| macro { Spanned (IdentTok "macro") _ } | |
| offsetof { Spanned (IdentTok "offsetof") _ } | |
| override { Spanned (IdentTok "override") _ } | |
| priv { Spanned (IdentTok "priv") _ } | |
| proc { Spanned (IdentTok "proc") _ } | |
| pure { Spanned (IdentTok "pure") _ } | |
| sizeof { Spanned (IdentTok "sizeof") _ } | |
| typeof { Spanned (IdentTok "typeof") _ } | |
| unsized { Spanned (IdentTok "unsized") _ } | |
| virtual { Spanned (IdentTok "virtual") _ } | |
| -- Weak keywords, have special meaning only in specific contexts. | |
| default { Spanned (IdentTok "default") _ } | |
| union { Spanned (IdentTok "union") _ } | |
| catch { Spanned (IdentTok "catch") _ } | |
| auto { Spanned (IdentTok "auto") _ } | |
| yield { Spanned (IdentTok "yield") _ } | |
| dyn { Spanned (IdentTok "dyn") _ } | |
| -- Comments | |
| outerDoc { Spanned (Doc _ Outer _) _ } | |
| innerDoc { Spanned (Doc _ Inner _) _ } | |
| -- Identifiers. | |
| '_' { Spanned (IdentTok "_") _ } | |
| IDENT { Spanned IdentTok{} _ } | |
| -- Lifetimes. | |
| LIFETIME { Spanned (LifetimeTok _) _ } | |
| -- Interpolated | |
| ntItem { Spanned (Interpolated (NtItem $$)) _ } | |
| ntBlock { Spanned (Interpolated (NtBlock $$)) _ } | |
| ntStmt { Spanned (Interpolated (NtStmt $$)) _ } | |
| ntPat { Spanned (Interpolated (NtPat $$)) _ } | |
| ntExpr { Spanned (Interpolated (NtExpr $$)) _ } | |
| ntTy { Spanned (Interpolated (NtTy $$)) _ } | |
| ntIdent { Spanned (Interpolated (NtIdent _)) _ } | |
| ntPath { Spanned (Interpolated (NtPath $$)) _ } | |
| ntTT { Spanned (Interpolated (NtTT $$)) _ } | |
| ntArm { Spanned (Interpolated (NtArm $$)) _ } | |
| ntImplItem { Spanned (Interpolated (NtImplItem $$)) _ } | |
| ntTraitItem { Spanned (Interpolated (NtTraitItem $$)) _ } | |
| ntGenerics { Spanned (Interpolated (NtGenerics $$)) _ } | |
| ntWhereClause { Spanned (Interpolated (NtWhereClause $$)) _ } | |
| ntArg { Spanned (Interpolated (NtArg $$)) _ } | |
| ntLit { Spanned (Interpolated (NtLit $$)) _ } | |
| -- 'SEG' needs to be lower than '::' for path segments | |
| %nonassoc SEG | |
| -- 'mut' needs to be lower precedence than 'IDENT' so that in 'pat', something like "&mut x" | |
| -- associates the "mut" to a refence pattern and not to the identifier pattern "x". | |
| -- | |
| -- 'DEF' is for the empty case of 'def', which needs to _not_ be taken when there is a 'default' | |
| -- token available. | |
| -- | |
| -- 'EQ' is for differentiating the 'where ty' from 'where ty = ty' case in where clause | |
| -- predicates, since the former needs to _not_ be taken when there is a '=' token available. | |
| -- | |
| -- '::' is so that the remainder of mod paths in attributes are not gobbled as just raw tokens | |
| %nonassoc mut DEF EQ '::' | |
| -- These are all identifiers of sorts ('union' and 'default' are "weak" keywords) | |
| %nonassoc IDENT ntIdent default union catch self Self super auto dyn crate | |
| -- These are all very low precedence unary operators | |
| %nonassoc box return yield break continue for IMPLTRAIT LAMBDA | |
| -- 'static' needs to have higher precedenc than 'LAMBDA' so that statements starting in static get | |
| -- considered as static items, and not a static lambda | |
| %nonassoc static | |
| -- These are the usual arithmetic precedences. 'UNARY' is introduced here for '*', '!', '-', '&' | |
| %right '=' '>>=' '<<=' '-=' '+=' '*=' '/=' '^=' '|=' '&=' '%=' | |
| %right '<-' | |
| %nonassoc SINGLERNG | |
| %nonassoc INFIXRNG | |
| %nonassoc POSTFIXRNG | |
| %nonassoc PREFIXRNG | |
| %nonassoc '..' '...' '..=' | |
| %left '||' | |
| %left '&&' | |
| %left '==' '!=' '<' '>' '<=' '>=' | |
| %left '|' | |
| %left '^' | |
| %left '&' | |
| %left '<<' '>>' | |
| %left '+' '-' | |
| %left '*' '/' '%' | |
| %nonassoc ':' as | |
| %nonassoc UNARY | |
| -- These are all generated precedence tokens. | |
| -- | |
| -- * 'FIELD' for field access expressions (which bind less tightly than '.' for method calls) | |
| -- * 'VIS' for adjusting the precedence of 'pub' compared to other visbility modifiers (see 'vis') | |
| -- * 'PATH' boosts the precedences of paths in types and expressions | |
| -- * 'WHERE' is for non-empty where clauses | |
| -- | |
| %nonassoc FIELD VIS PATH WHERE NOSEMI | |
| -- These are postfix operators. | |
| %nonassoc '?' '.' | |
| -- Delimiters have the highest precedence. 'ntBlock' counts as a delimiter since it always starts | |
| -- and ends with '{' and '}' | |
| %nonassoc '{' ntBlock '[' '(' '!' ';' | |
| %% | |
| -- Unwraps the IdentTok into just an Ident | |
| -- For questionable reasons of backwards compatibility, 'union', 'default', and 'catch' can be used | |
| -- as identifiers, even if they are also keywords. They are "contextual" keywords. | |
| -- | |
| -- Union's RFC: https://github.com/rust-lang/rfcs/blob/master/text/1444-union.md | |
| ident :: { Spanned Ident } | |
| : ntIdent { fmap (\(Interpolated (NtIdent i)) -> i) $1 } | |
| | union { toIdent $1 } | |
| | default { toIdent $1 } | |
| | catch { toIdent $1 } | |
| | auto { toIdent $1 } | |
| | dyn { toIdent $1 } | |
| | IDENT { toIdent $1 } | |
| -- This should precede any '>' token which could be absorbed in a '>>', '>=', or '>>=' token. Its | |
| -- purpose is to check if the lookahead token starts with '>' but contains more that. If that is | |
| -- the case, it pushes two tokens, the first of which is '>'. We exploit the %% feature of threaded | |
| -- lexers to discard what would have been the troublesome '>>', '>=', or '>>=' token. | |
| gt :: { () } | |
| : {- empty -} {%% \(Spanned tok s) -> | |
| let s' = nudge 1 0 s; s'' = nudge 0 (-1) s in | |
| case tok of | |
| GreaterGreater -> pushToken (Spanned Greater s') *> pushToken (Spanned Greater s'') | |
| GreaterEqual -> pushToken (Spanned Equal s') *> pushToken (Spanned Greater s'') | |
| GreaterGreaterEqual -> pushToken (Spanned GreaterEqual s') *> pushToken (Spanned Greater s'') | |
| _ -> pushToken (Spanned tok s) | |
| } | |
| -- This should precede any '|' token which could be absorbed in a '||' token. This works in the same | |
| -- way as 'gt'. | |
| pipe :: { () } | |
| : {- empty -} {%% \(Spanned tok s) -> | |
| let s' = nudge 1 0 s; s'' = nudge 0 (-1) s in | |
| case tok of | |
| PipePipe -> pushToken (Spanned Pipe s') *> pushToken (Spanned Pipe s'') | |
| _ -> pushToken (Spanned tok s) | |
| } | |
| ------------- | |
| -- Utility -- | |
| ------------- | |
| -- | One or more occurences of 'p' | |
| some(p) :: { Reversed NonEmpty _ } | |
| : some(p) p { let Reversed xs = $1 in Reversed ($2 <| xs) } | |
| | p { [$1] } | |
| -- | Zero or more occurences of 'p' | |
| many(p) :: { [ _ ] } | |
| : some(p) { toList $1 } | |
| | {- empty -} { [] } | |
| -- | One or more occurences of 'p', seperated by 'sep' | |
| sep_by1(p,sep) :: { Reversed NonEmpty _ } | |
| : sep_by1(p,sep) sep p { let Reversed xs = $1 in Reversed ($3 <| xs) } | |
| | p { [$1] } | |
| -- | Zero or more occurrences of 'p', separated by 'sep' | |
| sep_by(p,sep) :: { [ _ ] } | |
| : sep_by1(p,sep) { toList $1 } | |
| | {- empty -} { [] } | |
| -- | One or more occurrences of 'p', seperated by 'sep', optionally ending in 'sep' | |
| sep_by1T(p,sep) :: { Reversed NonEmpty _ } | |
| : sep_by1(p,sep) sep { $1 } | |
| | sep_by1(p,sep) { $1 } | |
| -- | Zero or more occurences of 'p', seperated by 'sep', optionally ending in 'sep' (only if there | |
| -- is at least one 'p') | |
| sep_byT(p,sep) :: { [ _ ] } | |
| : sep_by1T(p,sep) { toList $1 } | |
| | {- empty -} { [] } | |
| -------------------------- | |
| -- Whole file | |
| -------------------------- | |
| -- shebang is dealt with at the top level, outside Happy/Alex | |
| source_file :: { ([Attribute Span],[Item Span]) } | |
| : inner_attrs many(mod_item) { (toList $1, $2) } | |
| | many(mod_item) { ([], $1) } | |
| -------------------------- | |
| -- Attributes | |
| -------------------------- | |
| outer_attribute :: { Attribute Span } | |
| : '#' '[' mod_path token_stream ']' { Attribute Outer $3 $4 ($1 # $>) } | |
| | outerDoc { let Spanned (Doc str _ l) x = $1 in SugaredDoc Outer l str x } | |
| inner_attribute :: { Attribute Span } | |
| : '#' '!' '[' mod_path token_stream ']' { Attribute Inner $4 $5 ($1 # $>) } | |
| | '#!' '[' mod_path token_stream ']' { Attribute Inner $3 $4 ($1 # $>) } | |
| | innerDoc { let Spanned (Doc str _ l) x = $1 in SugaredDoc Inner l str x } | |
| -- TODO: for some precedence related reason, using 'some' here doesn't work | |
| inner_attrs :: { Reversed NonEmpty (Attribute Span) } | |
| : inner_attrs inner_attribute { let Reversed xs = $1 in Reversed ($2 <| xs) } | |
| | inner_attribute { [$1] } | |
| -------------- | |
| -- Literals -- | |
| -------------- | |
| lit :: { Lit Span } | |
| : ntLit { $1 } | |
| | byte { lit $1 } | |
| | char { lit $1 } | |
| | int { lit $1 } | |
| | float { lit $1 } | |
| | true { lit $1 } | |
| | false { lit $1 } | |
| | string { $1 } | |
| string :: { Lit Span } | |
| : str { lit $1 } | |
| | rawStr { lit $1 } | |
| | byteStr { lit $1 } | |
| | rawByteStr { lit $1 } | |
| ----------- | |
| -- Paths -- | |
| ----------- | |
| -- parse_qualified_path(PathStyle::Type) | |
| -- qual_path :: Spanned (NonEmpty (Ident, PathParameters Span)) -> P (Spanned (QSelf Span, Path Span)) | |
| qual_path(segs) :: { Spanned (QSelf Span, Path Span) } | |
| : '<' qual_path_suf(segs) { let Spanned x _ = $2 in Spanned x ($1 # $2) } | |
| | lt_ty_qual_path as ty_path '>' '::' segs { | |
| let Path g segsTy x = $3 in | |
| Spanned (QSelf (unspan $1) (length segsTy), Path g (segsTy <> toList $6) x) ($1 # $>) | |
| } | |
| -- Basically a qualified path, but ignoring the very first '<' token | |
| qual_path_suf(segs) :: { Spanned (QSelf Span, Path Span) } | |
| : ty '>' '::' segs { Spanned (QSelf $1 0, Path False (toList $4) (spanOf $4)) ($1 # $>) } | |
| | ty as ty_path '>' '::' segs { | |
| let Path g segsTy x = $3 in | |
| Spanned (QSelf $1 (length segsTy), Path g (segsTy <> toList $6) x) ($1 # $>) | |
| } | |
| -- Usually qual_path_suf is for... type paths! This consumes these but with a starting '<<' token. | |
| -- The underlying type has the right 'Span' (it doesn't include the very first '<', while the | |
| -- 'Spanned' wrapper does) | |
| lt_ty_qual_path :: { Spanned (Ty Span) } | |
| : '<<' qual_path_suf(path_segments_without_colons) | |
| { let (qself,path) = unspan $2 in Spanned (PathTy (Just qself) path (nudge 1 0 ($1 # $2))) ($1 # $2) } | |
| -- parse_generic_args() but with the '<' '>' | |
| generic_values :: { Spanned ([Lifetime Span], [Ty Span], [(Ident, Ty Span)]) } | |
| : '<' sep_by1(lifetime,',') ',' sep_by1(ty,',') ',' sep_by1T(binding,',') gt '>' | |
| { Spanned (toList $2, toList $4, toList $6) ($1 # $>) } | |
| | '<' sep_by1(lifetime,',') ',' sep_by1T(ty,',') gt '>' | |
| { Spanned (toList $2, toList $4, [] ) ($1 # $>) } | |
| | '<' sep_by1(lifetime,',') ',' sep_by1T(binding,',') gt '>' | |
| { Spanned (toList $2, [], toList $4) ($1 # $>) } | |
| | '<' sep_by1T(lifetime,',') gt '>' | |
| { Spanned (toList $2, [], [] ) ($1 # $>) } | |
| | '<' sep_by1(ty,',') ',' sep_by1T(binding,',') gt '>' | |
| { Spanned ([], toList $2, toList $4) ($1 # $>) } | |
| | '<' sep_by1T(ty,',') gt '>' | |
| { Spanned ([], toList $2, [] ) ($1 # $>) } | |
| | '<' sep_by1T(binding,',') gt '>' | |
| { Spanned ([], [], toList $2) ($1 # $>) } | |
| | '<' gt '>' | |
| { Spanned ([], [], [] ) ($1 # $>) } | |
| | lt_ty_qual_path ',' sep_by1(ty,',') ',' sep_by1T(binding,',') gt '>' | |
| { Spanned ([], unspan $1 : toList $3, toList $5) ($1 # $>) } | |
| | lt_ty_qual_path ',' sep_by1T(ty,',') gt '>' | |
| { Spanned ([], unspan $1 : toList $3, [] ) ($1 # $>) } | |
| | lt_ty_qual_path ',' sep_by1T(binding,',') gt '>' | |
| { Spanned ([], [unspan $1],toList $3) ($1 # $>) } | |
| | lt_ty_qual_path gt '>' | |
| { Spanned ([], [unspan $1],[] ) ($1 # $>) } | |
| binding :: { (Ident, Ty Span) } | |
| : ident '=' ty { (unspan $1, $3) } | |
| -- Type related: | |
| -- parse_path(PathStyle::Type) | |
| ty_path :: { Path Span } | |
| : ntPath { $1 } | |
| | path_segments_without_colons { Path False $1 (spanOf $1) } | |
| | '::' path_segments_without_colons { Path True $2 ($1 # $2) } | |
| ty_qual_path :: { Spanned (QSelf Span, Path Span) } | |
| : qual_path(path_segments_without_colons) { $1 } | |
| -- parse_path_segments_without_colons() | |
| path_segments_without_colons :: { [PathSegment Span] } | |
| : sep_by1(path_segment_without_colons, '::') %prec SEG { toList $1 } | |
| -- No corresponding function - see path_segments_without_colons | |
| path_segment_without_colons :: { PathSegment Span } | |
| : self_or_ident path_parameter { PathSegment (unspan $1) $2 ($1 # $>) } | |
| path_parameter :: { Maybe (PathParameters Span) } | |
| : generic_values { let (lts, tys, bds) = unspan $1 | |
| in Just (AngleBracketed lts tys bds (spanOf $1)) } | |
| | '(' sep_byT(ty,',') ')' { Just (Parenthesized $2 Nothing ($1 # $>)) } | |
| | '(' sep_byT(ty,',') ')' '->' ty_no_plus { Just (Parenthesized $2 (Just $>) ($1 # $>)) } | |
| | {- empty -} %prec IDENT { Nothing } | |
| -- Expression related: | |
| -- parse_path(PathStyle::Expr) | |
| expr_path :: { Path Span } | |
| : ntPath { $1 } | |
| | path_segments_with_colons { Path False (toList $1) (spanOf $1) } | |
| | '::' path_segments_with_colons { Path True (toList $2) ($1 # $2) } | |
| expr_qual_path :: { Spanned (QSelf Span, Path Span) } | |
| : qual_path(path_segments_with_colons) { $1 } | |
| -- parse_path_segments_with_colons() | |
| path_segments_with_colons :: { Reversed NonEmpty (PathSegment Span) } | |
| : self_or_ident | |
| { [PathSegment (unspan $1) Nothing (spanOf $1)] } | |
| | path_segments_with_colons '::' self_or_ident | |
| { $1 <> [PathSegment (unspan $3) Nothing (spanOf $3)] } | |
| | path_segments_with_colons '::' generic_values | |
| {% | |
| case (unsnoc $1, unspan $3) of | |
| ((rst, PathSegment i Nothing x), (lts, tys, bds)) -> | |
| let seg = PathSegment i (Just (AngleBracketed lts tys bds (spanOf $3))) (x # $3) | |
| in pure $ snoc rst seg | |
| _ -> fail "invalid path segment in expression path" | |
| } | |
| -- Mod related: | |
| -- parse_path(PathStyle::Mod) | |
| -- | |
| -- TODO: This is O(n^2) in the segment length! I haven't been able to make the grammar work out in | |
| -- order to refactor this nicely | |
| mod_path :: { Path Span } | |
| : ntPath { $1 } | |
| | self_or_ident { Path False [PathSegment (unspan $1) Nothing (spanOf $1)] (spanOf $1) } | |
| | '::' self_or_ident { Path True [PathSegment (unspan $2) Nothing (spanOf $2)] ($1 # $>) } | |
| | mod_path '::' self_or_ident { | |
| let Path g segs _ = $1 in | |
| Path g (segs <> [PathSegment (unspan $3) Nothing (spanOf $3) ]) ($1 # $3) | |
| } | |
| self_or_ident :: { Spanned Ident } | |
| : ident { $1 } | |
| | crate { Spanned "crate" (spanOf $1) } | |
| | self { Spanned "self" (spanOf $1) } | |
| | Self { Spanned "Self" (spanOf $1) } | |
| | super { Spanned "super" (spanOf $1) } | |
| ----------- | |
| -- Types -- | |
| ----------- | |
| lifetime :: { Lifetime Span } | |
| : LIFETIME { let Spanned (LifetimeTok (Ident l _ _)) s = $1 in Lifetime l s } | |
| -- parse_trait_ref() | |
| trait_ref :: { TraitRef Span } | |
| : ty_path { TraitRef $1 } | |
| -- parse_ty() | |
| -- See https://github.com/rust-lang/rfcs/blob/master/text/0438-precedence-of-plus.md | |
| -- All types, including trait types with plus | |
| ty :: { Ty Span } | |
| : ty_no_plus { $1 } | |
| | poly_trait_ref_mod_bound '+' sep_by1T(ty_param_bound_mod,'+') { TraitObject ($1 <| toNonEmpty $3) ($1 # $3) } | |
| -- parse_ty_no_plus() | |
| ty_no_plus :: { Ty Span } | |
| : ntTy { $1 } | |
| | no_for_ty { $1 } | |
| | for_ty_no_plus { $1 } | |
| -- All types not starting with a '(' or '<' | |
| ty_prim :: { Ty Span } | |
| : no_for_ty_prim { $1 } | |
| | for_ty_no_plus { $1 } | |
| | poly_trait_ref_mod_bound '+' sep_by1T(ty_param_bound_mod,'+') { TraitObject ($1 <| toNonEmpty $3) ($1 # $3) } | |
| -- All (non-sum) types not starting with a 'for' | |
| no_for_ty :: { Ty Span } | |
| : no_for_ty_prim { $1 } | |
| | '(' ')' { TupTy [] ($1 # $2) } | |
| | '(' ty ')' { ParenTy $2 ($1 # $3) } | |
| | '(' ty ',' ')' { TupTy [$2] ($1 # $4) } | |
| | '(' ty ',' sep_by1T(ty,',') ')' { TupTy ($2 : toList $4) ($1 # $5) } | |
| | ty_qual_path { PathTy (Just (fst (unspan $1))) (snd (unspan $1)) (spanOf $1) } | |
| -- All (non-sum) types not starting with a 'for', '(', or '<' | |
| no_for_ty_prim :: { Ty Span } | |
| : '_' { Infer (spanOf $1) } | |
| | '!' { Never (spanOf $1) } | |
| | '[' ty ']' { Slice $2 ($1 # $3) } | |
| | '*' ty_no_plus { Ptr Immutable $2 ($1 # $2) } | |
| | '*' const ty_no_plus { Ptr Immutable $3 ($1 # $3) } | |
| | '*' mut ty_no_plus { Ptr Mutable $3 ($1 # $3) } | |
| | '&' ty_no_plus { Rptr Nothing Immutable $2 ($1 # $>) } | |
| | '&' lifetime ty_no_plus { Rptr (Just $2) Immutable $3 ($1 # $>) } | |
| | '&' mut ty_no_plus { Rptr Nothing Mutable $3 ($1 # $>) } | |
| | '&' lifetime mut ty_no_plus { Rptr (Just $2) Mutable $4 ($1 # $>) } | |
| | '&&' ty_no_plus { Rptr Nothing Immutable (Rptr Nothing Immutable $2 (nudge 1 0 ($1 # $>))) ($1 # $>) } | |
| | '&&' lifetime ty_no_plus { Rptr Nothing Immutable (Rptr (Just $2) Immutable $3 (nudge 1 0 ($1 # $>))) ($1 # $>) } | |
| | '&&' mut ty_no_plus { Rptr Nothing Immutable (Rptr Nothing Mutable $3 (nudge 1 0 ($1 # $>))) ($1 # $>) } | |
| | '&&' lifetime mut ty_no_plus { Rptr Nothing Immutable (Rptr (Just $2) Mutable $4 (nudge 1 0 ($1 # $>))) ($1 # $>) } | |
| | ty_path %prec PATH { PathTy Nothing $1 ($1 # $>) } | |
| | ty_mac { MacTy $1 ($1 # $>) } | |
| | unsafe extern abi fn fn_decl(arg_general) { BareFn Unsafe $3 [] $> ($1 # $>) } | |
| | unsafe fn fn_decl(arg_general) { BareFn Unsafe Rust [] $> ($1 # $>) } | |
| | extern abi fn fn_decl(arg_general) { BareFn Normal $2 [] $> ($1 # $>) } | |
| | fn fn_decl(arg_general) { BareFn Normal Rust [] $> ($1 # $>) } | |
| | typeof '(' expr ')' { Typeof $3 ($1 # $>) } | |
| | '[' ty ';' expr ']' { Array $2 $4 ($1 # $>) } | |
| | '?' trait_ref { TraitObject [TraitTyParamBound (PolyTraitRef [] $2 (spanOf $2)) Maybe ($1 # $2)] ($1 # $2) } | |
| | '?' for_lts trait_ref { TraitObject [TraitTyParamBound (PolyTraitRef (unspan $2) $3 ($2 # $3)) Maybe ($1 # $3)] ($1 # $3) } | |
| | impl sep_by1(ty_param_bound_mod,'+') %prec IMPLTRAIT { ImplTrait (toNonEmpty $2) ($1 # $2) } | |
| | dyn sep_by1(ty_param_bound_mod,'+') %prec IMPLTRAIT { TraitObject (toNonEmpty $2) ($1 # $2) } | |
| -- All (non-sum) types starting with a 'for' | |
| for_ty_no_plus :: { Ty Span } | |
| : for_lts unsafe extern abi fn fn_decl(arg_general) { BareFn Unsafe $4 (unspan $1) $> ($1 # $>) } | |
| | for_lts unsafe fn fn_decl(arg_general) { BareFn Unsafe Rust (unspan $1) $> ($1 # $>) } | |
| | for_lts extern abi fn fn_decl(arg_general) { BareFn Normal $3 (unspan $1) $> ($1 # $>) } | |
| | for_lts fn fn_decl(arg_general) { BareFn Normal Rust (unspan $1) $> ($1 # $>) } | |
| | for_lts trait_ref { | |
| let poly = PolyTraitRef (unspan $1) $2 ($1 # $2) in | |
| TraitObject [TraitTyParamBound poly None ($1 # $2)] ($1 # $2) | |
| } | |
| -- An optional lifetime followed by an optional mutability | |
| lifetime_mut :: { (Maybe (Lifetime Span), Mutability) } | |
| : lifetime mut { (Just $1, Mutable) } | |
| | lifetime { (Just $1, Immutable) } | |
| | mut { (Nothing, Mutable) } | |
| | {- empty -} { (Nothing, Immutable) } | |
| -- The argument list and return type in a function | |
| fn_decl(arg) :: { FnDecl Span } | |
| : '(' sep_by1(arg,',') ',' '...' ')' ret_ty { FnDecl (toList $2) $> True ($1 # $5 # $6) } | |
| | '(' sep_byT(arg,',') ')' ret_ty { FnDecl $2 $> False ($1 # $3 # $4) } | |
| -- Like 'fn_decl', but also accepting a self argument | |
| fn_decl_with_self_general :: { FnDecl Span } | |
| : '(' arg_self_general ',' sep_byT(arg_general,',') ')' ret_ty { FnDecl ($2 : $4) $> False ($1 # $5 # $6) } | |
| | '(' arg_self_general ')' ret_ty { FnDecl [$2] $> False ($1 # $3 # $4) } | |
| | '(' ')' ret_ty { FnDecl [] $> False ($1 # $2 # $3) } | |
| -- Like 'fn_decl', but also accepting a self argument | |
| fn_decl_with_self_named :: { FnDecl Span } | |
| : '(' arg_self_named ',' sep_by1(arg_named,',') ',' ')' ret_ty { FnDecl ($2 : toList $4) $> False ($1 # $6 # $7) } | |
| | '(' arg_self_named ',' sep_by1(arg_named,',') ')' ret_ty { FnDecl ($2 : toList $4) $> False ($1 # $5 # $6) } | |
| | '(' arg_self_named ',' ')' ret_ty { FnDecl [$2] $> False ($1 # $3 # $4) } | |
| | '(' arg_self_named ')' ret_ty { FnDecl [$2] $> False ($1 # $3 # $4) } | |
| | fn_decl(arg_named) { $1 } | |
| -- parse_ty_param_bounds(BoundParsingMode::Bare) == sep_by1(ty_param_bound,'+') | |
| ty_param_bound :: { TyParamBound Span } | |
| : lifetime { RegionTyParamBound $1 (spanOf $1) } | |
| | poly_trait_ref { TraitTyParamBound $1 None (spanOf $1) } | |
| | '(' poly_trait_ref ')' { TraitTyParamBound $2 None ($1 # $3) } | |
| poly_trait_ref_mod_bound :: { TyParamBound Span } | |
| : poly_trait_ref { TraitTyParamBound $1 None (spanOf $1) } | |
| | '?' poly_trait_ref { TraitTyParamBound $2 Maybe ($1 # $2) } | |
| -- parse_ty_param_bounds(BoundParsingMode::Modified) == sep_by1(ty_param_bound_mod,'+') | |
| ty_param_bound_mod :: { TyParamBound Span } | |
| : ty_param_bound { $1 } | |
| | '?' poly_trait_ref { TraitTyParamBound $2 Maybe ($1 # $2) } | |
| -- Sort of like parse_opt_abi() -- currently doesn't handle raw string ABI | |
| abi :: { Abi } | |
| : str {% case unspan $1 of | |
| LiteralTok (StrTok "cdecl") Nothing -> pure Cdecl | |
| LiteralTok (StrTok "stdcall") Nothing -> pure Stdcall | |
| LiteralTok (StrTok "fastcall") Nothing -> pure Fastcall | |
| LiteralTok (StrTok "vectorcall") Nothing -> pure Vectorcall | |
| LiteralTok (StrTok "aapcs") Nothing -> pure Aapcs | |
| LiteralTok (StrTok "win64") Nothing -> pure Win64 | |
| LiteralTok (StrTok "sysv64") Nothing -> pure SysV64 | |
| LiteralTok (StrTok "ptx-kernel") Nothing -> pure PtxKernel | |
| LiteralTok (StrTok "msp430-interrupt") Nothing -> pure Msp430Interrupt | |
| LiteralTok (StrTok "x86-interrupt") Nothing -> pure X86Interrupt | |
| LiteralTok (StrTok "Rust") Nothing -> pure Rust | |
| LiteralTok (StrTok "C") Nothing -> pure C | |
| LiteralTok (StrTok "system") Nothing -> pure System | |
| LiteralTok (StrTok "rust-intrinsic") Nothing -> pure RustIntrinsic | |
| LiteralTok (StrTok "rust-call") Nothing -> pure RustCall | |
| LiteralTok (StrTok "platform-intrinsic") Nothing -> pure PlatformIntrinsic | |
| LiteralTok (StrTok "unadjusted") Nothing -> pure Unadjusted | |
| _ -> parseError $1 {- "invalid ABI" -} | |
| } | |
| | {- empty -} { C } | |
| -- parse_ret_ty | |
| ret_ty :: { Maybe (Ty Span) } | |
| : '->' ty_no_plus { Just $2 } | |
| | {- empty -} { Nothing } | |
| -- parse_poly_trait_ref() | |
| poly_trait_ref :: { PolyTraitRef Span } | |
| : trait_ref { PolyTraitRef [] $1 (spanOf $1) } | |
| | for_lts trait_ref { PolyTraitRef (unspan $1) $2 ($1 # $2) } | |
| -- parse_for_lts() | |
| -- Unlike the Rust libsyntax version, this _requires_ the 'for' | |
| for_lts :: { Spanned [LifetimeDef Span] } | |
| : for '<' sep_byT(lifetime_def,',') '>' { Spanned $3 ($1 # $>) } | |
| -- Definition of a lifetime: attributes can come before the lifetime, and a list of bounding | |
| -- lifetimes can come after the lifetime. | |
| lifetime_def :: { LifetimeDef Span } | |
| : many(outer_attribute) lifetime ':' sep_by1T(lifetime,'+') { LifetimeDef $1 $2 (toList $4) ($1 # $2 # $>) } | |
| | many(outer_attribute) lifetime { LifetimeDef $1 $2 [] ($1 # $2 # $>) } | |
| --------------- | |
| -- Arguments -- | |
| --------------- | |
| -- Argument (requires a name / pattern, ie. @parse_arg_general(true)@) | |
| arg_named :: { Arg Span } | |
| : ntArg { $1 } | |
| | pat ':' ty { Arg (Just $1) $3 ($1 # $3) } | |
| -- Argument (does not require a name / pattern, ie. @parse_arg_general(false)@) | |
| -- | |
| -- Remark: not all patterns are accepted (as per <https://github.com/rust-lang/rust/issues/35203>) | |
| -- The details for which patterns _should_ be accepted fall into @is_named_argument()@. | |
| arg_general :: { Arg Span } | |
| : ntArg { $1 } | |
| | ty { Arg Nothing $1 (spanOf $1) } | |
| | '_' ':' ty { Arg (Just (WildP (spanOf $1))) $3 ($1 # $3) } | |
| | ident ':' ty { Arg (Just (IdentP (ByValue Immutable) (unspan $1) Nothing (spanOf $1))) $3 ($1 # $3) } | |
| | mut ident ':' ty { Arg (Just (IdentP (ByValue Mutable) (unspan $2) Nothing (spanOf $2))) $4 ($1 # $4) } | |
| | '&' '_' ':' ty { Arg (Just (RefP (WildP (spanOf $2)) Immutable ($1 # $2))) $4 ($1 # $4) } | |
| | '&' ident ':' ty { Arg (Just (RefP (IdentP (ByValue Immutable) (unspan $2) Nothing (spanOf $2)) Immutable ($1 # $2))) $4 ($1 # $4) } | |
| | '&&' '_' ':' ty { Arg (Just (RefP (RefP (WildP (spanOf $2)) Immutable (nudge 1 0 ($1 # $2))) Immutable ($1 # $2))) $4 ($1 # $4) } | |
| | '&&' ident ':' ty { Arg (Just (RefP (RefP (IdentP (ByValue Immutable) (unspan $2) Nothing (spanOf $2)) Immutable (nudge 1 0 ($1 # $2))) Immutable ($1 # $2))) $4 ($1 # $4) } | |
| -- Self argument (only allowed in trait function signatures) | |
| arg_self_general :: { Arg Span } | |
| : mut self { SelfValue Mutable ($1 # $>) } | |
| | self ':' ty { SelfExplicit $3 Immutable ($1 # $>) } | |
| | mut self ':' ty { SelfExplicit $4 Mutable ($1 # $>) } | |
| | arg_general { | |
| case $1 of | |
| Arg Nothing (PathTy Nothing (Path False [PathSegment "self" Nothing _] _) _) x -> SelfValue Immutable x | |
| Arg Nothing (Rptr l m (PathTy Nothing (Path False [PathSegment "self" Nothing _] _) _) _) x -> SelfRegion l m x | |
| _ -> $1 | |
| } | |
| -- Self argument (only allowed in impl function signatures) | |
| arg_self_named :: { Arg Span } | |
| : self { SelfValue Immutable ($1 # $>) } | |
| | mut self { SelfValue Mutable ($1 # $>) } | |
| | '&' self { SelfRegion Nothing Immutable ($1 # $>) } | |
| | '&' lifetime self { SelfRegion (Just $2) Immutable ($1 # $>) } | |
| | '&' mut self { SelfRegion Nothing Mutable ($1 # $>) } | |
| | '&' lifetime mut self { SelfRegion (Just $2) Mutable ($1 # $>) } | |
| | self ':' ty { SelfExplicit $3 Immutable ($1 # $>) } | |
| | mut self ':' ty { SelfExplicit $4 Mutable ($1 # $>) } | |
| -- Lambda expression argument | |
| lambda_arg :: { Arg Span } | |
| : ntArg { $1 } | |
| | pat ':' ty { Arg (Just $1) $3 ($1 # $3) } | |
| | pat { Arg (Just $1) (Infer mempty) (spanOf $1) } | |
| -------------- | |
| -- Patterns -- | |
| -------------- | |
| -- There is a funky trick going on here around 'IdentP'. When there is a binding mode (ie a 'mut' or | |
| -- 'ref') or an '@' pattern, everything is fine, but otherwise there is no difference between an | |
| -- expression variable path and a pattern. To deal with this, we intercept expression paths with | |
| -- only one segment, no path parameters, and not global and turn them into identifier patterns. | |
| pat :: { Pat Span } | |
| : ntPat { $1 } | |
| | '_' { WildP (spanOf $1) } | |
| | '&' mut pat { RefP $3 Mutable ($1 # $3) } | |
| | '&' pat { RefP $2 Immutable ($1 # $2) } | |
| | '&&' mut pat { RefP (RefP $3 Mutable (nudge 1 0 ($1 # $3))) Immutable ($1 # $3) } | |
| | '&&' pat { RefP (RefP $2 Immutable (nudge 1 0 ($1 # $2))) Immutable ($1 # $2) } | |
| | lit_expr { LitP $1 (spanOf $1) } | |
| | '-' lit_expr { LitP (Unary [] Neg $2 ($1 # $2)) ($1 # $2) } | |
| | box pat { BoxP $2 ($1 # $2) } | |
| | binding_mode1 ident '@' pat { IdentP (unspan $1) (unspan $2) (Just $4) ($1 # $>) } | |
| | binding_mode1 ident { IdentP (unspan $1) (unspan $2) Nothing ($1 # $>) } | |
| | ident '@' pat { IdentP (ByValue Immutable) (unspan $1) (Just $3) ($1 # $>) } | |
| | expr_path { | |
| case $1 of | |
| Path False [PathSegment i Nothing _] _ -> IdentP (ByValue Immutable) i Nothing (spanOf $1) | |
| _ -> PathP Nothing $1 (spanOf $1) | |
| } | |
| | expr_qual_path { PathP (Just (fst (unspan $1))) (snd (unspan $1)) ($1 # $>) } | |
| | lit_or_path '...' lit_or_path { RangeP $1 $3 ($1 # $>) } | |
| | lit_or_path '..=' lit_or_path { RangeP $1 $3 ($1 # $>) } | |
| | expr_path '{' '..' '}' { StructP $1 [] True ($1 # $>) } | |
| | expr_path '{' pat_fields '}' { let (fs,b) = $3 in StructP $1 fs b ($1 # $>) } | |
| | expr_path '(' pat_tup ')' { let (ps,m,_) = $3 in TupleStructP $1 ps m ($1 # $>) } | |
| | expr_mac { MacP $1 (spanOf $1) } | |
| | '[' pat_slice ']' { let (b,s,a) = $2 in SliceP b s a ($1 # $3) } | |
| | '(' pat_tup ')' {% | |
| case $2 of | |
| ([p], Nothing, False) -> parseError (CloseDelim Paren) | |
| (ps,m,t) -> pure (TupleP ps m ($1 # $3)) | |
| } | |
| -- The first element is the spans, the second the position of '..', and the third if there is a | |
| -- trailing comma | |
| pat_tup :: { ([Pat Span], Maybe Int, Bool) } | |
| : sep_by1(pat,',') ',' '..' ',' sep_by1(pat,',') { (toList ($1 <> $5), Just (length $1), False) } | |
| | sep_by1(pat,',') ',' '..' ',' sep_by1(pat,',') ',' { (toList ($1 <> $5), Just (length $1), True) } | |
| | sep_by1(pat,',') ',' '..' { (toList $1, Just (length $1), False) } | |
| | sep_by1(pat,',') { (toList $1, Nothing, False) } | |
| | sep_by1(pat,',') ',' { (toList $1, Nothing, True) } | |
| | '..' ',' sep_by1(pat,',') { (toList $3, Just 0, False) } | |
| | '..' ',' sep_by1(pat,',') ',' { (toList $3, Just 0, True) } | |
| | '..' { ([], Just 0, False) } | |
| | {- empty -} { ([], Nothing, False) } | |
| -- The first element is the patterns at the beginning of the slice, the second the optional binding | |
| -- for the middle slice ('Nothing' if there is no '..' and 'Just (WildP mempty) is there is one, but | |
| -- unlabelled), and the third is the patterns at the end of the slice. | |
| pat_slice :: { ([Pat Span], Maybe (Pat Span), [Pat Span]) } | |
| : sep_by1(pat,',') ',' '..' ',' sep_by1T(pat,',') { (toList $1, Just (WildP mempty), toList $5) } | |
| | sep_by1(pat,',') ',' '..' { (toList $1, Just (WildP mempty), []) } | |
| | sep_by1(pat,',') '..' ',' sep_by1T(pat,',') { let (xs, x) = unsnoc $1 in (toList xs, Just x, toList $4) } | |
| | sep_by1(pat,',') '..' { let (xs, x) = unsnoc $1 in (toList xs, Just x, []) } | |
| | sep_by1T(pat,',') { (toList $1, Nothing, []) } | |
| | '..' ',' sep_by1T(pat,',') { ([], Just (WildP mempty), toList $3) } | |
| | '..' { ([], Just (WildP mempty), []) } | |
| | {- empty -} { ([], Nothing, []) } | |
| -- Endpoints of range patterns | |
| lit_or_path :: { Expr Span } | |
| : expr_path { PathExpr [] Nothing $1 (spanOf $1) } | |
| | expr_qual_path { PathExpr [] (Just (fst (unspan $1))) (snd (unspan $1)) (spanOf $1) } | |
| | '-' lit_expr { Unary [] Neg $2 ($1 # $2) } | |
| | lit_expr { $1 } | |
| -- Used in patterns for tuple and expression patterns | |
| pat_fields :: { ([FieldPat Span], Bool) } | |
| : sep_byT(pat_field,',') { ($1, False) } | |
| | sep_by1(pat_field,',') ',' '..' { (toList $1, True) } | |
| pat_field :: { FieldPat Span } | |
| : binding_mode ident | |
| { FieldPat Nothing (IdentP (unspan $1) (unspan $2) Nothing (spanOf $2)) ($1 # $2) } | |
| | box binding_mode ident | |
| { FieldPat Nothing (BoxP (IdentP (unspan $2) (unspan $3) Nothing ($2 # $3)) ($1 # $3)) ($1 # $3) } | |
| | binding_mode ident ':' pat | |
| { FieldPat (Just (unspan $2)) $4 ($1 # $2 # $4) } | |
| -- Used prefixing IdentP patterns (not empty - that is a seperate pattern case) | |
| binding_mode1 :: { Spanned BindingMode } | |
| : ref mut { Spanned (ByRef Mutable) ($1 # $2) } | |
| | ref { Spanned (ByRef Immutable) (spanOf $1) } | |
| | mut { Spanned (ByValue Mutable) (spanOf $1) } | |
| -- Used for patterns for fields (includes the empty case) | |
| binding_mode :: { Spanned BindingMode } | |
| : binding_mode1 { $1 } | |
| | {- empty -} { Spanned (ByValue Immutable) mempty } | |
| ----------------- | |
| -- Expressions -- | |
| ----------------- | |
| -- Expressions are a pain to parse. The Rust language places "restrictions" preventing certain | |
| -- specific expressions from being valid in a certain context. Elsewhere in the parser, it will turn | |
| -- on or off these restrictions. Unfortunately, that doesn't work well at all in a grammar, so we | |
| -- have to define production rules for every combination of restrications used. Parametrized | |
| -- productions make this a bit easier by letting us factor out the core expressions used everywhere. | |
| -- Generalized expressions, parametrized by | |
| -- | |
| -- * 'lhs' - expressions allowed on the left extremity of the term | |
| -- * 'rhs' - expressions allowed on the right extremity of the term | |
| -- * 'rhs2' - expressions allowed on the right extremity following '..'/'.../..=' | |
| -- | |
| -- Precedences are handled by Happy (right at the end of the token section) | |
| gen_expression(lhs,rhs,rhs2) :: { Expr Span } | |
| -- immediate expressions | |
| : ntExpr { $1 } | |
| | lit_expr { $1 } | |
| | '[' sep_byT(expr,',') ']' { Vec [] $2 ($1 # $>) } | |
| | '[' inner_attrs sep_byT(expr,',') ']' { Vec (toList $2) $3 ($1 # $>) } | |
| | '[' expr ';' expr ']' { Repeat [] $2 $4 ($1 # $>) } | |
| | expr_mac { MacExpr [] $1 (spanOf $1) } | |
| | expr_path %prec PATH { PathExpr [] Nothing $1 (spanOf $1) } | |
| | expr_qual_path { PathExpr [] (Just (fst (unspan $1))) (snd (unspan $1)) (spanOf $1) } | |
| -- unary expressions | |
| | '*' rhs %prec UNARY { Unary [] Deref $2 ($1 # $>) } | |
| | '!' rhs %prec UNARY { Unary [] Not $2 ($1 # $>) } | |
| | '-' rhs %prec UNARY { Unary [] Neg $2 ($1 # $>) } | |
| | '&' rhs %prec UNARY { AddrOf [] Immutable $2 ($1 # $>) } | |
| | '&' mut rhs %prec UNARY { AddrOf [] Mutable $3 ($1 # $>) } | |
| | '&&' rhs %prec UNARY { AddrOf [] Immutable (AddrOf [] Immutable $2 (nudge 1 0 ($1 # $2))) ($1 # $2) } | |
| | '&&' mut rhs %prec UNARY { AddrOf [] Immutable (AddrOf [] Mutable $3 (nudge 1 0 ($1 # $3))) ($1 # $3) } | |
| | box rhs %prec UNARY { Box [] $2 ($1 # $>) } | |
| -- left-recursive | |
| | left_gen_expression(lhs,rhs,rhs2) { $1 } | |
| -- range expressions | |
| | '..' rhs2 %prec PREFIXRNG { Range [] Nothing (Just $2) HalfOpen ($1 # $2) } | |
| | '...' rhs2 %prec PREFIXRNG { Range [] Nothing (Just $2) Closed ($1 # $2) } | |
| | '..=' rhs2 %prec PREFIXRNG { Range [] Nothing (Just $2) Closed ($1 # $2) } | |
| | '..' %prec SINGLERNG { Range [] Nothing Nothing HalfOpen (spanOf $1) } | |
| | '..=' %prec SINGLERNG { Range [] Nothing Nothing Closed (spanOf $1) } | |
| -- low precedence prefix expressions | |
| | return { Ret [] Nothing (spanOf $1) } | |
| | return rhs { Ret [] (Just $2) ($1 # $2) } | |
| | yield { Yield [] Nothing (spanOf $1) } | |
| | yield rhs { Yield [] (Just $2) ($1 # $2) } | |
| | continue { Continue [] Nothing (spanOf $1) } | |
| | continue label { Continue [] (Just $2) ($1 # $2) } | |
| | break { Break [] Nothing Nothing (spanOf $1) } | |
| | break rhs { Break [] Nothing (Just $2) ($1 # $2) } | |
| | break label { Break [] (Just $2) Nothing ($1 # $2) } | |
| | break label rhs %prec break { Break [] (Just $2) (Just $3) ($1 # $3) } | |
| -- lambda expressions | |
| | static move lambda_args rhs %prec LAMBDA | |
| { Closure [] Immovable Value (FnDecl (unspan $3) Nothing False (spanOf $3)) $> ($1 # $>) } | |
| | move lambda_args rhs %prec LAMBDA | |
| { Closure [] Movable Value (FnDecl (unspan $2) Nothing False (spanOf $2)) $> ($1 # $>) } | |
| | static lambda_args rhs %prec LAMBDA | |
| { Closure [] Immovable Ref (FnDecl (unspan $2) Nothing False (spanOf $2)) $> ($1 # $>) } | |
| | lambda_args rhs %prec LAMBDA | |
| { Closure [] Movable Ref (FnDecl (unspan $1) Nothing False (spanOf $1)) $> ($1 # $>) } | |
| -- Variant of 'gen_expression' which only constructs expressions starting with another expression. | |
| left_gen_expression(lhs,rhs,rhs2) :: { Expr Span } | |
| : postfix_blockexpr(lhs) { $1 } | |
| | lhs '[' expr ']' { Index [] $1 $3 ($1 # $>) } | |
| | lhs '(' sep_byT(expr,',') ')' { Call [] $1 $3 ($1 # $>) } | |
| -- unary expressions | |
| | lhs ':' ty_no_plus { TypeAscription [] $1 $3 ($1 # $>) } | |
| | lhs as ty_no_plus { Cast [] $1 $3 ($1 # $>) } | |
| -- binary expressions | |
| | lhs '*' rhs { Binary [] MulOp $1 $3 ($1 # $>) } | |
| | lhs '/' rhs { Binary [] DivOp $1 $3 ($1 # $>) } | |
| | lhs '%' rhs { Binary [] RemOp $1 $3 ($1 # $>) } | |
| | lhs '+' rhs { Binary [] AddOp $1 $3 ($1 # $>) } | |
| | lhs '-' rhs { Binary [] SubOp $1 $3 ($1 # $>) } | |
| | lhs '<<' rhs { Binary [] ShlOp $1 $3 ($1 # $>) } | |
| | lhs '>>' rhs { Binary [] ShrOp $1 $3 ($1 # $>) } | |
| | lhs '&' rhs { Binary [] BitAndOp $1 $3 ($1 # $>) } | |
| | lhs '^' rhs { Binary [] BitXorOp $1 $3 ($1 # $>) } | |
| | lhs '|' rhs { Binary [] BitOrOp $1 $3 ($1 # $>) } | |
| | lhs '==' rhs { Binary [] EqOp $1 $3 ($1 # $>) } | |
| | lhs '!=' rhs { Binary [] NeOp $1 $3 ($1 # $>) } | |
| | lhs '<' rhs { Binary [] LtOp $1 $3 ($1 # $>) } | |
| | lhs '>' rhs { Binary [] GtOp $1 $3 ($1 # $>) } | |
| | lhs '<=' rhs { Binary [] LeOp $1 $3 ($1 # $>) } | |
| | lhs '>=' rhs { Binary [] GeOp $1 $3 ($1 # $>) } | |
| | lhs '&&' rhs { Binary [] AndOp $1 $3 ($1 # $>) } | |
| | lhs '||' rhs { Binary [] OrOp $1 $3 ($1 # $>) } | |
| -- range expressions | |
| | lhs '..' %prec POSTFIXRNG { Range [] (Just $1) Nothing HalfOpen ($1 # $>) } | |
| | lhs '...' %prec POSTFIXRNG { Range [] (Just $1) Nothing Closed ($1 # $>) } | |
| | lhs '..=' %prec POSTFIXRNG { Range [] (Just $1) Nothing Closed ($1 # $>) } | |
| | lhs '..' rhs2 %prec INFIXRNG { Range [] (Just $1) (Just $3) HalfOpen ($1 # $>) } | |
| | lhs '...' rhs2 %prec INFIXRNG { Range [] (Just $1) (Just $3) Closed ($1 # $>) } | |
| | lhs '..=' rhs2 %prec INFIXRNG { Range [] (Just $1) (Just $3) Closed ($1 # $>) } | |
| -- assignment expressions | |
| | lhs '<-' rhs { InPlace [] $1 $3 ($1 # $>) } | |
| | lhs '=' rhs { Assign [] $1 $3 ($1 # $>) } | |
| | lhs '>>=' rhs { AssignOp [] ShrOp $1 $3 ($1 # $>) } | |
| | lhs '<<=' rhs { AssignOp [] ShlOp $1 $3 ($1 # $>) } | |
| | lhs '-=' rhs { AssignOp [] SubOp $1 $3 ($1 # $>) } | |
| | lhs '+=' rhs { AssignOp [] AddOp $1 $3 ($1 # $>) } | |
| | lhs '*=' rhs { AssignOp [] MulOp $1 $3 ($1 # $>) } | |
| | lhs '/=' rhs { AssignOp [] DivOp $1 $3 ($1 # $>) } | |
| | lhs '^=' rhs { AssignOp [] BitXorOp $1 $3 ($1 # $>) } | |
| | lhs '|=' rhs { AssignOp [] BitOrOp $1 $3 ($1 # $>) } | |
| | lhs '&=' rhs { AssignOp [] BitAndOp $1 $3 ($1 # $>) } | |
| | lhs '%=' rhs { AssignOp [] RemOp $1 $3 ($1 # $>) } | |
| -- Postfix expressions that can come after an expression block, in a 'stmt' | |
| -- | |
| -- * `{ 1 }[0]` isn't here because it is treated as `{ 1 }; [0]` | |
| -- * `{ 1 }(0)` isn't here because it is treated as `{ 1 }; (0)` | |
| -- | |
| postfix_blockexpr(lhs) :: { Expr Span } | |
| : lhs '?' { Try [] $1 ($1 # $>) } | |
| | lhs '.' ident %prec FIELD { FieldAccess [] $1 (unspan $3) ($1 # $>) } | |
| | lhs '.' ident '(' sep_byT(expr,',') ')' | |
| { MethodCall [] $1 (unspan $3) Nothing $5 ($1 # $>) } | |
| | lhs '.' ident '::' '<' sep_byT(ty,',') '>' '(' sep_byT(expr,',') ')' | |
| { MethodCall [] $1 (unspan $3) (Just $6) $9 ($1 # $>) } | |
| | lhs '.' int {% | |
| case lit $3 of | |
| Int Dec i Unsuffixed _ -> pure (TupField [] $1 (fromIntegral i) ($1 # $3)) | |
| _ -> parseError $3 | |
| } | |
| -- Postfix expressions that can come after an expression block, in a 'stmt' | |
| -- | |
| -- * `{ 1 }[0]` isn't here because it is treated as `{ 1 }; [0]` | |
| -- * `{ 1 }(0)` isn't here because it is treated as `{ 1 }; (0)` | |
| -- | |
| postfix_blockexpr(lhs) :: { Expr Span } | |
| : lhs '?' { Try [] $1 ($1 # $>) } | |
| | lhs '.' ident %prec FIELD { FieldAccess [] $1 (unspan $3) ($1 # $>) } | |
| | lhs '.' ident '(' sep_byT(expr,',') ')' | |
| { MethodCall [] $1 (unspan $3) Nothing $5 ($1 # $>) } | |
| | lhs '.' ident '::' '<' sep_byT(ty,',') '>' '(' sep_byT(expr,',') ')' | |
| { MethodCall [] $1 (unspan $3) (Just $6) $9 ($1 # $>) } | |
| | lhs '.' int {% | |
| case lit $3 of | |
| Int Dec i Unsuffixed _ -> pure (TupField [] $1 (fromIntegral i) ($1 # $3)) | |
| _ -> parseError $3 | |
| } | |
| -- Postfix expressions that can come after an expression block, in a 'stmt' | |
| -- | |
| -- * `{ 1 }[0]` isn't here because it is treated as `{ 1 }; [0]` | |
| -- * `{ 1 }(0)` isn't here because it is treated as `{ 1 }; (0)` | |
| -- | |
| postfix_blockexpr(lhs) :: { Expr Span } | |
| : lhs '?' { Try [] $1 ($1 # $>) } | |
| | lhs '.' ident %prec FIELD { FieldAccess [] $1 (unspan $3) ($1 # $>) } | |
| | lhs '.' ident '(' sep_byT(expr,',') ')' | |
| { MethodCall [] $1 (unspan $3) Nothing $5 ($1 # $>) } | |
| | lhs '.' ident '::' '<' sep_byT(ty,',') '>' '(' sep_byT(expr,',') ')' | |
| { MethodCall [] $1 (unspan $3) (Just $6) $9 ($1 # $>) } | |
| | lhs '.' int {% | |
| case lit $3 of | |
| Int Dec i Unsuffixed _ -> pure (TupField [] $1 (fromIntegral i) ($1 # $3)) | |
| _ -> parseError $3 | |
| } | |
| -- Then, we instantiate this general production into the following families of rules: | |
| -- | |
| -- ['expr'] Most general class of expressions, no restrictions | |
| -- | |
| -- ['nostruct_expr'] Forbids struct literals (for use as scrutinee of loops, ifs, etc) | |
| -- | |
| -- ['nostructblock_expr'] Forbids struct literals and block expressions (but not block-like things | |
| -- like 'if' expressions or 'loop' expressions) | |
| -- | |
| -- ['nonblock_expr'] Forbids expressions starting with blocks (things such as '{ 1 } + 2' are | |
| -- not allowed, while struct expressions are - their "block" is at the end | |
| -- of the expression) | |
| -- | |
| -- ['blockpostfix_expr'] Allows expressions starting with blocks (things such as '{ 1 }? + 1') | |
| -- but only when the leading block is itself a postfix expression. | |
| -- | |
| -- There is also a later instantiation revolving around 'match' expressions, but it has some | |
| -- different types. | |
| expr :: { Expr Span } | |
| : gen_expression(expr,expr,expr) { $1 } | |
| | paren_expr { $1 } | |
| | struct_expr { $1 } | |
| | block_expr { $1 } | |
| | lambda_expr_block { $1 } | |
| nostruct_expr :: { Expr Span } | |
| : gen_expression(nostruct_expr,nostruct_expr,nonstructblock_expr) { $1 } | |
| | paren_expr { $1 } | |
| | block_expr { $1 } | |
| nonstructblock_expr :: { Expr Span } | |
| : gen_expression(nonstructblock_expr,nostruct_expr,nonstructblock_expr) { $1 } | |
| | paren_expr { $1 } | |
| | block_like_expr { $1 } | |
| | unsafe inner_attrs_block | |
| { let (as, Block ss r x) = $> in BlockExpr as (Block ss Unsafe ($1 # x)) ($1 # x) } | |
| nonblock_expr :: { Expr Span } | |
| : gen_expression(nonblock_expr,expr,expr) { $1 } | |
| | paren_expr { $1 } | |
| | struct_expr { $1 } | |
| | lambda_expr_block { $1 } | |
| blockpostfix_expr :: { Expr Span } | |
| : postfix_blockexpr(block_like_expr) { $1 } | |
| | postfix_blockexpr(vis_safety_block) { $1 } | |
| | left_gen_expression(blockpostfix_expr,expr,expr) { $1 } | |
| -- Finally, what remains is the more mundane definitions of particular types of expressions. | |
| -- labels on loops | |
| label :: { Label Span } | |
| : LIFETIME { let Spanned (LifetimeTok (Ident l _ _)) s = $1 in Label l s } | |
| -- Literal expressions (composed of just literals) | |
| lit_expr :: { Expr Span } | |
| : lit { Lit [] $1 (spanOf $1) } | |
| -- An expression ending in a '{ ... }' block. Useful since "There is a convenience rule that allows | |
| -- one to omit the separating ';' after 'if', 'match', 'loop', 'for', 'while'" | |
| block_expr :: { Expr Span } | |
| : block_like_expr { $1 } | |
| | inner_attrs_block { let (as,b) = $1 in BlockExpr as b (spanOf b) } | |
| | unsafe inner_attrs_block | |
| { let (as, Block ss r x) = $> in BlockExpr as (Block ss Unsafe ($1 # x)) ($1 # x) } | |
| -- Any expression ending in a '{ ... }' block except a block itself. | |
| block_like_expr :: { Expr Span } | |
| : if_expr { $1 } | |
| | loop inner_attrs_block { let (as,b) = $> in Loop as b Nothing ($1 # b) } | |
| | label ':' loop inner_attrs_block { let (as,b) = $> in Loop as b (Just $1) ($1 # b) } | |
| | for pat in nostruct_expr inner_attrs_block { let (as,b) = $> in ForLoop as $2 $4 b Nothing ($1 # b) } | |
| | label ':' for pat in nostruct_expr inner_attrs_block { let (as,b) = $> in ForLoop as $4 $6 b (Just $1) ($1 # b) } | |
| | while nostruct_expr inner_attrs_block { let (as,b) = $> in While as $2 b Nothing ($1 # b) } | |
| | label ':' while nostruct_expr inner_attrs_block { let (as,b) = $> in While as $4 b (Just $1) ($1 # b) } | |
| | while let pats '=' nostruct_expr inner_attrs_block { let (as,b) = $> in WhileLet as $3 $5 b Nothing ($1 # b) } | |
| | label ':' while let pats '=' nostruct_expr inner_attrs_block { let (as,b) = $> in WhileLet as $5 $7 b (Just $1) ($1 # b) } | |
| | match nostruct_expr '{' '}' { Match [] $2 [] ($1 # $>) } | |
| | match nostruct_expr '{' inner_attrs '}' { Match (toList $4) $2 [] ($1 # $>) } | |
| | match nostruct_expr '{' arms '}' { Match [] $2 $4 ($1 # $>) } | |
| | match nostruct_expr '{' inner_attrs arms '}' { Match (toList $4) $2 $5 ($1 # $>) } | |
| | expr_path '!' '{' token_stream '}' { MacExpr [] (Mac $1 $4 ($1 # $>)) ($1 # $>) } | |
| | do catch inner_attrs_block { let (as,b) = $> in Catch as b ($1 # b) } | |
| -- 'if' expressions are a bit special since they can have an arbitrary number of 'else if' chains. | |
| if_expr :: { Expr Span } | |
| : if nostruct_expr block else_expr { If [] $2 $3 $4 ($1 # $3 # $>) } | |
| | if let pats '=' nostruct_expr block else_expr { IfLet [] $3 $5 $6 $7 ($1 # $6 # $>) } | |
| else_expr :: { Maybe (Expr Span) } | |
| : else block { Just (BlockExpr [] $2 (spanOf $2)) } | |
| | else if_expr { Just $2 } | |
| | {- empty -} { Nothing } | |
| -- Match arms usually have to be seperated by commas (with an optional comma at the end). This | |
| -- condition is loosened (so that there is no seperator needed) if the arm ends in a safe block. | |
| arms :: { [Arm Span] } | |
| : ntArm { [$1] } | |
| | ntArm arms { $1 : $2 } | |
| | many(outer_attribute) pats arm_guard '=>' expr_arms { let (e,as) = $> in (Arm $1 $2 $3 e ($1 # $2 # e) : as) } | |
| pats :: { NonEmpty (Pat Span) } | |
| : '|' sep_by1(pat,'|') { toNonEmpty $2 } | |
| | sep_by1(pat,'|') { toNonEmpty $1 } | |
| arm_guard :: { Maybe (Expr Span) } | |
| : {- empty -} { Nothing } | |
| | if expr { Just $2 } | |
| -- Possibly more match arms, with a comma if present | |
| comma_arms :: { [Arm Span] } | |
| : {- empty -} { [] } | |
| | ',' { [] } | |
| | ',' arms { $2 } | |
| -- An expression followed by match arms. If there is a comma needed, it is added | |
| expr_arms :: { (Expr Span, [Arm Span]) } | |
| : nonblock_expr comma_arms { ($1, $2) } | |
| | blockpostfix_expr comma_arms { ($1, $2) } | |
| | vis_safety_block comma_arms { ($1, $2) } | |
| | vis_safety_block arms { ($1, $2) } | |
| | block_like_expr comma_arms { ($1, $2) } | |
| | block_like_expr arms { ($1, $2) } | |
| -- As per https://github.com/rust-lang/rust/issues/15701 (as of March 10 2017), the only way to have | |
| -- attributes on expressions should be with inner attributes on a paren expression. | |
| paren_expr :: { Expr Span } | |
| : '(' ')' { TupExpr [] [] ($1 # $>) } | |
| | '(' inner_attrs ')' { TupExpr (toList $2) [] ($1 # $>) } | |
| | '(' expr ')' { ParenExpr [] $2 ($1 # $>) } | |
| | '(' inner_attrs expr ')' { ParenExpr (toList $2) $3 ($1 # $>) } | |
| | '(' expr ',' ')' { TupExpr [] [$2] ($1 # $>) } | |
| | '(' inner_attrs expr ',' ')' { TupExpr (toList $2) [$3] ($1 # $>) } | |
| | '(' expr ',' sep_by1T(expr,',') ')' { TupExpr [] ($2 : toList $4) ($1 # $>) } | |
| | '(' inner_attrs expr ',' sep_by1T(expr,',') ')' { TupExpr (toList $2) ($3 : toList $5) ($1 # $>) } | |
| -- Closure ending in blocks | |
| lambda_expr_block :: { Expr Span } | |
| : static move lambda_args '->' ty_no_plus block | |
| { Closure [] Immovable Value (FnDecl (unspan $3) (Just $5) False (spanOf $3)) (BlockExpr [] $> (spanOf $>)) ($1 # $>) } | |
| | move lambda_args '->' ty_no_plus block | |
| { Closure [] Movable Value (FnDecl (unspan $2) (Just $4) False (spanOf $2)) (BlockExpr [] $> (spanOf $>)) ($1 # $>) } | |
| | static lambda_args '->' ty_no_plus block | |
| { Closure [] Immovable Ref (FnDecl (unspan $2) (Just $4) False (spanOf $2)) (BlockExpr [] $> (spanOf $>)) ($1 # $>) } | |
| | lambda_args '->' ty_no_plus block | |
| { Closure [] Movable Ref (FnDecl (unspan $1) (Just $3) False (spanOf $1)) (BlockExpr [] $> (spanOf $>)) ($1 # $>) } | |
| -- Lambda expression arguments block | |
| lambda_args :: { Spanned [Arg Span] } | |
| : '||' { Spanned [] (spanOf $1) } | |
| | '|' sep_byT(lambda_arg,',') pipe '|' { Spanned $2 ($1 # $4) } | |
| -- Struct expression literal | |
| struct_expr :: { Expr Span } | |
| : expr_path '{' '..' expr '}' { Struct [] $1 [] (Just $4) ($1 # $>) } | |
| | expr_path '{' inner_attrs '..' expr '}' { Struct (toList $3) $1 [] (Just $5) ($1 # $>) } | |
| | expr_path '{' sep_by1(field,',') ',' '..' expr '}' { Struct [] $1 (toList $3) (Just $6) ($1 # $>) } | |
| | expr_path '{' inner_attrs sep_by1(field,',') ',' '..' expr '}' { Struct (toList $3) $1 (toList $4) (Just $7) ($1 # $>) } | |
| | expr_path '{' sep_byT(field,',') '}' { Struct [] $1 $3 Nothing ($1 # $>) } | |
| | expr_path '{' inner_attrs sep_byT(field,',') '}' { Struct (toList $3) $1 $4 Nothing ($1 # $>) } | |
| field :: { Field Span } | |
| : ident ':' expr { Field (unspan $1) (Just $3) ($1 # $3) } | |
| | ident { Field (unspan $1) Nothing (spanOf $1) } | |
| -- an expression block that won't cause conflicts with stmts | |
| vis_safety_block :: { Expr Span } | |
| : pub_or_inherited safety inner_attrs_block {% | |
| let (as, Block ss r x) = $3 | |
| e = BlockExpr as (Block ss (unspan $2) ($2 # x)) ($2 # x) | |
| in noVis $1 e | |
| } | |
| -- an expression starting with 'union' or 'default' (as identifiers) that won't cause conflicts with stmts | |
| vis_union_def_nonblock_expr :: { Expr Span } | |
| : union_default_expr { $1 } | |
| | left_gen_expression(vis_union_def_nonblock_expr, expr, expr) { $1 } | |
| union_default_expr :: { Expr Span } | |
| : pub_or_inherited union {% | |
| noVis $1 (PathExpr [] Nothing (Path False [PathSegment "union" Nothing (spanOf $2)] (spanOf $1)) (spanOf $1)) | |
| } | |
| | pub_or_inherited default {% | |
| noVis $1 (PathExpr [] Nothing (Path False [PathSegment "default" Nothing (spanOf $2)] (spanOf $1)) (spanOf $1)) | |
| } | |
| ---------------- | |
| -- Statements -- | |
| ---------------- | |
| stmt :: { Stmt Span } | |
| : ntStmt { $1 } | |
| | many(outer_attribute) let pat ':' ty initializer ';' { Local $3 (Just $5) $6 $1 ($1 # $2 # $>) } | |
| | many(outer_attribute) let pat initializer ';' { Local $3 Nothing $4 $1 ($1 # $2 # $>) } | |
| | many(outer_attribute) nonblock_expr ';' { toStmt ($1 `addAttrs` $2) True False ($1 # $2 # $3) } | |
| | many(outer_attribute) block_like_expr ';' { toStmt ($1 `addAttrs` $2) True True ($1 # $2 # $3) } | |
| | many(outer_attribute) blockpostfix_expr ';' { toStmt ($1 `addAttrs` $2) True True ($1 # $2 # $3) } | |
| | many(outer_attribute) vis_union_def_nonblock_expr ';' { toStmt ($1 `addAttrs` $2) True False ($1 # $2 # $3) } | |
| | many(outer_attribute) block_like_expr %prec NOSEMI { toStmt ($1 `addAttrs` $2) False True ($1 # $2) } | |
| | many(outer_attribute) vis_safety_block ';' { toStmt ($1 `addAttrs` $2) True True ($1 # $2 # $>) } | |
| | many(outer_attribute) vis_safety_block %prec NOSEMI { toStmt ($1 `addAttrs` $2) False True ($1 # $2) } | |
| | gen_item(pub_or_inherited) { ItemStmt $1 (spanOf $1) } | |
| | many(outer_attribute) expr_path '!' ident '[' token_stream ']' ';' | |
| { ItemStmt (macroItem $1 (Just (unspan $4)) (Mac $2 $6 ($2 # $>)) ($1 # $2 # $>)) ($1 # $2 # $>) } | |
| | many(outer_attribute) expr_path '!' ident '(' token_stream ')' ';' | |
| { ItemStmt (macroItem $1 (Just (unspan $4)) (Mac $2 $6 ($2 # $>)) ($1 # $2 # $>)) ($1 # $2 # $>) } | |
| | many(outer_attribute) expr_path '!' ident '{' token_stream '}' | |
| { ItemStmt (macroItem $1 (Just (unspan $4)) (Mac $2 $6 ($2 # $>)) ($1 # $2 # $>)) ($1 # $2 # $>) } | |
| pub_or_inherited :: { Spanned (Visibility Span) } | |
| : pub %prec VIS { Spanned PublicV (spanOf $1) } | |
| | {- empty -} %prec VIS { pure InheritedV } | |
| stmtOrSemi :: { Maybe (Stmt Span) } | |
| : ';' { Nothing } | |
| | stmt { Just $1 } | |
| -- List of statements where the last statement might be a no-semicolon statement. | |
| stmts_possibly_no_semi :: { [Maybe (Stmt Span)] } | |
| : stmtOrSemi stmts_possibly_no_semi { $1 : $2 } | |
| | stmtOrSemi { [$1] } | |
| | many(outer_attribute) nonblock_expr { [Just (toStmt ($1 `addAttrs` $2) False False ($1 # $2))] } | |
| | many(outer_attribute) blockpostfix_expr { [Just (toStmt ($1 `addAttrs` $2) False True ($1 # $2))] } | |
| initializer :: { Maybe (Expr Span) } | |
| : '=' expr { Just $2 } | |
| | {- empty -} { Nothing } | |
| block :: { Block Span } | |
| : ntBlock { $1 } | |
| | '{' '}' { Block [] Normal ($1 # $>) } | |
| | '{' stmts_possibly_no_semi '}' { Block [ s | Just s <- $2 ] Normal ($1 # $>) } | |
| inner_attrs_block :: { ([Attribute Span], Block Span) } | |
| : block { ([], $1) } | |
| | '{' inner_attrs '}' { (toList $2, Block [] Normal ($1 # $>)) } | |
| | '{' inner_attrs stmts_possibly_no_semi '}' { (toList $2, Block [ s | Just s <- $3 ] Normal ($1 # $>)) } | |
| ----------- | |
| -- Items -- | |
| ----------- | |
| -- Given the types of permitted visibilities, generate a rule for items. The reason this production | |
| -- is useful over just having 'item :: { ItemSpan }' and then 'many(outer_attribute) vis item' is | |
| -- that (1) not all items have visibility and (2) attributes and visibility are fields on the 'Item' | |
| -- algebraic data type. | |
| gen_item(vis) :: { Item Span } | |
| : many(outer_attribute) vis static ident ':' ty '=' expr ';' | |
| { Static $1 (unspan $2) (unspan $4) $6 Immutable $8 ($1 # $2 # $3 # $>) } | |
| | many(outer_attribute) vis static mut ident ':' ty '=' expr ';' | |
| { Static $1 (unspan $2) (unspan $5) $7 Mutable $9 ($1 # $2 # $3 # $>) } | |
| | many(outer_attribute) vis const ident ':' ty '=' expr ';' | |
| { ConstItem $1 (unspan $2) (unspan $4) $6 $8 ($1 # $2 # $3 # $>) } | |
| | many(outer_attribute) vis type ident generics where_clause '=' ty ';' | |
| { TyAlias $1 (unspan $2) (unspan $4) $8 ($5 `withWhere` $6) ($1 # $2 # $3 # $>) } | |
| | many(outer_attribute) vis use use_tree ';' | |
| { Use $1 (unspan $2) $4 ($1 # $2 # $3 # $>) } | |
| | many(outer_attribute) vis safety extern crate ident ';' | |
| {% noSafety $3 (ExternCrate $1 (unspan $2) (unspan $6) Nothing ($1 # $2 # $4 # $>)) } | |
| | many(outer_attribute) vis safety extern crate ident as ident ';' | |
| {% noSafety $3 (ExternCrate $1 (unspan $2) (unspan $8) (Just (unspan $6)) ($1 # $2 # $4 # $>)) } | |
| | many(outer_attribute) vis const safety fn ident generics fn_decl(arg_named) where_clause inner_attrs_block | |
| { Fn ($1 ++ fst $>) (unspan $2) (unspan $6) $8 (unspan $4) Const Rust ($7 `withWhere` $9) (snd $>) ($1 # $2 # $3 # snd $>) } | |
| | many(outer_attribute) vis safety extern abi fn ident generics fn_decl(arg_named) where_clause inner_attrs_block | |
| { Fn ($1 ++ fst $>) (unspan $2) (unspan $7) $9 (unspan $3) NotConst $5 ($8 `withWhere` $10) (snd $>) ($1 # $2 # $3 # $4 # snd $>) } | |
| | many(outer_attribute) vis safety fn ident generics fn_decl(arg_named) where_clause inner_attrs_block | |
| { Fn ($1 ++ fst $>) (unspan $2) (unspan $5) $7 (unspan $3) NotConst Rust ($6 `withWhere` $8) (snd $>) ($1 # $2 # $3 # $4 # snd $>) } | |
| | many(outer_attribute) vis mod ident ';' | |
| { Mod $1 (unspan $2) (unspan $4) Nothing ($1 # $2 # $3 # $>) } | |
| | many(outer_attribute) vis mod ident '{' many(mod_item) '}' | |
| { Mod $1 (unspan $2) (unspan $4) (Just $6) ($1 # $2 # $3 # $>) } | |
| | many(outer_attribute) vis mod ident '{' inner_attrs many(mod_item) '}' | |
| { Mod ($1 ++ toList $6) (unspan $2) (unspan $4) (Just $7) ($1 # $2 # $3 # $>) } | |
| | many(outer_attribute) vis safety extern abi '{' many(foreign_item) '}' | |
| {% noSafety $3 (ForeignMod $1 (unspan $2) $5 $7 ($1 # $2 # $4 # $>)) } | |
| | many(outer_attribute) vis safety extern abi '{' inner_attrs many(foreign_item) '}' | |
| {% noSafety $3 (ForeignMod ($1 ++ toList $7) (unspan $2) $5 $8 ($1 # $2 # $4 # $>)) } | |
| | many(outer_attribute) vis struct ident generics struct_decl_args | |
| { StructItem $1 (unspan $2) (unspan $4) (snd $6) ($5 `withWhere` fst $6) ($1 # $2 # $3 # snd $>) } | |
| | many(outer_attribute) vis union ident generics struct_decl_args | |
| { Union $1 (unspan $2) (unspan $4) (snd $6) ($5 `withWhere` fst $6) ($1 # $2 # $3 # snd $>) } | |
| | many(outer_attribute) vis enum ident generics where_clause '{' sep_byT(enum_def,',') '}' | |
| { Enum $1 (unspan $2) (unspan $4) $8 ($5 `withWhere` $6) ($1 # $2 # $3 # $>) } | |
| | many(outer_attribute) vis safety trait ident generics ':' sep_by1T(ty_param_bound,'+') where_clause '{' many(trait_item) '}' | |
| { Trait $1 (unspan $2) (unspan $5) False (unspan $3) ($6 `withWhere` $9) (toList $8) $11 ($1 # $2 # $3 # $4 # $>) } | |
| | many(outer_attribute) vis safety trait ident generics where_clause '{' many(trait_item) '}' | |
| { Trait $1 (unspan $2) (unspan $5) False (unspan $3) ($6 `withWhere` $7) [] $9 ($1 # $2 # $3 # $4 # $>) } | |
| | many(outer_attribute) vis safety auto trait ident generics ':' sep_by1T(ty_param_bound,'+') where_clause '{' many(trait_item) '}' | |
| { Trait $1 (unspan $2) (unspan $6) True (unspan $3) ($7 `withWhere` $10) (toList $9) $12 ($1 # $2 # $3 # $5 # $>) } | |
| | many(outer_attribute) vis safety auto trait ident generics where_clause '{' many(trait_item) '}' | |
| { Trait $1 (unspan $2) (unspan $6) True (unspan $3) ($7 `withWhere` $8) [] $10 ($1 # $2 # $3 # $5 # $>) } | |
| | many(outer_attribute) vis safety trait ident generics '=' sep_by1T(ty_param_bound,'+') ';' | |
| {% noSafety $3 (TraitAlias $1 (unspan $2) (unspan $5) $6 (toNonEmpty $8) ($1 # $2 # $3 # $>)) } | |
| | many(outer_attribute) vis safety impl generics ty_prim where_clause '{' impl_items '}' | |
| { Impl ($1 ++ fst $9) (unspan $2) Final (unspan $3) Positive ($5 `withWhere` $7) Nothing $6 (snd $9) ($1 # $2 # $3 # $4 # $5 # $>) } | |
| | many(outer_attribute) vis default safety impl generics ty_prim where_clause '{' impl_items '}' | |
| { Impl ($1 ++ fst $10) (unspan $2) Default (unspan $4) Positive ($6 `withWhere` $8) Nothing $7 (snd $10) ($1 # $2 # $3 # $4 # $5 # $>) } | |
| | many(outer_attribute) vis safety impl generics '(' ty_no_plus ')' where_clause '{' impl_items '}' | |
| { Impl ($1 ++ fst $11) (unspan $2) Final (unspan $3) Positive ($5 `withWhere` $9) Nothing (ParenTy $7 ($6 # $8)) (snd $11) ($1 # $2 # $3 # $4 # $5 # $>) } | |
| | many(outer_attribute) vis default safety impl generics '(' ty_no_plus ')' where_clause '{' impl_items '}' | |
| { Impl ($1 ++ fst $12) (unspan $2) Default (unspan $4) Positive ($6 `withWhere` $10) Nothing (ParenTy $8 ($7 # $9)) (snd $12) ($1 # $2 # $3 # $4 # $5 # $>) } | |
| | many(outer_attribute) vis safety impl generics '!' trait_ref for ty where_clause '{' impl_items '}' | |
| { Impl ($1 ++ fst $12) (unspan $2) Final (unspan $3) Negative ($5 `withWhere` $10) (Just $7) $9 (snd $12) ($1 # $2 # $3 # $4 # $5 # $>) } | |
| | many(outer_attribute) vis default safety impl generics '!' trait_ref for ty where_clause '{' impl_items '}' | |
| { Impl ($1 ++ fst $13) (unspan $2) Default (unspan $4) Negative ($6 `withWhere` $11) (Just $8) $10 (snd $13) ($1 # $2 # $3 # $4 # $5 # $>) } | |
| | many(outer_attribute) vis safety impl generics trait_ref for ty where_clause '{' impl_items '}' | |
| { Impl ($1 ++ fst $11) (unspan $2) Final (unspan $3) Positive ($5 `withWhere` $9) (Just $6) $8 (snd $11) ($1 # $2 # $3 # $4 # $5 # $>) } | |
| | many(outer_attribute) vis default safety impl generics trait_ref for ty where_clause '{' impl_items '}' | |
| { Impl ($1 ++ fst $12) (unspan $2) Default (unspan $4) Positive ($6 `withWhere` $10) (Just $7) $9 (snd $12) ($1 # $2 # $3 # $4 # $5 # $>) } | |
| -- Most general type of item | |
| mod_item :: { Item Span } | |
| : ntItem { $1 } | |
| | gen_item(vis) { $1 } | |
| | many(outer_attribute) expr_path '!' ident '[' token_stream ']' ';' | |
| { macroItem $1 (Just (unspan $4)) (Mac $2 $6 ($2 # $>)) ($1 # $2 # $>) } | |
| | many(outer_attribute) expr_path '!' '[' token_stream ']' ';' | |
| { macroItem $1 Nothing (Mac $2 $5 ($2 # $>)) ($1 # $2 # $>) } | |
| | many(outer_attribute) expr_path '!' ident '(' token_stream ')' ';' | |
| { macroItem $1 (Just (unspan $4)) (Mac $2 $6 ($2 # $>)) ($1 # $2 # $>) } | |
| | many(outer_attribute) expr_path '!' '(' token_stream ')' ';' | |
| { macroItem $1 Nothing (Mac $2 $5 ($2 # $>)) ($1 # $2 # $>) } | |
| | many(outer_attribute) expr_path '!' ident '{' token_stream '}' | |
| { macroItem $1 (Just (unspan $4)) (Mac $2 $6 ($2 # $>)) ($1 # $2 # $>) } | |
| | many(outer_attribute) expr_path '!' '{' token_stream '}' | |
| { macroItem $1 Nothing (Mac $2 $5 ($2 # $>)) ($1 # $2 # $>) } | |
| foreign_item :: { ForeignItem Span } | |
| : many(outer_attribute) vis static ident ':' ty ';' | |
| { ForeignStatic $1 (unspan $2) (unspan $4) $6 Immutable ($1 # $2 # $>) } | |
| | many(outer_attribute) vis static mut ident ':' ty ';' | |
| { ForeignStatic $1 (unspan $2) (unspan $5) $7 Mutable ($1 # $2 # $>) } | |
| | many(outer_attribute) vis fn ident generics fn_decl(arg_named) where_clause ';' | |
| { ForeignFn $1 (unspan $2) (unspan $4) $6 ($5 `withWhere` $7) ($1 # $2 # $>) } | |
| | many(outer_attribute) vis type ident ';' | |
| { ForeignTy $1 (unspan $2) (unspan $4) ($1 # $2 # $>) } | |
| -- parse_generics | |
| -- Leaves the WhereClause empty | |
| generics :: { Generics Span } | |
| : ntGenerics { $1 } | |
| | '<' sep_by1(lifetime_def,',') ',' sep_by1T(ty_param,',') gt '>' { Generics (toList $2) (toList $4) (WhereClause [] mempty) ($1 # $>) } | |
| | '<' sep_by1T(lifetime_def,',') gt '>' { Generics (toList $2) [] (WhereClause [] mempty) ($1 # $>) } | |
| | '<' sep_by1T(ty_param,',') gt '>' { Generics [] (toList $2) (WhereClause [] mempty) ($1 # $>) } | |
| | '<' gt '>' { Generics [] [] (WhereClause [] mempty) ($1 # $>) } | |
| | {- empty -} { Generics [] [] (WhereClause [] mempty) mempty } | |
| ty_param :: { TyParam Span } | |
| : many(outer_attribute) ident { TyParam $1 (unspan $2) [] Nothing ($1 # $>) } | |
| | many(outer_attribute) ident ':' sep_by1T(ty_param_bound_mod,'+') { TyParam $1 (unspan $2) (toList $4) Nothing ($1 # $>) } | |
| | many(outer_attribute) ident '=' ty { TyParam $1 (unspan $2) [] (Just $>) ($1 # $>) } | |
| | many(outer_attribute) ident ':' sep_by1T(ty_param_bound_mod,'+') '=' ty { TyParam $1 (unspan $2) (toList $4) (Just $>) ($1 # $>) } | |
| struct_decl_args :: { (WhereClause Span, VariantData Span) } | |
| : where_clause ';' { ($1, UnitD ($1 # $>)) } | |
| | where_clause '{' sep_byT(struct_decl_field,',') '}' { ($1, StructD $3 ($1 # $>)) } | |
| | '(' sep_byT(tuple_decl_field,',') ')' where_clause ';' { ($4, TupleD $2 ($1 # $>)) } | |
| struct_decl_field :: { StructField Span } | |
| : many(outer_attribute) vis ident ':' ty { StructField (Just (unspan $3)) (unspan $2) $5 $1 ($1 # $2 # $5) } | |
| tuple_decl_field :: { StructField Span } | |
| : many(outer_attribute) vis ty { StructField Nothing (unspan $2) $3 $1 ($1 # $2 # $3) } | |
| enum_def :: { Variant Span } | |
| : many(outer_attribute) ident '{' sep_byT(struct_decl_field,',') '}' { Variant (unspan $2) $1 (StructD $4 ($3 # $5)) Nothing ($1 # $2 # $>) } | |
| | many(outer_attribute) ident '(' sep_byT(tuple_decl_field,',') ')' { Variant (unspan $2) $1 (TupleD $4 ($3 # $5)) Nothing ($1 # $2 # $>) } | |
| | many(outer_attribute) ident initializer { Variant (unspan $2) $1 (UnitD mempty) $3 ($1 # $2 # $>) } | |
| -- parse_where_clause | |
| where_clause :: { WhereClause Span } | |
| : {- empty -} { WhereClause [] mempty } | |
| | ntWhereClause { $1 } | |
| | where sep_by(where_predicate,',') %prec WHERE { WhereClause $2 ($1 # $2) } | |
| | where sep_by1(where_predicate,',') ',' %prec WHERE { WhereClause (toList $2) ($1 # $3) } | |
| where_predicate :: { WherePredicate Span } | |
| : lifetime { RegionPredicate $1 [] (spanOf $1) } | |
| | lifetime ':' sep_by1T(lifetime,'+') { RegionPredicate $1 (toList $3) ($1 # $3) } | |
| | no_for_ty %prec EQ { BoundPredicate [] $1 [] (spanOf $1) } | |
| | no_for_ty '=' ty { EqPredicate $1 $3 ($1 # $3) } | |
| | no_for_ty '==' ty { EqPredicate $1 $3 ($1 # $3) } | |
| | no_for_ty ':' sep_by1T(ty_param_bound_mod,'+') { BoundPredicate [] $1 (toList $3) ($1 # $3) } | |
| | for_lts no_for_ty { BoundPredicate (unspan $1) $2 [] ($1 # $2) } | |
| | for_lts no_for_ty ':' sep_by1T(ty_param_bound_mod,'+') { BoundPredicate (unspan $1) $2 (toList $4) ($1 # $>) } | |
| impl_items :: { ([Attribute Span], [ImplItem Span]) } | |
| : many(impl_item) { ([], $1) } | |
| | inner_attrs many(impl_item) { (toList $1, $2) } | |
| impl_item :: { ImplItem Span } | |
| : ntImplItem { $1 } | |
| | many(outer_attribute) vis def type ident '=' ty ';' { TypeI $1 (unspan $2) (unspan $3) (unspan $5) $7 ($1 # $2 # $3 # $4 # $>) } | |
| | many(outer_attribute) vis def const ident ':' ty '=' expr ';' { ConstI $1 (unspan $2) (unspan $3) (unspan $5) $7 $9 ($1 # $2 # $3 # $4 # $>) } | |
| | many(outer_attribute) def mod_mac { MacroI $1 (unspan $2) $3 ($1 # $2 # $>) } | |
| | many(outer_attribute) vis def const safety fn ident generics fn_decl_with_self_named where_clause inner_attrs_block | |
| { let methodSig = MethodSig (unspan $5) Const Rust $9; generics = $8 `withWhere` $10 | |
| in MethodI ($1 ++ fst $>) (unspan $2) (unspan $3) (unspan $7) generics methodSig (snd $>) ($1 # $2 # $3 # $4 # snd $>) } | |
| | many(outer_attribute) vis def safety ext_abi fn ident generics fn_decl_with_self_named where_clause inner_attrs_block | |
| { let methodSig = MethodSig (unspan $4) NotConst (unspan $5) $9; generics = $8 `withWhere` $10 | |
| in MethodI ($1 ++ fst $>) (unspan $2) (unspan $3) (unspan $7) generics methodSig (snd $>) ($1 # $2 # $3 # $4 # $5 # $6 # snd $>) } | |
| trait_item :: { TraitItem Span } | |
| : ntTraitItem { $1 } | |
| | many(outer_attribute) const ident ':' ty initializer ';' { ConstT $1 (unspan $3) $5 $6 ($1 # $2 # $>) } | |
| | many(outer_attribute) mod_mac { MacroT $1 $2 ($1 # $>) } | |
| | many(outer_attribute) type ident ';' { TypeT $1 (unspan $3) [] Nothing ($1 # $2 # $>) } | |
| | many(outer_attribute) type ident '=' ty ';' { TypeT $1 (unspan $3) [] (Just $5) ($1 # $2 # $>) } | |
| | many(outer_attribute) type ident ':' sep_by1T(ty_param_bound_mod,'+') ';' | |
| { TypeT $1 (unspan $3) (toList $5) Nothing ($1 # $2 # $>) } | |
| | many(outer_attribute) type ident ':' sep_by1T(ty_param_bound_mod,'+') '=' ty ';' | |
| { TypeT $1 (unspan $3) (toList $5) (Just $7) ($1 # $2 # $>) } | |
| | many(outer_attribute) safety ext_abi fn ident generics fn_decl_with_self_general where_clause ';' | |
| { let methodSig = MethodSig (unspan $2) NotConst (unspan $3) $7; generics = $6 `withWhere` $8 | |
| in MethodT $1 (unspan $5) generics methodSig Nothing ($1 # $2 # $3 # $4 # $>) } | |
| | many(outer_attribute) safety ext_abi fn ident generics fn_decl_with_self_general where_clause inner_attrs_block | |
| { let methodSig = MethodSig (unspan $2) NotConst (unspan $3) $7; generics = $6 `withWhere` $8 | |
| in MethodT ($1 ++ fst $>) (unspan $5) generics methodSig (Just (snd $>)) ($1 # $2 # $3 # $4 # snd $>) } | |
| safety :: { Spanned Unsafety } | |
| : {- empty -} { pure Normal } | |
| | unsafe { Spanned Unsafe (spanOf $1) } | |
| ext_abi :: { Spanned Abi } | |
| : {- empty -} { pure Rust } | |
| | extern abi { Spanned $2 (spanOf $1) } | |
| vis :: { Spanned (Visibility Span) } | |
| : {- empty -} %prec VIS { Spanned InheritedV mempty } | |
| | pub %prec VIS { Spanned PublicV (spanOf $1) } | |
| | pub '(' crate ')' { Spanned CrateV ($1 # $4) } | |
| | crate { Spanned CrateV (spanOf $1) } | |
| | pub '(' in mod_path ')' { Spanned (RestrictedV $4) ($1 # $5) } | |
| | pub '(' super ')' { Spanned (RestrictedV (Path False [PathSegment "super" Nothing (spanOf | |
| $3)] (spanOf $3))) ($1 # $4) } | |
| | pub '(' self ')' { Spanned (RestrictedV (Path False [PathSegment "self" Nothing (spanOf | |
| $3)] (spanOf $3))) ($1 # $4) } | |
| def :: { Spanned Defaultness } | |
| : {- empty -} %prec DEF { pure Final } | |
| | default { Spanned Default (spanOf $1) } | |
| use_tree :: { UseTree Span } | |
| : mod_path { UseTreeSimple $1 Nothing (spanOf $1) } | |
| | mod_path as ident { UseTreeSimple $1 (Just (unspan $3)) ($1 # $3) } | |
| | mod_path '::' '*' { UseTreeGlob $1 ($1 # $3) } | |
| | '::' '*' { UseTreeGlob (Path True [] (spanOf $1)) ($1 # $2) } | |
| | '*' { UseTreeGlob (Path False [] mempty) (spanOf $1) } | |
| | mod_path '::' '{' sep_byT(use_tree,',') '}' { UseTreeNested $1 $4 ($1 # $>) } | |
| | '::' '{' sep_byT(use_tree,',') '}' { UseTreeNested (Path True [] (spanOf $1)) $3 ($1 # $>) } | |
| | '{' sep_byT(use_tree,',') '}' { UseTreeNested (Path False [] mempty) $2 ($1 # $>) } | |
| ------------------- | |
| -- Macro related -- | |
| ------------------- | |
| expr_mac :: { Mac Span } | |
| : expr_path '!' '[' token_stream ']' { Mac $1 $4 ($1 # $>) } | |
| | expr_path '!' '(' token_stream ')' { Mac $1 $4 ($1 # $>) } | |
| ty_mac :: { Mac Span } | |
| : ty_path '!' '[' token_stream ']' { Mac $1 $4 ($1 # $>) } | |
| | ty_path '!' '{' token_stream '}' { Mac $1 $4 ($1 # $>) } | |
| | ty_path '!' '(' token_stream ')' { Mac $1 $4 ($1 # $>) } | |
| mod_mac :: { Mac Span } | |
| : mod_path '!' '[' token_stream ']' ';' { Mac $1 $4 ($1 # $>) } | |
| | mod_path '!' '{' token_stream '}' { Mac $1 $4 ($1 # $>) } | |
| | mod_path '!' '(' token_stream ')' ';' { Mac $1 $4 ($1 # $>) } | |
| token_stream :: { TokenStream } | |
| : {- empty -} { Stream [] } | |
| | some(token_tree) { | |
| case $1 of | |
| [tt] -> Tree tt | |
| tts -> Stream [ Tree tt | tt <- toList tts ] | |
| } | |
| token_tree :: { TokenTree } | |
| : ntTT { $1 } | |
| -- # Delimited | |
| | '(' token_stream ')' { Delimited ($1 # $3) Paren $2 } | |
| | '{' token_stream '}' { Delimited ($1 # $3) Brace $2 } | |
| | '[' token_stream ']' { Delimited ($1 # $3) Bracket $2 } | |
| -- # Token | |
| | token { let Spanned t s = $1 in Token s t } | |
| token :: { Spanned Token } | |
| : '=' { $1 } | |
| | '<' { $1 } | |
| | '>' { $1 } | |
| | '!' { $1 } | |
| | '~' { $1 } | |
| | '-' { $1 } | |
| | '/' { $1 } | |
| | '+' { $1 } | |
| | '*' { $1 } | |
| | '%' { $1 } | |
| | '^' { $1 } | |
| | '&' { $1 } | |
| | '|' { $1 } | |
| | '<<=' { $1 } | |
| | '>>=' { $1 } | |
| | '-=' { $1 } | |
| | '&=' { $1 } | |
| | '|=' { $1 } | |
| | '+=' { $1 } | |
| | '*=' { $1 } | |
| | '/=' { $1 } | |
| | '^=' { $1 } | |
| | '%=' { $1 } | |
| | '||' { $1 } | |
| | '&&' { $1 } | |
| | '==' { $1 } | |
| | '!=' { $1 } | |
| | '<=' { $1 } | |
| | '>=' { $1 } | |
| | '<<' { $1 } | |
| | '>>' { $1 } | |
| -- Structural symbols. | |
| | '@' { $1 } | |
| | '...' { $1 } | |
| | '..=' { $1 } | |
| | '..' { $1 } | |
| | '.' { $1 } | |
| | ',' { $1 } | |
| | ';' { $1 } | |
| | '::' { $1 } | |
| | ':' { $1 } | |
| | '->' { $1 } | |
| | '<-' { $1 } | |
| | '=>' { $1 } | |
| | '#' { $1 } | |
| | '$' { $1 } | |
| | '?' { $1 } | |
| | '#!' { $1 } | |
| -- Literals. | |
| | byte { $1 } | |
| | char { $1 } | |
| | int { $1 } | |
| | float { $1 } | |
| | str { $1 } | |
| | byteStr { $1 } | |
| | rawStr { $1 } | |
| | rawByteStr { $1 } | |
| -- Strict keywords used in the language | |
| | as { $1 } | |
| | box { $1 } | |
| | break { $1 } | |
| | const { $1 } | |
| | continue { $1 } | |
| | crate { $1 } | |
| | else { $1 } | |
| | enum { $1 } | |
| | extern { $1 } | |
| | false { $1 } | |
| | fn { $1 } | |
| | for { $1 } | |
| | if { $1 } | |
| | impl { $1 } | |
| | in { $1 } | |
| | let { $1 } | |
| | loop { $1 } | |
| | match { $1 } | |
| | mod { $1 } | |
| | move { $1 } | |
| | mut { $1 } | |
| | pub { $1 } | |
| | ref { $1 } | |
| | return { $1 } | |
| | Self { $1 } | |
| | self { $1 } | |
| | static { $1 } | |
| | struct { $1 } | |
| | super { $1 } | |
| | trait { $1 } | |
| | true { $1 } | |
| | type { $1 } | |
| | unsafe { $1 } | |
| | use { $1 } | |
| | where { $1 } | |
| | while { $1 } | |
| -- Keywords reserved for future use | |
| | abstract { $1 } | |
| | alignof { $1 } | |
| | become { $1 } | |
| | do { $1 } | |
| | final { $1 } | |
| | macro { $1 } | |
| | offsetof { $1 } | |
| | override { $1 } | |
| | priv { $1 } | |
| | proc { $1 } | |
| | pure { $1 } | |
| | sizeof { $1 } | |
| | typeof { $1 } | |
| | unsized { $1 } | |
| | virtual { $1 } | |
| -- Weak keywords, have special meaning only in specific contexts. | |
| | default { $1 } | |
| | union { $1 } | |
| | catch { $1 } | |
| | auto { $1 } | |
| | yield { $1 } | |
| | dyn { $1 } | |
| -- Comments | |
| | outerDoc { $1 } | |
| | innerDoc { $1 } | |
| -- Identifiers. | |
| | IDENT { $1 } | |
| | '_' { $1 } | |
| -- Lifetimes. | |
| | LIFETIME { $1 } | |
| --------------------- | |
| -- Just for export -- | |
| --------------------- | |
| -- These rules aren't used anywhere in the grammar above, they just provide a more general parsers. | |
| -- Any attribute | |
| export_attribute :: { Attribute Span } | |
| : inner_attribute { $1 } | |
| | outer_attribute { $1 } | |
| -- Complete blocks | |
| export_block :: { Block Span } | |
| : ntBlock { $1 } | |
| | safety '{' '}' { Block [] (unspan $1) ($1 # $2 # $>) } | |
| | safety '{' stmts_possibly_no_semi '}' { Block [ s | Just s <- $3 ] (unspan $1) ($1 # $2 # $>) } | |
| { | |
| -- | Parser for literals. | |
| parseLit :: P (Lit Span) | |
| -- | Parser for attributes. | |
| parseAttr :: P (Attribute Span) | |
| -- | Parser for types. | |
| parseTy :: P (Ty Span) | |
| -- | Parser for patterns. | |
| parsePat :: P (Pat Span) | |
| -- | Parser for statements. | |
| parseStmt :: P (Stmt Span) | |
| -- | Parser for expressions. | |
| parseExpr :: P (Expr Span) | |
| -- | Parser for items. | |
| parseItem :: P (Item Span) | |
| -- | Parser for blocks. | |
| parseBlock :: P (Block Span) | |
| -- | Parser for @impl@ items. | |
| parseImplItem :: P (ImplItem Span) | |
| -- | Parser for @trait@ items. | |
| parseTraitItem :: P (TraitItem Span) | |
| -- | Parser for token trees. | |
| parseTt :: P TokenTree | |
| -- | Parser for token streams. | |
| parseTokenStream :: P TokenStream | |
| -- | Parser for lifetime definitions. | |
| parseLifetimeDef :: P (LifetimeDef Span) | |
| -- | Parser for a type parameter. | |
| parseTyParam :: P (TyParam Span) | |
| -- | Parser for a where clause. | |
| parseWhereClause :: P (WhereClause Span) | |
| -- | Parser for generics (although 'WhereClause' is always empty here). | |
| parseGenerics :: P (Generics Span) | |
| -- | Generate a nice looking error message based on expected tokens | |
| expParseError :: (Spanned Token, [String]) -> P a | |
| expParseError (Spanned t _, exps) = fail $ "Syntax error: unexpected `" ++ show t ++ "'" ++ | |
| case go (sort exps) [] replacements of | |
| [] -> "" | |
| [s] -> " (expected " ++ s ++ ")" | |
| [s2,s1] -> " (expected " ++ s1 ++ " or " ++ s2 ++ ")" | |
| (s : ss) -> " (expected " ++ (reverse ss >>= (++ ", ")) ++ "or " ++ s ++ ")" | |
| where | |
| go [] msgs _ = msgs | |
| go (e:es) msgs rs | e `elem` ignore = go es msgs rs | |
| go (e:es) msgs [] = go es (e : msgs) [] | |
| go es msgs ((rep,msg):rs) | |
| | rep `isSubsequenceOf` es = go (es \\ rep) (msg : msgs) rs | |
| | otherwise = go es msgs rs | |
| ignore = words "ntItem ntBlock ntStmt ntPat ntExpr ntTy ntIdent ntPath ntTT" ++ | |
| words "ntArm ntImplItem ntTraitItem ntGenerics ntWhereClause ntArg ntLit" | |
| replacements = map (\(ks,v) -> (sort ks,v)) $ | |
| [ (expr, "an expression" ) | |
| , (lit, "a literal" ) | |
| , (boolLit, "a boolean" ) | |
| , (byteLit, "a byte" ) | |
| , (charLit, "a character" ) | |
| , (intLit, "an int" ) | |
| , (floatLit, "a float" ) | |
| , (strLit, "a string" ) | |
| , (byteStrLit, "a byte string" ) | |
| , (rawStrLit, "a raw string" ) | |
| , (rawByteStrLit, "a raw bytestring") | |
| , (doc, "a doc" ) | |
| , (outerDoc, "an outer doc" ) | |
| , (innerDoc, "an inner doc" ) | |
| , (identifier, "an identifier" ) | |
| , (lifetime, "a lifetime" ) | |
| ] | |
| expr :: [String] | |
| expr = lit ++ identifier ++ lifetime ++ | |
| words "'<' '!' '-' '*' '&' '|' '...' '..=' '..' '::'" ++ | |
| words "'||' '&&' '<<' '(' '[' '{' box break continue" ++ | |
| words "for if loop match move return Self self " ++ | |
| words "static super unsafe while do default union " ++ | |
| words "catch auto yield dyn" | |
| lit = boolLit ++ byteLit ++ charLit ++ intLit ++ floatLit ++ strLit ++ | |
| byteStrLit ++ rawStrLit ++ rawByteStrLit | |
| boolLit = words "true false" | |
| byteLit = words "byte" | |
| charLit = words "char" | |
| intLit = words "int" | |
| floatLit = words "float" | |
| strLit = words "str" | |
| byteStrLit = words "byteStr" | |
| rawStrLit = words "rawStr" | |
| rawByteStrLit = words "rawByteStr" | |
| doc = outerDoc ++ innerDoc | |
| outerDoc = words "outerDoc" | |
| innerDoc = words "innerDoc" | |
| identifier = words "IDENT" | |
| lifetime = words "LIFETIME" | |
| -- | Convert an 'IdentTok' into an 'Ident' | |
| toIdent :: Spanned Token -> Spanned Ident | |
| toIdent (Spanned (IdentTok i) s) = Spanned i s | |
| -- | Try to convert an expression to a statement given information about whether there is a trailing | |
| -- semicolon | |
| toStmt :: Expr Span -> Bool -> Bool -> Span -> Stmt Span | |
| toStmt (MacExpr a m s) hasSemi isBlock | hasSemi = MacStmt m SemicolonMac a | |
| | isBlock = MacStmt m BracesMac a | |
| toStmt e hasSemi _ = (if hasSemi then Semi else NoSemi) e | |
| -- | Return the second argument, as long as the visibility is 'InheritedV' | |
| noVis :: Spanned (Visibility Span) -> a -> P a | |
| noVis (Spanned InheritedV _) x = pure x | |
| noVis _ _ = fail "visibility is not allowed here" | |
| -- | Fill in the where clause in a generic | |
| withWhere :: Generics a -> WhereClause a -> Generics a | |
| withWhere (Generics l t _ x) w = Generics l t w x | |
| -- | Return the second argument, as long as the safety is 'Normal' | |
| noSafety :: Spanned Unsafety -> a -> P a | |
| noSafety (Spanned Normal _) x = pure x | |
| noSafety _ _ = fail "safety is not allowed here" | |
| -- | Make a macro item, which may be a 'MacroDef' | |
| macroItem :: [Attribute Span] -> (Maybe Ident) -> Mac Span -> Span -> Item Span | |
| macroItem as (Just i) (Mac (Path False [PathSegment "macro_rules" Nothing _] _) tts _) x = MacroDef as i tts x | |
| macroItem as i mac x = MacItem as i mac x | |
| -- | Add attributes to an expression | |
| addAttrs :: [Attribute Span] -> Expr Span -> Expr Span | |
| addAttrs as (Box as' e s) = Box (as ++ as') e s | |
| addAttrs as (InPlace as' e1 e2 s) = InPlace (as ++ as') e1 e2 s | |
| addAttrs as (Vec as' e s) = Vec (as ++ as') e s | |
| addAttrs as (Call as' f es s) = Call (as ++ as') f es s | |
| addAttrs as (MethodCall as' i s tys es s') = MethodCall (as ++ as') i s tys es s' | |
| addAttrs as (TupExpr as' e s) = TupExpr (as ++ as') e s | |
| addAttrs as (Binary as' b e1 e2 s) = Binary (as ++ as') b e1 e2 s | |
| addAttrs as (Unary as' u e s) = Unary (as ++ as') u e s | |
| addAttrs as (Lit as' l s) = Lit (as ++ as') l s | |
| addAttrs as (Cast as' e t s) = Cast (as ++ as') e t s | |
| addAttrs as (TypeAscription as' e t s) = TypeAscription (as ++ as') e t s | |
| addAttrs as (If as' e1 b b2 s) = If (as ++ as') e1 b b2 s | |
| addAttrs as (IfLet as' p e b em s) = IfLet (as ++ as') p e b em s | |
| addAttrs as (While as' e b l s) = While (as ++ as') e b l s | |
| addAttrs as (WhileLet as' p e b l s) = WhileLet (as ++ as') p e b l s | |
| addAttrs as (ForLoop as' p e b l s) = ForLoop (as ++ as') p e b l s | |
| addAttrs as (Loop as' b l s) = Loop (as ++ as') b l s | |
| addAttrs as (Match as' e a s) = Match (as ++ as') e a s | |
| addAttrs as (Closure as' m c f e s) = Closure (as ++ as') m c f e s | |
| addAttrs as (BlockExpr as' b s) = BlockExpr (as ++ as') b s | |
| addAttrs as (Catch as' b s) = Catch (as ++ as') b s | |
| addAttrs as (Assign as' e1 e2 s) = Assign (as ++ as') e1 e2 s | |
| addAttrs as (AssignOp as' b e1 e2 s) = AssignOp (as ++ as') b e1 e2 s | |
| addAttrs as (FieldAccess as' e i s) = FieldAccess (as ++ as') e i s | |
| addAttrs as (TupField as' e i s) = TupField (as ++ as') e i s | |
| addAttrs as (Index as' e1 e2 s) = Index (as ++ as') e1 e2 s | |
| addAttrs as (Range as' e1 e2 r s) = Range (as ++ as') e1 e2 r s | |
| addAttrs as (PathExpr as' q p s) = PathExpr (as ++ as') q p s | |
| addAttrs as (AddrOf as' m e s) = AddrOf (as ++ as') m e s | |
| addAttrs as (Break as' l e s) = Break (as ++ as') l e s | |
| addAttrs as (Continue as' l s) = Continue (as ++ as') l s | |
| addAttrs as (Ret as' e s) = Ret (as ++ as') e s | |
| addAttrs as (MacExpr as' m s) = MacExpr (as ++ as') m s | |
| addAttrs as (Struct as' p f e a) = Struct (as ++ as') p f e a | |
| addAttrs as (Repeat as' e1 e2 s) = Repeat (as ++ as') e1 e2 s | |
| addAttrs as (ParenExpr as' e s) = ParenExpr (as ++ as') e s | |
| addAttrs as (Try as' e s) = Try (as ++ as') e s | |
| addAttrs as (Yield as' e s) = Yield (as ++ as') e s | |
| -- | Given a 'LitTok' token that is expected to result in a valid literal, construct the associated | |
| -- literal. Note that this should _never_ fail on a token produced by the lexer. | |
| lit :: Spanned Token -> Lit Span | |
| lit (Spanned (IdentTok (Ident "true" False _)) s) = Bool True Unsuffixed s | |
| lit (Spanned (IdentTok (Ident "false" False _)) s) = Bool False Unsuffixed s | |
| lit (Spanned (LiteralTok litTok suffix_m) s) = translateLit litTok suffix s | |
| where | |
| suffix = case suffix_m of | |
| Nothing -> Unsuffixed | |
| (Just "isize") -> Is | |
| (Just "usize") -> Us | |
| (Just "i8") -> I8 | |
| (Just "u8") -> U8 | |
| (Just "i16") -> I16 | |
| (Just "u16") -> U16 | |
| (Just "i32") -> I32 | |
| (Just "u32") -> U32 | |
| (Just "i64") -> I64 | |
| (Just "u64") -> U64 | |
| (Just "i128") -> I128 | |
| (Just "u128") -> U128 | |
| (Just "f32") -> F32 | |
| (Just "f64") -> F64 | |
| _ -> error "invalid literal" | |
| isTraitTyParamBound TraitTyParamBound{} = True | |
| isTraitTyParamBound _ = False | |
| -- | Parse a source file | |
| parseSourceFile :: P (SourceFile Span) | |
| parseSourceFile = do | |
| sh <- lexShebangLine | |
| (as,items) <- parseSourceFileContents | |
| pure (SourceFile sh as items) | |
| -- | Nudge the span endpoints of a 'Span' value | |
| nudge :: Int -> Int -> Span -> Span | |
| nudge leftSide rightSide (Span l r) = Span l' r' | |
| where l' = incPos l leftSide | |
| r' = incPos r rightSide | |
| -- Functions related to `NonEmpty` that really should already exist... | |
| -- | Append an element to a list to get a nonempty list (flipped version of '(:|)') | |
| (|:) :: [a] -> a -> NonEmpty a | |
| [] |: y = y :| [] | |
| (x:xs) |: y = x :| (xs ++ [y]) | |
| -- | Append an element to a nonempty list to get anothg nonempty list (flipped version of '(<|)') | |
| (|>) :: NonEmpty a -> a -> NonEmpty a | |
| (x:|xs) |> y = x :| (xs ++ [y]) | |
| } |