Skip to content
Permalink
Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1959 lines (1706 sloc) 95.4 KB
{
{-|
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])
}
You can’t perform that action at this time.