diff --git a/appveyor.yml b/.appveyor.yml similarity index 88% rename from appveyor.yml rename to .appveyor.yml index 6dde16a..44fb825 100644 --- a/appveyor.yml +++ b/.appveyor.yml @@ -4,14 +4,15 @@ clone_folder: c:\language-rust # Add new environments to the build here: environment: matrix: - # - resolver: lts-6.35 # ghc-7.10.3 - # - resolver: lts-7.24 # ghc-8.0.1 - # - resolver: lts-9.21 # ghc-8.0.2 - resolver: lts-11.22 # ghc-8.2.2 - resolver: lts-12.14 # ghc-8.4.4 - resolver: lts-14.4 # ghc-8.6.5 - resolver: nightly +matrix: + allow_failures: + - resolver: nightly + # Manually fetch stack install: - set PATH=C:\Program Files\Git\mingw64\bin;%PATH% diff --git a/.gitignore b/.gitignore index 37fb369..311a61e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,8 +13,9 @@ bench/allocations/ bench/timings/ # Sample source files -sample-sources/ +sample-sources/* !sample-sources/attributes.rs +!sample-sources/difficult.rs !sample-sources/empty.rs !sample-sources/expressions.rs !sample-sources/items.rs @@ -26,3 +27,4 @@ sample-sources/ !sample-sources/statement-expressions.rs !sample-sources/statements.rs !sample-sources/types.rs +!sample-sources/visibility.rs diff --git a/ChangeLog.md b/ChangeLog.md index 2eec9d3..6a87a6b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,24 @@ # Revision history for language-rust +## 0.3.0.39 -- 2019-11-01 + +* Bump Rust version + - async blocks, async closures, async functions + - try blocks + - await + - or-patterns + - associated type constraints + - macro definitions (fixes #31) + - optional discriminator (::) in type paths + - foreign macros + +* Fix a couple old issues + - parsing of expressions which conflict with statements is much more robust + - parsing of expressions in the no-struct context + - handle semicolons more like rustc + +* Test harnesses have more options for skipping, removing, etc. tests + ## 0.2.0.27 -- 2018-04-22 * Bump Rust version diff --git a/README.md b/README.md index 4d43ff5..9a774e4 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,13 @@ it :: Doc b ## Building +You'll need a supported version of GHC (check supported versions by searching for `tested-with` in +`language-rust.cabal`). Odds are the version you want to use is supported. + ### Cabal -With Cabal and GHC, run +With a recent version of Cabal, run - cabal install happy --constraint 'happy >= 1.19.8' - cabal install alex cabal configure cabal build @@ -44,10 +45,8 @@ With the [Stack][1] tool installed, run stack init stack build -The second command is responsible for pulling in all of the dependencies (including executable -tools like [Alex][2], [Happy][3], and GHC itself) and then compiling everything. If Stack complains -about the version of Happy installed, you can explicitly install a recent one with `stack install -happy-1.19.8`. +If Stack complains about the version of Happy installed, you can explicitly install a recent one +with `stack install happy-1.19.12`. ## Evolution of Rust diff --git a/bench/README.md b/bench/README.md index 32b53a8..583e23b 100644 --- a/bench/README.md +++ b/bench/README.md @@ -21,11 +21,11 @@ directory). # Tools Since some of these tests take a while, you can add a `.benchignore` file in `sample-sources` which -lists files to skip for benchmarking (one file name per line). +lists files to skip for benchmarking (one file name per line). There is also a `bench.py` utility in this directory which lets you compare benchmarks across different commits. It relies on the JSON files in `allocations` and `timings`, so you will have to -checkout and run the benchmarks on commits you want to compare against (to generate the +checkout and run the benchmarks on commits you want to compare against (to generate the corresponding JSON file). ``` diff --git a/bench/allocation-benchmarks/Main.hs b/bench/allocation-benchmarks/Main.hs index aa2e828..080b9b6 100644 --- a/bench/allocation-benchmarks/Main.hs +++ b/bench/allocation-benchmarks/Main.hs @@ -2,9 +2,9 @@ import Weigh +import Control.DeepSeq (rnf) import Control.Monad (filterM) -import Control.Exception (catch, throwIO) -import Data.Foldable (for_) +import Control.Exception (catch, throwIO, evaluate) import Data.Traversable (for) import GHC.Exts (fromString) @@ -18,7 +18,6 @@ import System.Process (proc, readCreateProcess) import System.IO.Error (isDoesNotExistError) import Data.Aeson -import qualified Data.ByteString.Lazy as BL -- TODO: only allocation and GCs seem to be really reproducible. Live and max sometimes are 0. @@ -29,7 +28,7 @@ main = do logFileName <- case status of "" -> init <$> readCreateProcess (proc "git" ["rev-parse", "HEAD"]) "" _ -> pure "WIP" - + -- Get the test cases workingDirectory <- getCurrentDirectory let sampleSources = workingDirectory "sample-sources" @@ -46,25 +45,21 @@ main = do (\e -> if isDoesNotExistError e then pure () else throwIO e) -- Run 'weigh' tests - fileStreams <- for files $ \file -> do { is <- readInputStream file; pure (takeFileName file, is) } - let weigh = do setColumns [ Case, Max, Allocated, GCs, Live ] - for_ fileStreams $ \(file,is) -> func file (parse' :: InputStream -> SourceFile Span) is - mainWith weigh - (wr, _) <- weighResults weigh - let results = object [ case maybeErr of - Nothing -> key .= object [ "allocated" .= weightAllocatedBytes weight --- , "max" .= weightMaxBytes w --- , "live" .= weightLiveBytes w --- , "GCs" .= weightGCs w - ] - Just err -> key .= String (fromString err) - | (weight, maybeErr) <- wr - , let key = fromString (weightLabel weight) - ] + weighResultsJson <- fmap object . for files $ \file -> do + is <- readInputStream file + evaluate (rnf is) + let testName = fromString (takeFileName file) + (allocatedBytes, _gcs, _liveBytes, _maxBytes) <- + weighFunc (parse' :: InputStream -> SourceFile Span) is + pure $ testName .= object [ "allocated" .= allocatedBytes +-- , "max" .= maxBytes +-- , "live" .= liveBytes +-- , "GCs" .= gcs + ] -- Save the output to JSON createDirectoryIfMissing False (workingDirectory "bench" "allocations") let logFile = workingDirectory "bench" "allocations" logFileName <.> "json" putStrLn $ "writing results to: " ++ logFile - logFile `BL.writeFile` encode results + encodeFile logFile weighResultsJson diff --git a/bench/timing-benchmarks/Main.hs b/bench/timing-benchmarks/Main.hs index d980f8f..25a2cd5 100644 --- a/bench/timing-benchmarks/Main.hs +++ b/bench/timing-benchmarks/Main.hs @@ -5,8 +5,9 @@ import Criterion.Main (defaultConfig) import Criterion.Types (anMean, reportAnalysis, timeLimit, anOutlierVar, ovEffect, OutlierEffect(Moderate)) import Statistics.Types (Estimate(..), ConfInt(..)) +import Control.DeepSeq (rnf) import Control.Monad (filterM) -import Control.Exception (catch, throwIO) +import Control.Exception (catch, evaluate, throwIO) import Data.Foldable (for_) import Data.Traversable (for) import GHC.Exts (fromString) @@ -21,7 +22,6 @@ import System.Process (proc, readCreateProcess) import System.IO.Error (isDoesNotExistError) import Data.Aeson -import qualified Data.ByteString.Lazy as BL main :: IO () main = do @@ -30,7 +30,7 @@ main = do logFileName <- case status of "" -> init <$> readCreateProcess (proc "git" ["rev-parse", "HEAD"]) "" _ -> pure "WIP" - + -- Get the test cases workingDirectory <- getCurrentDirectory let sampleSources = workingDirectory "sample-sources" @@ -51,6 +51,7 @@ main = do let name = takeFileName f putStrLn name is <- readInputStream f + evaluate (rnf is) bnch <- benchmarkWith' defaultConfig{ timeLimit = 20 } (nf (parse' :: InputStream -> SourceFile Span) is) pure (name, bnch) let results = object [ fromString name .= object [ "mean" .= m @@ -68,5 +69,5 @@ main = do createDirectoryIfMissing False (workingDirectory "bench" "timings") let logFile = workingDirectory "bench" "timings" logFileName <.> "json" putStrLn $ "writing results to: " ++ logFile - logFile `BL.writeFile` encode results + encodeFile logFile results diff --git a/get-rust-sources.sh b/get-rust-sources.sh index 3178f3a..6a745f6 100755 --- a/get-rust-sources.sh +++ b/get-rust-sources.sh @@ -31,7 +31,7 @@ curl https://api.github.com/orgs/rust-lang-nursery/repos > rust-lang-nursery.jso # Make one big JSON array of repos and extract the name and clone url (jq -rs '.[0] + .[1] | .[] | (.name, .clone_url)' rust-lang.json rust-lang-nursery.json \ ) | while read -r REPO_NAME; read -r REPO_CLONE; do - + # Skip 'multirust-rs-binaries' and 'rustc-timing-archive' in particular if [ $REPO_NAME = "multirust-rs-binaries" ] || [ $REPO_NAME = "rustc-timing-archive" ] then @@ -48,7 +48,7 @@ curl https://api.github.com/orgs/rust-lang-nursery/repos > rust-lang-nursery.jso # compile. echo "Finding rust files in $REPO_NAME" find $REPO_NAME -type f -name '*.rs' | while read -r FILE; do - + # Escaped file name DEST_FILE="../$DEST/${FILE//\//|}" diff --git a/language-rust.cabal b/language-rust.cabal index f9c4331..3e63511 100644 --- a/language-rust.cabal +++ b/language-rust.cabal @@ -1,22 +1,23 @@ name: language-rust -version: 0.2.0.27 +version: 0.3.0.39 synopsis: Parsing and pretty printing of Rust code description: Language Rust is a library for the analysis of Rust code. It includes a - complete, well tested parser and pretty printer. + complete, well tested parser and pretty printer. homepage: https://github.com/harpocrates/language-rust license: BSD3 license-file: LICENSE author: Alec Theriault maintainer: alec.theriault@gmail.com -copyright: (c) 2017-2018 Alec Theriault +copyright: (c) 2017-2019 Alec Theriault stability: provisional bug-reports: https://github.com/harpocrates/language-rust/issues category: Language build-type: Simple extra-source-files: ChangeLog.md README.md cabal-version: >=1.10 +tested-with: GHC==8.0.2, GHC==8.2.2, GHC==8.4.4, GHC==8.6.5, GHC==8.8.1 source-repository head type: git @@ -34,12 +35,13 @@ library hs-source-dirs: src ghc-options: -Wall - - if impl(ghc >= 8) - ghc-options: + -Wcompat + -Widentities -Wincomplete-patterns + -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-signatures + -Wredundant-constraints build-tools: alex >=3.1, happy >=1.19.8 default-language: Haskell2010 @@ -130,6 +132,7 @@ test-suite rustc-tests main-is: Main.hs other-modules: Diff DiffUtils + Options other-extensions: InstanceSigs , OverloadedStrings @@ -142,7 +145,7 @@ test-suite rustc-tests build-depends: process >=1.3 , bytestring >=0.10 - , aeson >=0.11.0.0 + , aeson >=1.2.4.0 , directory >=1.2.5.0 , filepath >=1.4.0.0 , test-framework >=0.8.0 @@ -166,7 +169,7 @@ benchmark timing-benchmarks default-language: Haskell2010 build-depends: process >=1.3 , bytestring >=0.10 - , aeson >=0.11.0.0 + , aeson >=1.2.4.0 , directory >=1.2.5.0 , filepath >=1.4.0.0 , criterion >=1.1.1.0 @@ -174,10 +177,11 @@ benchmark timing-benchmarks , language-rust , base + , deepseq benchmark allocation-benchmarks hs-source-dirs: bench/allocation-benchmarks - ghc-options: -Wall + ghc-options: -Wall -with-rtsopts=-T main-is: Main.hs @@ -186,12 +190,12 @@ benchmark allocation-benchmarks type: exitcode-stdio-1.0 default-language: Haskell2010 build-depends: process >=1.3 - , bytestring >=0.10 - , aeson >=0.11.0.0 + , aeson >=1.2.4.0 , directory >=1.2.5.0 , filepath >=1.4.0.0 - , weigh >=0.0.6 + , weigh >=0.0.8 && <=0.0.14 , language-rust , base + , deepseq diff --git a/sample-sources/attributes.rs b/sample-sources/attributes.rs index 18d7698..14abdd5 100644 --- a/sample-sources/attributes.rs +++ b/sample-sources/attributes.rs @@ -58,7 +58,7 @@ fn expressions() { #![while_inner] 1; } - + #[whilelet_outer] while let x = true { #![whilelet_inner] @@ -91,8 +91,8 @@ fn expressions() { #[blockexpr_outer] unsafe { #![blockexpr_inner] 1; 2 } - #[catch_outer] - do catch { #![catch_inner] 1 }; + #[try_outer] + try { #![try_inner] 1 }; // #[assign_outer] // x = 1; @@ -159,7 +159,7 @@ impl Impls { #![method_inner] 1f64 } - + #[type_outer] type N = i32; @@ -170,43 +170,44 @@ impl Impls { fn items() { #[use_outer] use foo::bar as FooBar; - + #[static_outer] static FOO: i32 = 42; - + #[const_outer] const FOO: i32 = 42; - + #[fn_outer] fn foo(bar: usize) -> usize { #![fn_inner] 1 } - + #[mod_outer] mod foo { #![mod_inner] } - + #[type_outer] type Foo = Bar; - + #[enum_outer] enum Foo { #[variant_outer] C(A), D(B) } - + #[struct_outer] struct Foo { #[field_outer] x: A } - + #[union_outer] union Foo { x: A, y: B } #[macro_outer] foo!{ .. } - + #[macrodef_outer] macro_rules! foo { () => ( .. ) } + let x: i32 = #[expression_outer] 34; } fn foo< #[lifetimedef_outer] 'a: 'b, #[typaram_outer] T ->() { } +>() { } diff --git a/sample-sources/difficult.rs b/sample-sources/difficult.rs new file mode 100644 index 0000000..9ff9d1a --- /dev/null +++ b/sample-sources/difficult.rs @@ -0,0 +1,7 @@ +fn difficult() { + // expression statement starting with `union` vs. `union` + union + 1; + union Foo { x: (i32,i32), y: u64 }; + + loop { if break { } } +} diff --git a/sample-sources/expressions.rs b/sample-sources/expressions.rs index 58c0381..3810713 100644 --- a/sample-sources/expressions.rs +++ b/sample-sources/expressions.rs @@ -43,12 +43,17 @@ fn main() { let x = [1; 5]; let x = 1 * (2 + 3); let x = foo()?; - let x = do catch { 1 }; + let x = try { 1 }; return 0; return; yield 0; yield; let r#return = 0; + let r#async = 0; + let x = async { 1 }; + let x = y.await; + // foo::(i32) -> f64(); TODO + // foo::(); TODO match true { true => move | | { 1 }, diff --git a/sample-sources/items.rs b/sample-sources/items.rs index bbf9d1b..67ad16d 100644 --- a/sample-sources/items.rs +++ b/sample-sources/items.rs @@ -23,14 +23,15 @@ mod bar { } type Foo = Bar; - + enum Foo { C(A), D(B) } - + struct Foo { x: A } union Foo { x: A, y: B } - + pub(super) struct Point { x: i32 } + auto trait IsCool { } trait Foo { } trait Foo { const ID1: i32; @@ -53,14 +54,15 @@ mod bar { } trait Foo = Bar + Baz; + trait Foo = ?Sized; trait Foo<'a,N> = Bar<'a,N> + Baz + 'a; fn foo(x: &T) { } struct Foo { field: Box } trait Bar { type Baz: ?Sized; } - struct Bleh where T: Copy, U: Sized; - + struct Bleh where T: Copy, U: Sized; + impl Foo { const ID: i32 = 1; fn area(&self) -> f64 { 1f64 } @@ -69,10 +71,13 @@ mod bar { } impl Trait for Foo { } impl !Trait for Foo { } - + macro_rules! foo { } foo!(); + pub macro PartialEq($item:item) { /* compiler built-in */ } + pub macro PartialEq { 1 } + enum Foo { Baz { foo: i32, diff --git a/sample-sources/patterns.rs b/sample-sources/patterns.rs index 29726dd..e31360c 100644 --- a/sample-sources/patterns.rs +++ b/sample-sources/patterns.rs @@ -17,7 +17,7 @@ fn main() { &mut (a,b) => 0, 0 => 0, 0...1 => 0, - [a, b, i.., y, z] => 0, + [a, b, i @ .., y, z] => 0, [a, b, .., y, z] => 0, [a, b, c] => 0, LinkedList!(1,2,3) => 0, diff --git a/sample-sources/precedences.rs b/sample-sources/precedences.rs index 36ad1c6..ba9917f 100644 --- a/sample-sources/precedences.rs +++ b/sample-sources/precedences.rs @@ -1,7 +1,7 @@ // See fn main() { - a /= - b ? ^= * - c >= - * d [0] ? == box & ! e ? [0] .0 ? [0] .0 ?; + a /= - b ? ^= * - c >= - * d [0] ? + box & ! e ? [0] .0 ? [0] .0 ?; - a == box b [0] [0] [0] .0 || c [0] ^= d % e = f != g; & a *= ! b ^= c * d | e [0]; a ^ b < * c ? || box d ? %= e [0] = - f < box g % & h &= i ? % & & & j ?; @@ -9,7 +9,7 @@ fn main() { a >> & b && - box c >= d .. e .0 [0] + ! f * g >= h && & - i [0] * j; * a > b *= c * d && e ^ - & f ? *= g %= h .0 [0] ? & i -= j ?; * a >> b %= c .0 != * - d [0] || e <= f << g .0 | ! h += - & i >= j .0; - a && ! * box b [0] >> - c || * d ^ * e >= f >= g /= ! h = i [0] ... j; + a && ! * box b [0] >> - c || * d ^ * e + f >= g /= ! h = i [0] ..= j; .. a + box b ? [0] * c ? .0 ^ d + & f <= g [0] * h && i + j [0] ?; a * b &= c & * d ? |= & ! e [0] != & f .0 = g >> ! ! * - h ? ^ i ? %= - j; & a != b [0] % c - & & ! - box - d & e [0] += g ? << h /= i <<= .. .. j; @@ -17,13 +17,13 @@ fn main() { a & b - c *= &&*d? << *e.0?.0 ^= !f?[0].0 >> -g - h .. i??[0] | j; -a[0] - b[0][0]??.0 != c -= d || e[0][0] *= &f = !!g[0] / h ^ i | box!j[0]; a != -b.0 - box!c.0?.0 *= -e? <= *-f.0 ^= g >> box box h + i + j; - !&&-box a??.0 >> b |= c[0]? ^ d * e | &*f[0] <= box -g? ... &h * &i - j[0][0]; + !&&-box a??.0 >> b |= c[0]? ^ d * e | &*f[0] <= box -g? ..= &h * &i - j[0][0]; a & b &= c[0] <= d + -!-box*e[0]?[0] % f.0? + -g >>= h[0] /= i = j; - a[0][0] >>= *b.0 .0? / c ^ d >>= !e >= box f ... g >= h + i? || j; + a[0][0] >>= *b.0 .0? / c ^ d >>= !e >= box f ..= g >= h + i? || j; !&a? |= -b >= c / *-d? *= e % f += !box g.0? != &-*h? + i.0 / j; a? - b? | c * *-box box box*box d? .0 .0 %= !!!e? &= -box!f.0 += g - h /= i && j; - *box box!a -= box-b.0 % c &= d % e? ^= !&f[0]? != g > h & i /= j; - box---!a.0 ^= b = -&box c? > d << e.0 >= f[0] + g -= h >>= i * j; + *box box!a -= box-b.0 % c &= d % e? ^= !&f[0]? != h & i /= j; + box---!a.0 ^= b = -&box c? > d << e.0 + f[0] + g -= h >>= i * j; a .0 .0 >>= -b >= -box*c || d? &= box&-e | f << g * h[0][0] |= i * j; box-a / b != c -= d == &e.0 >>= f - *g[0] %= h & i << &-j??; !&-a.0 == b *= c.0 <<= --d && e? ^= !f <<= g[0] > h += -i >>= j; diff --git a/sample-sources/statement-expressions.rs b/sample-sources/statement-expressions.rs index efe0b0f..0896da2 100644 --- a/sample-sources/statement-expressions.rs +++ b/sample-sources/statement-expressions.rs @@ -2,12 +2,12 @@ fn main() { { 1 }[1]; // !!! Parses as { 1 }; [1]; { 1 }(0); // !!! Parses as { 1 }; (0); - + { 1 }.foo; // Parses as a field access { 1 }.foo(0); // Parses as a method call { 1 }.0; // Parses as a tup field access { 1 }?; // Parses as a try - + { 1 }? + 1; // SHOULD WORK { 1 }[0] + 1; // SHOULD WORK @@ -18,7 +18,7 @@ fn main() { // { 1 } as i32 + 1; // SHOULD NOT WORK // { 1 } + 1; // SHOULD NOT WORK - + { 1 }[1]; { 1 }(); { 1 }.bar; diff --git a/sample-sources/statements.rs b/sample-sources/statements.rs index c5135fa..7c6c4d8 100644 --- a/sample-sources/statements.rs +++ b/sample-sources/statements.rs @@ -6,17 +6,22 @@ fn main() { // Item fn foo() { return 1 } - // Empty - ;;; - // NoSemi if true { foo() } - let b = { let y = 3; y }; + let b = { let y = 3; y.await }; + + // Empty + ; // Semi 2 + { 1 }; + ;;; + + // Blocks + unsafe { 1 }; + async { 1 }; // Mac println!("hi") diff --git a/sample-sources/types.rs b/sample-sources/types.rs index 28dbc79..89d296b 100644 --- a/sample-sources/types.rs +++ b/sample-sources/types.rs @@ -14,7 +14,7 @@ fn main() { let x: (i32,); let x: (i32,!); let x: i32; - let x: T; + let x: T; let x: as SomeTrait>::SomeType; let x: Bound1 + Bound2 + 'static; let x: impl Bound1 + Bound2 + 'static; @@ -28,11 +28,11 @@ fn main() { fn foo() -> impl Bound1 + Bound2 + Bound3 { } -pub fn walk(x: i32, it: &mut F) -> bool +pub fn walk(x: i32, it: &mut F) -> bool where F: FnMut(&Pat) -> bool, 'a: 'b + 'c, F = i32, { - foo::<'a,A,B,C=i32> + foo::<'a,A,B,{N},C=i32,D: Send + ?Sync> } diff --git a/sample-sources/visibility.rs b/sample-sources/visibility.rs new file mode 100644 index 0000000..23261e9 --- /dev/null +++ b/sample-sources/visibility.rs @@ -0,0 +1,15 @@ +fn foo() { } +pub fn foo() { } +pub(crate) fn foo() { } +pub(in bar::baz) fn foo() { } +pub(super) fn foo() { } +pub(self) fn foo() { } + +fn as_stmt() { + fn foo() { } + pub fn foo() { } + pub(crate) fn foo() { } + pub(in bar::baz) fn foo() { } + pub(super) fn foo() { } + pub(self) fn foo() { } +} diff --git a/src/Language/Rust/Data/Ident.hs b/src/Language/Rust/Data/Ident.hs index 421552f..4ec26ca 100644 --- a/src/Language/Rust/Data/Ident.hs +++ b/src/Language/Rust/Data/Ident.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Data.Ident Description : Identifiers -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -68,7 +68,7 @@ mkIdent s = Ident s False (hashString s) -- | Hash a string into an 'Int' hashString :: String -> Int hashString = foldl' f golden - where f m c = fromIntegral (ord c) * magic + m + where f m c = ord c * magic + m magic = 0xdeadbeef golden = 1013904242 diff --git a/src/Language/Rust/Data/InputStream.hs b/src/Language/Rust/Data/InputStream.hs index e286e48..c1f58fb 100644 --- a/src/Language/Rust/Data/InputStream.hs +++ b/src/Language/Rust/Data/InputStream.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Data.InputStream Description : Interface to the underlying input of parsing -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -15,18 +15,19 @@ means incurring a dependency on the [utf8-string](https://hackage.haskell.org/pa package. -} {-# LANGUAGE CPP #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Language.Rust.Data.InputStream ( -- * InputStream type InputStream, countLines, inputStreamEmpty, - + -- * Introduction forms readInputStream, hReadInputStream, inputStreamFromString, - + -- * Elimination forms inputStreamToString, takeByte, @@ -46,6 +47,8 @@ import qualified Data.ByteString.UTF8 as BE import qualified Data.Char as Char #endif +import Control.DeepSeq ( NFData ) + -- | Read an encoded file into an 'InputStream' readInputStream :: FilePath -> IO InputStream {-# INLINE readInputStream #-} @@ -134,7 +137,7 @@ countLines :: InputStream -> Int #ifdef USE_BYTESTRING -- | Opaque input type. -newtype InputStream = IS BS.ByteString deriving (Eq, Ord) +newtype InputStream = IS BS.ByteString deriving (Eq, Ord, NFData) takeByte bs = (BS.head (coerce bs), coerce (BS.tail (coerce bs))) takeChar bs = maybe (error "takeChar: no char left") coerce (BE.uncons (coerce bs)) inputStreamEmpty = BS.null . coerce @@ -142,7 +145,7 @@ peekChars n = BE.toString . BE.take n . coerce readInputStream f = coerce <$> BS.readFile f hReadInputStream h = coerce <$> BS.hGetContents h inputStreamToString = BE.toString . coerce -inputStreamFromString = IS . BE.fromString +inputStreamFromString = IS . BE.fromString countLines = length . BE.lines . coerce instance Show InputStream where @@ -151,7 +154,7 @@ instance Show InputStream where #else -- | Opaque input type. -newtype InputStream = IS String deriving (Eq, Ord) +newtype InputStream = IS String deriving (Eq, Ord, NFData) takeByte (IS ~(c:str)) | Char.isLatin1 c = let b = fromIntegral (Char.ord c) in b `seq` (b, IS str) | otherwise = error "takeByte: not a latin-1 character" diff --git a/src/Language/Rust/Data/Position.hs b/src/Language/Rust/Data/Position.hs index ad8205b..f027d73 100644 --- a/src/Language/Rust/Data/Position.hs +++ b/src/Language/Rust/Data/Position.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Data.Position Description : Positions and spans in files -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -9,7 +9,6 @@ Portability : GHC Everything to do with describing a position or a contiguous region in a file. -} -{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveAnyClass #-} @@ -59,7 +58,7 @@ data Position = Position { -- | Field names are not shown instance Show Position where showsPrec _ NoPosition = showString "NoPosition" - showsPrec p (Position a r c) = showParen (p >= 11) + showsPrec p (Position a r c) = showParen (p >= 11) ( showString "Position" . showString " " . showsPrec 11 a . showString " " . showsPrec 11 r @@ -107,29 +106,29 @@ initPos = Position 0 1 0 {-# INLINE incPos #-} incPos :: Position -> Int -> Position incPos NoPosition _ = NoPosition -incPos p@Position{ absoluteOffset = a, col = c } offset = p { absoluteOffset = a + offset, col = c + offset } +incPos (Position a r c) offset = Position (a + offset) r (c + offset) -- | Advance to the next line. {-# INLINE retPos #-} retPos :: Position -> Position retPos NoPosition = NoPosition -retPos (Position a r _) = Position { absoluteOffset = a + 1, row = r + 1, col = 1 } +retPos (Position a r _) = Position (a + 1) (r + 1) 1 -- | Advance only the absolute offset, not the row and column information. Only use this if you -- know what you are doing! {-# INLINE incOffset #-} incOffset :: Position -> Int -> Position incOffset NoPosition _ = NoPosition -incOffset p@Position{ absoluteOffset = a } offset = p { absoluteOffset = a + offset } +incOffset (Position a r c) offset = Position (a + offset) r c -- | Spans represent a contiguous region of code, delimited by two 'Position's. The endpoints are -- inclusive. Analogous to the information encoded in a selection. data Span = Span { lo, hi :: !Position } deriving (Eq, Ord, Data, Typeable, Generic, NFData) --- | Field names are not shown +-- | Field names are not shown instance Show Span where - showsPrec p (Span l h) = showParen (p >= 11) + showsPrec p (Span l h) = showParen (p >= 11) ( showString "Span" . showString " " . showsPrec 11 l . showString " " . showsPrec 11 h ) @@ -176,7 +175,7 @@ instance Functor Spanned where instance Applicative Spanned where {-# INLINE pure #-} pure x = Spanned x mempty - + {-# INLINE (<*>) #-} Spanned f s1 <*> Spanned x s2 = Spanned (f x) (s1 Sem.<> s2) diff --git a/src/Language/Rust/Parser.hs b/src/Language/Rust/Parser.hs index 905e73d..1747c56 100644 --- a/src/Language/Rust/Parser.hs +++ b/src/Language/Rust/Parser.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Parser Description : Parsing and lexing -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -136,8 +136,9 @@ class Parse a where instance Parse (Lit Span) where parser = parseLit instance Parse (Attribute Span) where parser = parseAttr -instance Parse (Ty Span) where parser = parseTy +instance Parse (Ty Span) where parser = parseTy instance Parse (Pat Span) where parser = parsePat +instance Parse (Path Span) where parser = parsePath instance Parse (Expr Span) where parser = parseExpr instance Parse (Stmt Span) where parser = parseStmt instance Parse (Item Span) where parser = parseItem @@ -145,9 +146,8 @@ instance Parse (SourceFile Span) where parser = parseSourceFile instance Parse TokenTree where parser = parseTt instance Parse TokenStream where parser = parseTokenStream instance Parse (Block Span) where parser = parseBlock -instance Parse (ImplItem Span) where parser = parseImplItem +instance Parse (ImplItem Span) where parser = parseImplItem instance Parse (TraitItem Span) where parser = parseTraitItem -instance Parse (TyParam Span) where parser = parseTyParam -instance Parse (LifetimeDef Span) where parser = parseLifetimeDef +instance Parse (GenericParam Span)where parser = parseGenericParam instance Parse (Generics Span) where parser = parseGenerics instance Parse (WhereClause Span) where parser = parseWhereClause diff --git a/src/Language/Rust/Parser/Internal.y b/src/Language/Rust/Parser/Internal.y index 4753c6c..af52d35 100644 --- a/src/Language/Rust/Parser/Internal.y +++ b/src/Language/Rust/Parser/Internal.y @@ -2,14 +2,14 @@ {-| Module : Language.Rust.Parser.Internal Description : Rust parser -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 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: +The parsers in this file are all re-exported to 'Language.Rust.Parser' via the +'Language.Rust.Parser.Parse' class. The parsers are based off of: * primarily the reference @rustc@ [implementation][0] * some documentation on [rust-lang][2] @@ -32,22 +32,24 @@ module Language.Rust.Parser.Internal ( parseAttr, parseBlock, parseExpr, + parseGenericParam, parseGenerics, parseImplItem, parseItem, - parseLifetimeDef, parseLit, parsePat, + parsePath, parseSourceFile, parseStmt, parseTokenStream, parseTraitItem, parseTt, parseTy, - parseTyParam, parseWhereClause, ) where +import Prelude hiding ( fail ) + import Language.Rust.Syntax import Language.Rust.Data.Ident ( Ident(..), mkIdent ) @@ -58,9 +60,11 @@ import Language.Rust.Parser.ParseMonad ( pushToken, getPosition, P, parseError ) import Language.Rust.Parser.Literals ( translateLit ) import Language.Rust.Parser.Reversed +import Data.Either ( partitionEithers ) import Data.Foldable ( toList ) import Data.List ( (\\), isSubsequenceOf, sort ) import Data.Semigroup ( (<>) ) +import Control.Monad.Fail ( fail ) import Text.Read ( readMaybe ) @@ -72,7 +76,8 @@ import qualified Data.List.NonEmpty as N %name parseLit lit %name parseAttr export_attribute %name parseTy ty -%name parsePat pat +%name parsePat or_pat +%name parsePath ty_path %name parseStmt stmt %name parseExpr expr %name parseItem mod_item @@ -82,8 +87,7 @@ import qualified Data.List.NonEmpty as N %name parseTraitItem trait_item %name parseTt token_tree %name parseTokenStream token_stream -%name parseTyParam ty_param -%name parseLifetimeDef lifetime_def +%name parseGenericParam generic_param %name parseWhereClause where_clause %name parseGenerics generics @@ -171,11 +175,14 @@ import qualified Data.List.NonEmpty as N -- Strict keywords used in the language as { Spanned (IdentTok "as") _ } + async { Spanned (IdentTok "async") _ } + await { Spanned (IdentTok "await") _ } box { Spanned (IdentTok "box") _ } break { Spanned (IdentTok "break") _ } const { Spanned (IdentTok "const") _ } continue { Spanned (IdentTok "continue") _ } crate { Spanned (IdentTok "crate") _ } + dyn { Spanned (IdentTok "dyn") _ } else { Spanned (IdentTok "else") _ } enum { Spanned (IdentTok "enum") _ } extern { Spanned (IdentTok "extern") _ } @@ -187,6 +194,7 @@ import qualified Data.List.NonEmpty as N in { Spanned (IdentTok "in") _ } let { Spanned (IdentTok "let") _ } loop { Spanned (IdentTok "loop") _ } + macro { Spanned (IdentTok "macro") _ } match { Spanned (IdentTok "match") _ } mod { Spanned (IdentTok "mod") _ } move { Spanned (IdentTok "move") _ } @@ -201,25 +209,22 @@ import qualified Data.List.NonEmpty as N super { Spanned (IdentTok "super") _ } trait { Spanned (IdentTok "trait") _ } true { Spanned (IdentTok "true") _ } + try { Spanned (IdentTok "try") _ } type { Spanned (IdentTok "type") _ } unsafe { Spanned (IdentTok "unsafe") _ } use { Spanned (IdentTok "use") _ } where { Spanned (IdentTok "where") _ } while { Spanned (IdentTok "while") _ } - do { Spanned (IdentTok "do") _ } + yield { Spanned (IdentTok "yield") _ } -- Keywords reserved for future use abstract { Spanned (IdentTok "abstract") _ } - alignof { Spanned (IdentTok "alignof") _ } become { Spanned (IdentTok "become") _ } + do { Spanned (IdentTok "do") _ } 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") _ } @@ -227,10 +232,8 @@ import qualified Data.List.NonEmpty as N -- 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") _ } + macro_rules { Spanned (IdentTok "macro_rules") _ } -- Comments outerDoc { Spanned (Doc _ Outer _) _ } @@ -277,14 +280,14 @@ import qualified Data.List.NonEmpty as N %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 +%nonassoc IDENT ntIdent default union self Self super auto crate macro_rules -- These are all very low precedence unary operators -%nonassoc box return yield break continue for IMPLTRAIT LAMBDA +%nonassoc async box return yield break continue for IMPLTRAIT LAMBDA --- 'static' needs to have higher precedenc than 'LAMBDA' so that statements starting in static get +-- 'static' needs to have higher precedence than 'LAMBDA' so that statements starting in static get -- considered as static items, and not a static lambda -%nonassoc static +%nonassoc static move -- These are the usual arithmetic precedences. 'UNARY' is introduced here for '*', '!', '-', '&' %right '=' '>>=' '<<=' '-=' '+=' '*=' '/=' '^=' '|=' '&=' '%=' @@ -296,7 +299,7 @@ import qualified Data.List.NonEmpty as N %nonassoc '..' '...' '..=' %left '||' %left '&&' -%left '==' '!=' '<' '>' '<=' '>=' +%nonassoc '==' '!=' '<' '>' '<=' '>=' %left '|' %left '^' %left '&' @@ -325,7 +328,7 @@ import qualified Data.List.NonEmpty as N %% -- Unwraps the IdentTok into just an Ident --- For questionable reasons of backwards compatibility, 'union', 'default', and 'catch' can be used +-- For questionable reasons of backwards compatibility, 'union', and 'default' 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 @@ -333,11 +336,14 @@ 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 } + | macro_rules { toIdent $1 } | IDENT { toIdent $1 } +ident_or_self :: { Spanned Ident } + : ident { $1 } + | self { 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 @@ -355,7 +361,7 @@ gt :: { () } -- 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) -> + : {- 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'') @@ -433,19 +439,19 @@ inner_attrs :: { Reversed NonEmpty (Attribute Span) } lit :: { Lit Span } : ntLit { $1 } - | byte { lit $1 } - | char { lit $1 } - | int { lit $1 } - | float { lit $1 } - | true { lit $1 } - | false { lit $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 } + : str {% lit $1 } + | rawStr {% lit $1 } + | byteStr {% lit $1 } + | rawByteStr {% lit $1 } ----------- @@ -453,131 +459,150 @@ string :: { Lit Span } ----------- -- parse_qualified_path(PathStyle::Type) --- qual_path :: Spanned (NonEmpty (Ident, PathParameters Span)) -> P (Spanned (QSelf Span, Path Span)) +-- qual_path :: Spanned (NonEmpty (Ident, GenericArgs 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 { + : '<' 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 # $>) + let idx = length segsTy + if g then 1 else 0 in + Spanned (QSelf (unspan $1) idx, 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 { + : 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 # $>) + let idx = length segsTy + if g then 1 else 0 in + Spanned (QSelf $1 idx, 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) +-- '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) } + : '<<' qual_path_suf(ty_path_segments) + { + 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) } - +generic_args :: { GenericArgs Span } + : '<' sep_byT(generic_arg_elem,',') gt '>' + { let (a, c) = partitionEithers $2 in AngleBracketed a c ($1 # $>) } + | lt_ty_qual_path ',' sep_by1T(generic_arg_elem,',') gt '>' + { let (a, c) = partitionEithers (toList $3) + in AngleBracketed (TypeArg (unspan $1) : a) c ($1 # $>) } + | lt_ty_qual_path gt '>' + { AngleBracketed [TypeArg (unspan $1)] [] ($1 # $>) } + +generic_arg :: { GenericArg Span } + : lifetime { LifetimeArg $1 } + | ty { TypeArg $1 } + | unannotated_block { ConstArg $1 } + | '-' lit_expr { ConstArg (Unary [] Neg $2 ($1 # $2)) } + | lit_expr { ConstArg $1 } + +generic_constraint :: { AssocTyConstraint Span } + : ident '=' ty { EqualityConstraint (unspan $1) $3 ($1 # $3) } + | ident ':' sep_by1T(ty_param_bound_mod,'+') { BoundConstraint (unspan $1) (toNonEmpty $3) ($1 # $>) } + +generic_arg_elem :: { Either (GenericArg Span) (AssocTyConstraint Span) } + : generic_arg { Left $1 } + | generic_constraint { Right $1 } -- 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) } + : ntPath { $1 } + | ty_path_segments %prec SEG { Path False (toList $1) (spanOf $1) } + | '::' ty_path_segments %prec SEG { Path True (toList $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 # $>) } + : qual_path(ty_path_segments) { $1 } + +-- parse_ty_path_segments() +ty_path_segments :: { Reversed NonEmpty (PathSegment Span) } + : path_segment_ident ty_generic_args + { [PathSegment (unspan $1) $2 ($1 # $2)] } + | ty_path_segments '::' path_segment_ident ty_generic_args + { $1 <> [PathSegment (unspan $3) $4 ($3 # $4)] } + | ty_path_segments '::' ty_generic_args1 + {% + case (unsnoc $1) of + (rst, PathSegment i Nothing x) -> + let seg = PathSegment i (Just $3) (x # $3) + in pure $ snoc rst seg + _ -> fail "invalid path segment in type path" + } -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 } +ty_generic_args :: { Maybe (GenericArgs Span) } + : ty_generic_args1 { Just $1 } + | {- empty -} %prec IDENT { Nothing } +ty_generic_args1 :: { GenericArgs Span } + : generic_args { $1 } + | '(' sep_byT(ty,',') ')' { Parenthesized $2 Nothing ($1 # $>) } + | '(' sep_byT(ty,',') ')' '->' ty_no_plus { Parenthesized $2 (Just $>) ($1 # $>) } -- 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) } + : ntPath { $1 } + | expr_path_segments { Path False (toList $1) (spanOf $1) } + | '::' expr_path_segments { Path True (toList $2) ($1 # $2) } expr_qual_path :: { Spanned (QSelf Span, Path Span) } - : qual_path(path_segments_with_colons) { $1 } + : qual_path(expr_path_segments) { $1 } --- parse_path_segments_with_colons() -path_segments_with_colons :: { Reversed NonEmpty (PathSegment Span) } - : self_or_ident +-- parse_expr_path_segments() +expr_path_segments :: { Reversed NonEmpty (PathSegment Span) } + : gen_expr_path_segments(path_segment_ident) { $1 } + +gen_expr_path_segments(first_seg) :: { Reversed NonEmpty (PathSegment Span) } + : first_seg { [PathSegment (unspan $1) Nothing (spanOf $1)] } - | path_segments_with_colons '::' self_or_ident + | gen_expr_path_segments(first_seg) '::' path_segment_ident { $1 <> [PathSegment (unspan $3) Nothing (spanOf $3)] } - | path_segments_with_colons '::' generic_values + | gen_expr_path_segments(first_seg) '::' generic_args {% - 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 + case (unsnoc $1) of + (rst, PathSegment i Nothing x) -> + let seg = PathSegment i (Just $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 { + : ntPath { $1 } + | path_segment_ident + { Path False [PathSegment (unspan $1) Nothing (spanOf $1)] (spanOf $1) } + | '::' path_segment_ident + { Path True [PathSegment (unspan $2) Nothing (spanOf $2)] ($1 # $>) } + | mod_path '::' path_segment_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) } +-- parse_path_segment_ident +path_segment_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) } ----------- @@ -595,8 +620,8 @@ trait_ref :: { TraitRef Span } -- 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) } + : ty_no_plus { $1 } + | sum_ty { $1 } -- parse_ty_no_plus() ty_no_plus :: { Ty Span } @@ -608,7 +633,21 @@ ty_no_plus :: { Ty Span } 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) } + | sum_ty { $1 } + +-- The types that contain top-level sums +sum_ty :: { Ty Span } + : poly_trait_ref_mod_bound '+' { TraitObject [$1] ($1 # $2) } + | poly_trait_ref_mod_bound '+' sep_by1T(ty_param_bound_mod,'+') { TraitObject ($1 <| toNonEmpty $3) ($1 # $3) } + | impl ty_param_bound_mod '+' %prec IMPLTRAIT { ImplTrait [$2] ($1 # $>) } + | impl ty_param_bound_mod '+' sep_by1T(ty_param_bound_mod,'+') %prec IMPLTRAIT { ImplTrait ($2 <| toNonEmpty $4) ($1 # $>) } + | dyn ty_param_bound_mod '+' %prec IMPLTRAIT { TraitObject [$2] ($1 # $>) } + | dyn ty_param_bound_mod '+' sep_by1T(ty_param_bound_mod,'+') %prec IMPLTRAIT { TraitObject ($2 <| toNonEmpty $4) ($1 # $>) } + | bare_fn_ty(ret_ty_plus) { $1 } + | for_lts bare_fn_ty(ret_ty_plus) { + let BareFn safety abi _ retTy s = $2 in + BareFn safety abi (unspan $1) retTy ($1 # s) + } -- All (non-sum) types not starting with a 'for' no_for_ty :: { Ty Span } @@ -637,28 +676,32 @@ no_for_ty_prim :: { Ty Span } | '&&' 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 # $>) } + | bare_fn_ty(ret_ty_no_plus) { $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) } + | '?' trait_ref { TraitObject [TraitBound (PolyTraitRef [] $2 (spanOf $2)) Maybe ($1 # $2)] ($1 # $2) } + | '?' for_lts trait_ref { TraitObject [TraitBound (PolyTraitRef (unspan $2) $3 ($2 # $3)) Maybe ($1 # $3)] ($1 # $3) } + | impl ty_param_bound_mod %prec IMPLTRAIT { ImplTrait [$2] ($1 # $>) } + | dyn ty_param_bound_mod %prec IMPLTRAIT { TraitObject [$2] ($1 # $>) } -- 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 bare_fn_ty(ret_ty_no_plus) { + let BareFn safety abi _ retTy s = $2 in + BareFn safety abi (unspan $1) retTy ($1 # s) + } | for_lts trait_ref { let poly = PolyTraitRef (unspan $1) $2 ($1 # $2) in - TraitObject [TraitTyParamBound poly None ($1 # $2)] ($1 # $2) + TraitObject [TraitBound poly None ($1 # $2)] ($1 # $2) } +-- Bare function types +bare_fn_ty(ret) :: { Ty Span } + : unsafe extern abi fn fn_decl(arg_general, ret) { BareFn Unsafe $3 [] $> ($1 # $>) } + | unsafe fn fn_decl(arg_general, ret) { BareFn Unsafe Rust [] $> ($1 # $>) } + | extern abi fn fn_decl(arg_general, ret) { BareFn Normal $2 [] $> ($1 # $>) } + | fn fn_decl(arg_general, ret) { BareFn Normal Rust [] $> ($1 # $>) } + -- An optional lifetime followed by an optional mutability lifetime_mut :: { (Maybe (Lifetime Span), Mutability) } : lifetime mut { (Just $1, Mutable) } @@ -667,69 +710,74 @@ lifetime_mut :: { (Maybe (Lifetime Span), Mutability) } | {- 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) } +fn_decl(arg, ret) :: { FnDecl Span } + : '(' sep_by1(arg,',') ',' '...' ')' ret { FnDecl (toList $2) $> True ($1 # $5 # $6) } + | '(' sep_byT(arg,',') ')' ret { FnDecl $2 $> False ($1 # $3 # $4) } -- 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 } +fn_decl_with_self :: { FnDecl Span } + : '(' arg_self ',' sep_by1T(arg_named,',') ')' ret_ty { FnDecl ($2 : toList $4) $> False ($1 # $5 # $6) } + | '(' arg_self ',' ')' ret_ty { FnDecl [$2] $> False ($1 # $3 # $4) } + | '(' arg_self ')' ret_ty { FnDecl [$2] $> False ($1 # $3 # $4) } + | fn_decl(arg_named, ret_ty) { $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) } +ty_param_bound :: { GenericBound Span } + : lifetime { OutlivesBound $1 (spanOf $1) } + | poly_trait_ref { TraitBound $1 None (spanOf $1) } + | '(' poly_trait_ref ')' { TraitBound $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) } +poly_trait_ref_mod_bound :: { GenericBound Span } + : lifetime { OutlivesBound $1 (spanOf $1) } + | poly_trait_ref { TraitBound $1 None (spanOf $1) } + | '?' poly_trait_ref { TraitBound $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) } +ty_param_bound_mod :: { GenericBound Span } + : ty_param_bound { $1 } + | '?' poly_trait_ref { TraitBound $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 "cdecl") Nothing -> pure Cdecl + LiteralTok (StrTok "stdcall") Nothing -> pure Stdcall + LiteralTok (StrTok "fastcall") Nothing -> pure Fastcall + LiteralTok (StrTok "thiscall") Nothing -> pure Thiscall + 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 "amdgpu-kernel") Nothing -> pure AmdGpuKernel + 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 + LiteralTok (StrTok "unadjusted") Nothing -> pure Unadjusted _ -> parseError $1 {- "invalid ABI" -} } | {- empty -} { C } --- parse_ret_ty +-- parse_ret_ty(allow_plus = true) ret_ty :: { Maybe (Ty Span) } + : '->' ty { Just $2 } + | {- empty -} { Nothing } + +-- parse_ret_ty(allow_plus = false) +ret_ty_no_plus :: { Maybe (Ty Span) } : '->' ty_no_plus { Just $2 } | {- empty -} { Nothing } +-- Must contain a sum ( +ret_ty_plus :: { Maybe (Ty Span) } + : '->' sum_ty { Just $2 } + -- parse_poly_trait_ref() poly_trait_ref :: { PolyTraitRef Span } : trait_ref { PolyTraitRef [] $1 (spanOf $1) } @@ -737,14 +785,14 @@ poly_trait_ref :: { PolyTraitRef Span } -- parse_for_lts() -- Unlike the Rust libsyntax version, this _requires_ the 'for' -for_lts :: { Spanned [LifetimeDef Span] } +for_lts :: { Spanned [GenericParam 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 # $>) } +lifetime_def :: { GenericParam Span } + : many(outer_attribute) lifetime ':' sep_byT(lifetime,'+') { LifetimeParam $1 $2 [ OutlivesBound l (spanOf l) | l <- $4 ] ($1 # $2 # $>) } + | many(outer_attribute) lifetime { LifetimeParam $1 $2 [] ($1 # $2 # $>) } --------------- @@ -753,8 +801,8 @@ lifetime_def :: { LifetimeDef Span } -- Argument (requires a name / pattern, ie. @parse_arg_general(true)@) arg_named :: { Arg Span } - : ntArg { $1 } - | pat ':' ty { Arg (Just $1) $3 ($1 # $3) } + : ntArg { $1 } + | many(outer_attribute) pat ':' ty { Arg $1 (Just $2) $4 ($1 # $2 # $3) } -- Argument (does not require a name / pattern, ie. @parse_arg_general(false)@) -- @@ -762,49 +810,41 @@ arg_named :: { Arg Span } -- 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 # $>) } + | many(outer_attribute) ty { Arg $1 Nothing $2 ($1 # $1) } + | many(outer_attribute) '_' ':' ty { Arg $1 (Just (WildP (spanOf $2))) $4 ($1 # $2 # $3) } + | many(outer_attribute) ident ':' ty { Arg $1 (Just (IdentP (ByValue Immutable) (unspan $2) Nothing (spanOf $2))) $4 ($1 # $2 # $4) } + | many(outer_attribute) mut ident ':' ty { Arg $1 (Just (IdentP (ByValue Mutable) (unspan $3) Nothing (spanOf $3))) $5 ($1 # $2 # $4) } + | many(outer_attribute) '&' '_' ':' ty { Arg $1 (Just (RefP (WildP (spanOf $3)) Immutable ($2 # $3))) $5 ($1 # $2 # $4) } + | many(outer_attribute) '&' ident ':' ty { Arg $1 (Just (RefP (IdentP (ByValue Immutable) (unspan $3) Nothing (spanOf $3)) Immutable ($2 # $3))) $5 ($1 # $2 # $5) } + | many(outer_attribute) '&&' '_' ':' ty { Arg $1 (Just (RefP (RefP (WildP (spanOf $3)) Immutable (nudge 1 0 ($2 # $3))) Immutable ($2 # $3))) $5 ($1 # $2 # $5) } + | many(outer_attribute) '&&' ident ':' ty { Arg $1 (Just (RefP (RefP (IdentP (ByValue Immutable) (unspan $3) Nothing (spanOf $3)) Immutable (nudge 1 0 ($2 # $3))) Immutable ($2 # $3))) $5 ($1 # $2 # $4) } + +-- Self argument (only allowed in trait/impl function signatures) +arg_self :: { Arg Span } + : many(outer_attribute) self { SelfValue $1 Immutable ($1 # $2 # $>) } + | many(outer_attribute) mut self { SelfValue $1 Mutable ($1 # $2 # $>) } + | many(outer_attribute) '&' self { SelfRegion $1 Nothing Immutable ($1 # $2 # $>) } + | many(outer_attribute) '&' lifetime self { SelfRegion $1 (Just $3) Immutable ($1 # $2 # $>) } + | many(outer_attribute) '&' mut self { SelfRegion $1 Nothing Mutable ($1 # $2 # $>) } + | many(outer_attribute) '&' lifetime mut self { SelfRegion $1 (Just $3) Mutable ($1 # $2 # $>) } + | many(outer_attribute) self ':' ty { SelfExplicit $1 $4 Immutable ($1 # $2 # $>) } + | many(outer_attribute) mut self ':' ty { SelfExplicit $1 $5 Mutable ($1 # $2 # $>) } -- 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) } + : ntArg { $1 } + | many(outer_attribute) pat ':' ty { Arg $1 (Just $2) $4 ($1 # $2 # $3) } + | many(outer_attribute) pat { Arg $1 (Just $2) (Infer mempty) ($1 # $2) } -------------- -- Patterns -- -------------- +top_pat :: { Pat Span } + : '|' or_pat { $> } + | or_pat { $> } + -- 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 @@ -812,6 +852,7 @@ lambda_arg :: { Arg Span } pat :: { Pat Span } : ntPat { $1 } | '_' { WildP (spanOf $1) } + | '..' { RestP (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) } @@ -828,46 +869,29 @@ pat :: { Pat Span } _ -> 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 # $>) } + | lit_or_path '...' lit_or_path { RangeP $1 $3 Closed ($1 # $>) } + | lit_or_path '..=' lit_or_path { RangeP $1 $3 Closed ($1 # $>) } + | lit_or_path '..' lit_or_path { RangeP $1 $3 HalfOpen ($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_path '(' sep_byT(or_pat,',') ')' { TupleStructP $1 $3 ($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)) + | '[' sep_byT(or_pat,',') ']' { SliceP $2 ($1 # $>) } + | '(' ')' { TupleP [] ($1 # $>) } + | '(' sep_by1(or_pat,',') ',' ')' { TupleP (toList $2) ($1 # $>) } + | '(' sep_by1(or_pat,',') ')' { + case toList $2 of + l @ [RestP _] -> TupleP l ($1 # $>) -- (..) is a tuple pattern + [p] -> ParenP p ($1 # $>) -- () is parenthesis around a pattern + l -> TupleP l ($1 # $>) -- (, ) is a tuple pattern } - --- 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, []) } - +-- Or-pattern +or_pat :: { Pat Span } + : sep_by1(pat,'|') { + case toNonEmpty $1 of + [p] -> p + ps -> OrP ps (spanOf ps) + } -- Endpoints of range patterns lit_or_path :: { Expr Span } @@ -876,18 +900,19 @@ lit_or_path :: { Expr Span } | '-' lit_expr { Unary [] Neg $2 ($1 # $2) } | lit_expr { $1 } --- Used in patterns for tuple and expression patterns +-- Used in patterns for expression patterns pat_fields :: { ([FieldPat Span], Bool) } - : sep_byT(pat_field,',') { ($1, False) } + : '..' { ([], True) } + | 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) } + : many(outer_attribute) binding_mode ident + { FieldPat Nothing (IdentP (unspan $2) (unspan $3) Nothing (spanOf $1)) $1 ($1 # $2 # $3) } + | many(outer_attribute) box binding_mode ident + { FieldPat Nothing (BoxP (IdentP (unspan $3) (unspan $4) Nothing ($3 # $4)) ($2 # $4)) $1 ($1 # $2 # $4) } + | many(outer_attribute) binding_mode ident ':' or_pat + { FieldPat (Just (unspan $3)) $5 $1 ($1 # $2 # $3 # $5) } -- Used prefixing IdentP patterns (not empty - that is a seperate pattern case) @@ -916,7 +941,7 @@ binding_mode :: { Spanned BindingMode } -- -- * '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 '..'/'.../..=' +-- * 'rhs2' - expressions optionally allowed on the right extremity of terms -- -- Precedences are handled by Happy (right at the end of the token section) gen_expression(lhs,rhs,rhs2) :: { Expr Span } @@ -948,24 +973,18 @@ gen_expression(lhs,rhs,rhs2) :: { Expr Span } | '..=' %prec SINGLERNG { Range [] Nothing Nothing Closed (spanOf $1) } -- low precedence prefix expressions | return { Ret [] Nothing (spanOf $1) } - | return rhs { Ret [] (Just $2) ($1 # $2) } + | return rhs2 { Ret [] (Just $2) ($1 # $2) } | yield { Yield [] Nothing (spanOf $1) } - | yield rhs { Yield [] (Just $2) ($1 # $2) } + | yield rhs2 { 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 rhs2 { 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) } + | break label rhs2 %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 # $>) } + | lambda_prefix rhs %prec LAMBDA { $1 Nothing $> } + -- Variant of 'gen_expression' which only constructs expressions starting with another expression. left_gen_expression(lhs,rhs,rhs2) :: { Expr Span } @@ -1002,7 +1021,6 @@ left_gen_expression(lhs,rhs,rhs2) :: { Expr Span } | 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 # $>) } @@ -1022,67 +1040,30 @@ left_gen_expression(lhs,rhs,rhs2) :: { Expr Span } -- postfix_blockexpr(lhs) :: { Expr Span } : lhs '?' { Try [] $1 ($1 # $>) } + | lhs '.' await { Await [] $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 # $>) } + { MethodCall [] $1 (PathSegment (unspan $3) Nothing (spanOf $3)) $5 ($1 # $>) } | lhs '.' ident '::' '<' sep_byT(ty,',') '>' '(' sep_byT(expr,',') ')' - { MethodCall [] $1 (unspan $3) (Just $6) $9 ($1 # $>) } + { MethodCall [] $1 (PathSegment (unspan $3) (Just (AngleBracketed (map TypeArg $6) [] ($5 # $7))) ($3 # $7)) $9 ($1 # $>) } | lhs '.' int {% - case lit $3 of + lit $3 >>= \l -> case l 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) +-- ['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) +-- ['nostructblock_expr'] Forbids struct literals and block expressions, but not block-like things +-- like 'if' expressions or 'loop' expressions (for use as an optional +-- right hand side of a `nostruct_expr` expression). -- --- ['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) +-- ['nonblock_expr'] Forbids expressions starting with blocks like '{ 1 } + 2', but not +-- struct expressions since 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. @@ -1095,30 +1076,31 @@ expr :: { Expr Span } | paren_expr { $1 } | struct_expr { $1 } | block_expr { $1 } - | lambda_expr_block { $1 } + | lambda_expr_with_ty { $1 } nostruct_expr :: { Expr Span } - : gen_expression(nostruct_expr,nostruct_expr,nonstructblock_expr) { $1 } + : gen_expression(nostruct_expr,nostruct_expr,nostructblock_expr) { $1 } | paren_expr { $1 } | block_expr { $1 } + | lambda_expr_with_ty { $1 } -nonstructblock_expr :: { Expr Span } - : gen_expression(nonstructblock_expr,nostruct_expr,nonstructblock_expr) { $1 } +nostructblock_expr :: { Expr Span } + : gen_expression(nostructblock_expr,nostruct_expr,nostructblock_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) } + | annotated_block { $1 } + | lambda_expr_with_ty { $1 } nonblock_expr :: { Expr Span } : gen_expression(nonblock_expr,expr,expr) { $1 } | paren_expr { $1 } | struct_expr { $1 } - | lambda_expr_block { $1 } + | lambda_expr_with_ty { $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 } + | left_gen_expression(blockpostfix_expr,expr,expr) { $1 } -- Finally, what remains is the more mundane definitions of particular types of expressions. @@ -1135,35 +1117,48 @@ lit_expr :: { Expr Span } -- 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. + | unannotated_block { $1 } + | annotated_block { $1 } + +-- simple expression that is a block (no prefix, just '{ ... }') +unannotated_block :: { Expr Span } + : inner_attrs_block { let (as,b) = $1 in BlockExpr as b Nothing (spanOf b) } + +-- `unsafe` and `async` block expressions +annotated_block :: { Expr Span } + : unsafe inner_attrs_block + { let (as, Block ss r x) = $> in BlockExpr as (Block ss Unsafe ($1 # x)) Nothing ($1 # x) } + | async inner_attrs_block { let (as,b) = $> in Async as Ref b ($1 # b) } + | async move inner_attrs_block { let (as,b) = $> in Async as Value b ($1 # b) } + +-- Any expression ending in a '{ ... }' block except those that cause ambiguities with statements +-- (eg. 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_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 top_pat in nostruct_expr inner_attrs_block { let (as,b) = $> in ForLoop as $2 $4 b Nothing ($1 # b) } + | label ':' for top_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 top_pat '=' nostruct_expr inner_attrs_block { let (as,b) = $> in WhileLet as $3 $5 b Nothing ($1 # b) } + | label ':' while let top_pat '=' 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 # $>) } + | try inner_attrs_block { let (as,b) = $> in TryBlock as b ($1 # b) } + | label ':' inner_attrs_block { let (as,b) = $> in BlockExpr as b (Just $1) ($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 # $>) } + : if nostruct_expr block else_expr { If [] $2 $3 $4 ($1 # $3 # $>) } + | if let top_pat '=' 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 block { Just (BlockExpr [] $2 Nothing (spanOf $2)) } | else if_expr { Just $2 } | {- empty -} { Nothing } @@ -1172,11 +1167,7 @@ else_expr :: { Maybe (Expr Span) } 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 } + | many(outer_attribute) top_pat arm_guard '=>' expr_arms { let (e,as) = $> in (Arm $1 $2 $3 e ($1 # $2 # e) : as) } arm_guard :: { Maybe (Expr Span) } : {- empty -} { Nothing } @@ -1209,17 +1200,29 @@ paren_expr :: { Expr Span } | '(' 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 # $>) } +-- A lambda expression with a return type. This is seperate from the `gen_expression` production +-- because the RHS _has_ to be a block. +lambda_expr_with_ty :: { Expr Span } + : lambda_prefix '->' ty block { $1 (Just $3) (BlockExpr [] $> Nothing (spanOf $>)) } + +-- Given a return type and a body, make a lambda expression +lambda_prefix :: { Maybe (Ty Span) -> Expr Span -> Expr Span } + : static async move lambda_args + { \retTy body -> Closure [] Value IsAsync Immovable (FnDecl (unspan $4) retTy False (spanOf $4)) body ($1 # body) } + | async move lambda_args + { \retTy body -> Closure [] Value IsAsync Movable (FnDecl (unspan $3) retTy False (spanOf $3)) body ($1 # body) } + | static move lambda_args + { \retTy body -> Closure [] Value NotAsync Immovable (FnDecl (unspan $3) retTy False (spanOf $3)) body ($1 # body) } + | move lambda_args + { \retTy body -> Closure [] Value NotAsync Movable (FnDecl (unspan $2) retTy False (spanOf $2)) body ($1 # body) } + | static async lambda_args + { \retTy body -> Closure [] Ref IsAsync Immovable (FnDecl (unspan $3) retTy False (spanOf $3)) body ($1 # body) } + | async lambda_args + { \retTy body -> Closure [] Ref IsAsync Movable (FnDecl (unspan $2) retTy False (spanOf $2)) body ($1 # body) } + | static lambda_args + { \retTy body -> Closure [] Ref NotAsync Immovable (FnDecl (unspan $2) retTy False (spanOf $2)) body ($1 # body) } + | lambda_args + { \retTy body -> Closure [] Ref NotAsync Movable (FnDecl (unspan $1) retTy False (spanOf $1)) body ($1 # body) } -- Lambda expression arguments block lambda_args :: { Spanned [Arg Span] } @@ -1229,37 +1232,66 @@ lambda_args :: { Spanned [Arg Span] } -- 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 # $>) } + : expr_path struct_suffix { $2 $1 } + +struct_suffix :: { Path Span -> Expr Span } + : '{' '..' expr '}' { \p -> Struct [] p [] (Just $3) (p # $>) } + | '{' inner_attrs '..' expr '}' { \p -> Struct (toList $2) p [] (Just $4) (p # $>) } + | '{' sep_by1(field,',') ',' '..' expr '}' { \p -> Struct [] p (toList $2) (Just $5) (p # $>) } + | '{' inner_attrs sep_by1(field,',') ',' '..' expr '}' { \p -> Struct (toList $2) p (toList $3) (Just $6) (p # $>) } + | '{' sep_byT(field,',') '}' { \p -> Struct [] p $2 Nothing (p # $>) } + | '{' inner_attrs sep_byT(field,',') '}' { \p -> Struct (toList $2) p $3 Nothing (p # $>) } field :: { Field Span } - : ident ':' expr { Field (unspan $1) (Just $3) ($1 # $3) } - | ident { Field (unspan $1) Nothing (spanOf $1) } + : many(outer_attribute) ident ':' expr { Field (unspan $2) (Just $4) $1 ($1 # $2 # $4) } + | many(outer_attribute) ident { Field (unspan $2) Nothing $1 ($1 # $2) } -- 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 - } + : vis unannotated_block {% noVis $1 $> } + | vis annotated_block {% noVis $1 $> } --- 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 } +-- Like 'nonblock_expr', but for expressions which explicitly conflict with +-- other statements: +-- +-- * expressions starting with `union`, `default`, or `auto` (conflicts with +-- union items, default impls, and auto impls) +-- +-- * expressions starting with `unsafe`, `static` (conflicts with unsafe +-- functions and static items) +-- +-- This rule is designed to mesh with the `stmt` rule (hence the `vis`/`noVis` +-- and `safety`/`noSafety` dance). It _only_ generates the problematic cases +-- laid out above. Generating more cases would imply a conflict with the other +-- expression rules for statements. +conflict_nonblock_expr :: { Expr Span } + : conflict_expr_path { (PathExpr [] Nothing $> (spanOf $>)) } + | conflict_expr_path struct_suffix { ($2 $1) } + | vis lambda_expr_with_ty {% noVis $1 $2 } + | vis lambda_prefix expr %prec '::' {% noVis $1 ($2 Nothing $>) } + | left_gen_expression(conflict_nonblock_expr, expr, expr) { $1 } + | conflict_expr_path '!' '(' token_stream ')' { MacExpr [] (Mac $1 $4 ($1 # $>)) ($1 # $>) } + | conflict_expr_path '!' '[' token_stream ']' { MacExpr [] (Mac $1 $4 ($1 # $>)) ($1 # $>) } + +-- Like 'block_like_expr', but for expressions which explicitly conflict with +-- other statements: +-- +-- * expressions starting with `union`, `default`, or `auto` (conflicts with +-- union items, default impls, and auto impls) +-- +-- See comments/motivation on 'conflict_nonblock_expr' +conflict_block_like_expr :: { Expr Span } + : conflict_expr_path '!' '{' token_stream '}' { MacExpr [] (Mac $1 $4 ($1 # $>)) ($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)) - } +-- Problematic "contextual" identifiers +conflict_ident :: { Spanned Ident } + : vis union {% noVis $1 (Spanned "union" (spanOf $>)) } + | vis default {% noVis $1 (Spanned "default" (spanOf $>)) } + | vis safety auto {% noSafety $2 =<< noVis $1 (Spanned "auto" (spanOf $>)) } + +-- Expression path starting with a problematic identifier +conflict_expr_path :: { Path Span } + : gen_expr_path_segments(conflict_ident) { Path False (toList $1) (spanOf $1) } ---------------- @@ -1267,83 +1299,91 @@ union_default_expr :: { Expr Span } ---------------- 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 } + : ntStmt { $1 } + | many(outer_attribute) let top_pat ':' ty initializer ';' { Local $3 (Just $5) $6 $1 ($1 # $2 # $>) } + | many(outer_attribute) let top_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) conflict_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) conflict_block_like_expr ';' { toStmt ($1 `addAttrs` $2) False True ($1 # $2 # $3) } + | many(outer_attribute) block_like_expr %prec NOSEMI { toStmt ($1 `addAttrs` $2) False True ($1 # $2) } + | many(outer_attribute) conflict_block_like_expr %prec NOSEMI { toStmt ($1 `addAttrs` $2) False True ($1 # $2) } + | many(outer_attribute) blockpostfix_expr ';' { toStmt ($1 `addAttrs` $2) True True ($1 # $2 # $3) } + | 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) } + | item ';' { ItemStmt $1 ($1 # $2) } + | item %prec NOSEMI { ItemStmt $1 (spanOf $1) } + | many(outer_attribute) macro_rules '!' ident '[' token_stream ']' ';' + { let s = $1 # $2 # $> in ItemStmt (MacroDef $1 InheritedV (unspan $4) $6 s) s } + | many(outer_attribute) macro_rules '!' ident '(' token_stream ')' ';' + { let s = $1 # $2 # $> in ItemStmt (MacroDef $1 InheritedV (unspan $4) $6 s) s } + | many(outer_attribute) macro_rules '!' ident '{' token_stream '}' %prec NOSEMI + { let s = $1 # $2 # $> in ItemStmt (MacroDef $1 InheritedV (unspan $4) $6 s) s } + | many(outer_attribute) macro_rules '!' ident '{' token_stream '}' ';' + { let s = $1 # $2 # $> in ItemStmt (MacroDef $1 InheritedV (unspan $4) $6 s) s } + | many(outer_attribute) macro_rules '!' '[' token_stream ']' ';' + { MacStmt (Mac (macroRulesPath $2) $5 ($2 # $6)) SemicolonMac $1 ($1 # $2 # $>) } + | many(outer_attribute) macro_rules '!' '{' token_stream '}' + { MacStmt (Mac (macroRulesPath $2) $5 ($2 # $6)) BracesMac $1 ($1 # $2 # $>) } + | many(outer_attribute) macro_rules '!' '(' token_stream ')' ';' + { MacStmt (Mac (macroRulesPath $2) $5 ($2 # $6)) SemicolonMac $1 ($1 # $2 # $>) } + | ';' { StandaloneSemi (spanOf $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))] } +stmts_possibly_no_semi :: { [Stmt Span] } + : stmt stmts_possibly_no_semi { $1 : $2 } + | stmt { [$1] } + | many(outer_attribute) nonblock_expr { [toStmt ($1 `addAttrs` $2) False False ($1 # $2)] } + | many(outer_attribute) conflict_nonblock_expr { [toStmt ($1 `addAttrs` $2) False False ($1 # $2)] } + | many(outer_attribute) blockpostfix_expr { [toStmt ($1 `addAttrs` $2) False True ($1 # $2)] } initializer :: { Maybe (Expr Span) } - : '=' expr { Just $2 } + : '=' many(outer_attribute) expr { Just ($2 `addAttrs` $3) } | {- empty -} { Nothing } block :: { Block Span } : ntBlock { $1 } | '{' '}' { Block [] Normal ($1 # $>) } - | '{' stmts_possibly_no_semi '}' { Block [ s | Just s <- $2 ] Normal ($1 # $>) } + | '{' stmts_possibly_no_semi '}' { Block $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 # $>)) } + | '{' inner_attrs stmts_possibly_no_semi '}' { (toList $2, Block $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 } +item :: { 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 const '_' ':' ty '=' expr ';' + { ConstItem $1 (unspan $2) "_" $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 ';' + | many(outer_attribute) vis safety extern crate ident_or_self ';' {% noSafety $3 (ExternCrate $1 (unspan $2) (unspan $6) Nothing ($1 # $2 # $4 # $>)) } - | many(outer_attribute) vis safety extern crate ident as ident ';' + | many(outer_attribute) vis safety extern crate ident_or_self 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 safety extern crate ident_or_self as '_' ';' + {% noSafety $3 (ExternCrate $1 (unspan $2) "_" (Just (unspan $6)) ($1 # $2 # $4 # $>)) } + | many(outer_attribute) vis const safety fn ident generics fn_decl(arg_named, ret_ty) where_clause inner_attrs_block + { Fn ($1 ++ fst $>) (unspan $2) (unspan $6) $8 (FnHeader (unspan $4) NotAsync Const Rust (spanOf $4)) ($7 `withWhere` $9) (snd $>) ($1 # $2 # $3 # snd $>) } + | many(outer_attribute) vis async safety fn ident generics fn_decl(arg_named, ret_ty) where_clause inner_attrs_block + { Fn ($1 ++ fst $>) (unspan $2) (unspan $6) $8 (FnHeader (unspan $4) IsAsync NotConst Rust (spanOf $4)) ($7 `withWhere` $9) (snd $>) ($1 # $2 # $3 # snd $>) } + | many(outer_attribute) vis safety extern abi fn ident generics fn_decl(arg_named, ret_ty) where_clause inner_attrs_block + { Fn ($1 ++ fst $>) (unspan $2) (unspan $7) $9 (FnHeader (unspan $3) NotAsync NotConst $5 ($3 # $4)) ($8 `withWhere` $10) (snd $>) ($1 # $2 # $3 # $4 # snd $>) } + | many(outer_attribute) vis safety fn ident generics fn_decl(arg_named, ret_ty) where_clause inner_attrs_block + { Fn ($1 ++ fst $>) (unspan $2) (unspan $5) $7 (FnHeader (unspan $3) NotAsync NotConst Rust (spanOf $3)) ($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) '}' @@ -1360,16 +1400,16 @@ gen_item(vis) :: { Item Span } { 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 ':' sep_byT(ty_param_bound,'+') where_clause '{' many(trait_item) '}' + { Trait $1 (unspan $2) (unspan $5) False (unspan $3) ($6 `withWhere` $9) $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 ':' sep_byT(ty_param_bound,'+') where_clause '{' many(trait_item) '}' + { Trait $1 (unspan $2) (unspan $6) True (unspan $3) ($7 `withWhere` $10) $9 $12 ($1 # $2 # $3 # $4 # $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 # $>)) } + { Trait $1 (unspan $2) (unspan $6) True (unspan $3) ($7 `withWhere` $8) [] $10 ($1 # $2 # $3 # $4 # $5 # $>) } + | many(outer_attribute) vis safety trait ident generics '=' sep_byT(ty_param_bound_mod,'+') where_clause ';' + {% noSafety $3 (TraitAlias $1 (unspan $2) (unspan $5) ($6 `withWhere` $9) $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 '}' @@ -1386,50 +1426,80 @@ gen_item(vis) :: { Item Span } { 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 # $>) } + | many(outer_attribute) vis macro ident '(' token_stream ')' '{' token_stream '}' + { MacroDef $1 (unspan $2) (unspan $4) (Stream [ Tree (Delimited ($5 # $7) Paren $6) + , Tree (Token mempty FatArrow) + , Tree (Delimited ($8 # $10) Brace $9) ]) ($1 # $2 # $3 # $>) } + | many(outer_attribute) vis macro ident '{' token_stream '}' + { MacroDef $1 (unspan $2) (unspan $4) $6 ($1 # $2 # $3 # $>) } -- 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 # $>) } + : ntItem { $1 } + | item { $1 } + | many(outer_attribute) mod_mac { MacItem $1 $2 ($1 # $2) } + | many(outer_attribute) conflict_mod_path '!' '[' token_stream ']' ';' { MacItem $1 (Mac $2 $5 ($2 # $>)) ($1 # $2 # $>) } + | many(outer_attribute) conflict_mod_path '!' '{' token_stream '}' { MacItem $1 (Mac $2 $5 ($2 # $>)) ($1 # $2 # $>) } + | many(outer_attribute) conflict_mod_path '!' '(' token_stream ')' ';' { MacItem $1 (Mac $2 $5 ($2 # $>)) ($1 # $2 # $>) } + | many(outer_attribute) macro_rules '!' ident '[' token_stream ']' ';' + { MacroDef $1 InheritedV (unspan $4) $6 ($1 # $2 # $>) } + | many(outer_attribute) macro_rules '!' ident '(' token_stream ')' ';' + { MacroDef $1 InheritedV (unspan $4) $6 ($1 # $2 # $>) } + | many(outer_attribute) macro_rules '!' ident '{' token_stream '}' + { MacroDef $1 InheritedV (unspan $4) $6 ($1 # $2 # $>) } + | many(outer_attribute) macro_rules '!' '[' token_stream ']' ';' + { MacItem $1 (Mac (macroRulesPath $2) $5 ($2 # $>)) ($1 # $2 # $>) } + | many(outer_attribute) macro_rules '!' '{' token_stream '}' + { MacItem $1 (Mac (macroRulesPath $2) $5 ($2 # $>)) ($1 # $2 # $>) } + | many(outer_attribute) macro_rules '!' '(' token_stream ')' ';' + { MacItem $1 (Mac (macroRulesPath $2) $5 ($2 # $>)) ($1 # $2 # $>) } + +-- Module path starting with a problematic identifier +conflict_mod_path :: { Path Span } + : conflict_ident + { Path False [PathSegment (unspan $1) Nothing (spanOf $1)] (spanOf $1) } + | conflict_mod_path '::' path_segment_ident + { + let Path g segs _ = $1 in + Path g (segs <> [PathSegment (unspan $3) Nothing (spanOf $3) ]) ($1 # $3) + } 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 ';' + | many(outer_attribute) vis fn ident generics fn_decl(arg_named, ret_ty) 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 # $>) } + | many(outer_attribute) mod_mac + { ForeignMac $1 $2 ($1 # $>) } -- 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 } + : generics1 { $1 } + | {- empty -} { Generics [] (WhereClause [] mempty) mempty } + +generics1 :: { Generics Span } + : ntGenerics { $1 } + | '<' sep_byT(generic_param,',') gt '>' { Generics $2 (WhereClause [] mempty) ($1 # $>) } + +ty_param :: { GenericParam Span } + : many(outer_attribute) ident { TypeParam $1 (unspan $2) [] Nothing ($1 # $>) } + | many(outer_attribute) ident ':' sep_byT(ty_param_bound_mod,'+') { TypeParam $1 (unspan $2) $4 Nothing ($1 # $>) } + | many(outer_attribute) ident '=' ty { TypeParam $1 (unspan $2) [] (Just $>) ($1 # $>) } + | many(outer_attribute) ident ':' sep_byT(ty_param_bound_mod,'+') '=' ty { TypeParam $1 (unspan $2) $4 (Just $>) ($1 # $>) } + | many(outer_attribute) ident ':' sep_by1(ty_param_bound_mod,'+') '+=' ty { TypeParam $1 (unspan $2) (toList $4) (Just $>) ($1 # $>) } -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 # $>) } +const_param :: { GenericParam Span } + : many(outer_attribute) const ident ':' ty { ConstParam $1 (unspan $3) $5 ($1 # $2 # $>) } +generic_param :: { GenericParam Span } + : ty_param { $1 } + | lifetime_def { $1 } + | const_param { $1 } struct_decl_args :: { (WhereClause Span, VariantData Span) } : where_clause ';' { ($1, UnitD ($1 # $>)) } @@ -1443,27 +1513,28 @@ 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 # $>) } + : many(outer_attribute) ident '{' sep_byT(struct_decl_field,',') '}' initializer + { Variant (unspan $2) $1 (StructD $4 ($3 # $5)) $> ($1 # $2 # $5 # $>) } + | many(outer_attribute) ident '(' sep_byT(tuple_decl_field,',') ')' initializer + { Variant (unspan $2) $1 (TupleD $4 ($3 # $5)) $> ($1 # $2 # $5 # $>) } + | 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 sep_byT(where_predicate,',') %prec WHERE { WhereClause $2 ($1 # $2) } where_predicate :: { WherePredicate Span } : lifetime { RegionPredicate $1 [] (spanOf $1) } - | lifetime ':' sep_by1T(lifetime,'+') { RegionPredicate $1 (toList $3) ($1 # $3) } + | lifetime ':' sep_byT(lifetime,'+') { RegionPredicate $1 $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) } + | no_for_ty ':' sep_byT(ty_param_bound_mod,'+') { BoundPredicate [] $1 $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 # $>) } + | for_lts no_for_ty ':' sep_byT(ty_param_bound_mod,'+') { BoundPredicate (unspan $1) $2 $4 ($1 # $>) } impl_items :: { ([Attribute Span], [ImplItem Span]) } : many(impl_item) { ([], $1) } @@ -1474,29 +1545,37 @@ impl_item :: { ImplItem Span } | 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 + | many(outer_attribute) vis def const safety fn ident generics fn_decl_with_self where_clause inner_attrs_block + { let methodSig = MethodSig (FnHeader (unspan $5) NotAsync Const Rust (spanOf $5)) $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 + | many(outer_attribute) vis def async safety fn ident generics fn_decl_with_self where_clause inner_attrs_block + { let methodSig = MethodSig (FnHeader (unspan $5) IsAsync NotConst Rust (spanOf $5)) $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 where_clause inner_attrs_block + { let methodSig = MethodSig (FnHeader (unspan $4) NotAsync NotConst (unspan $5) ($4 # $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 $>) } + | many(outer_attribute) type ident ':' sep_byT(ty_param_bound_mod,'+') ';' + { TypeT $1 (unspan $3) $5 Nothing ($1 # $2 # $>) } + | many(outer_attribute) type ident ':' sep_byT(ty_param_bound_mod,'+') '=' ty ';' + { TypeT $1 (unspan $3) $5 (Just $7) ($1 # $2 # $>) } + | many(outer_attribute) is_async safety ext_abi fn ident generics fn_decl_with_self where_clause ';' + { let methodSig = MethodSig (FnHeader (unspan $3) (unspan $2) NotConst (unspan $4) ($2 # $3 # $4)) $8; generics = $7 `withWhere` $9 + in MethodT $1 (unspan $6) generics methodSig Nothing ($1 # $2 # $3 # $4 # $5 # $>) } + | many(outer_attribute) is_async safety ext_abi fn ident generics fn_decl_with_self where_clause inner_attrs_block + { let methodSig = MethodSig (FnHeader (unspan $3) (unspan $2) NotConst (unspan $4) ($2 # $3 # $4)) $8; generics = $7 `withWhere` $9 + in MethodT ($1 ++ fst $>) (unspan $6) generics methodSig (Just (snd $>)) ($1 # $2 # $3 # $4 # $5 # snd $>) } + +is_async :: { Spanned IsAsync } + : {- empty -} { pure NotAsync } + | async { Spanned IsAsync (spanOf $1) } safety :: { Spanned Unsafety } : {- empty -} { pure Normal } @@ -1510,12 +1589,12 @@ 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) } + | crate %prec VIS { 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) } + | 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 } @@ -1524,6 +1603,7 @@ def :: { Spanned Defaultness } use_tree :: { UseTree Span } : mod_path { UseTreeSimple $1 Nothing (spanOf $1) } | mod_path as ident { UseTreeSimple $1 (Just (unspan $3)) ($1 # $3) } + | mod_path as '_' { UseTreeSimple $1 (Just "_") ($1 # $3) } | mod_path '::' '*' { UseTreeGlob $1 ($1 # $3) } | '::' '*' { UseTreeGlob (Path True [] (spanOf $1)) ($1 # $2) } | '*' { UseTreeGlob (Path False [] mempty) (spanOf $1) } @@ -1562,7 +1642,7 @@ token_tree :: { TokenTree } -- # Delimited | '(' token_stream ')' { Delimited ($1 # $3) Paren $2 } | '{' token_stream '}' { Delimited ($1 # $3) Brace $2 } - | '[' token_stream ']' { Delimited ($1 # $3) Bracket $2 } + | '[' token_stream ']' { Delimited ($1 # $3) Bracket $2 } -- # Token | token { let Spanned t s = $1 in Token s t } @@ -1626,11 +1706,14 @@ token :: { Spanned Token } | rawByteStr { $1 } -- Strict keywords used in the language | as { $1 } + | async { $1 } + | await { $1 } | box { $1 } | break { $1 } | const { $1 } | continue { $1 } | crate { $1 } + | dyn { $1 } | else { $1 } | enum { $1 } | extern { $1 } @@ -1642,6 +1725,7 @@ token :: { Spanned Token } | in { $1 } | let { $1 } | loop { $1 } + | macro { $1 } | match { $1 } | mod { $1 } | move { $1 } @@ -1656,34 +1740,29 @@ token :: { Spanned Token } | super { $1 } | trait { $1 } | true { $1 } + | try { $1 } | type { $1 } | unsafe { $1 } | use { $1 } | where { $1 } | while { $1 } + | yield { $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 } + | macro_rules { $1 } -- Comments | outerDoc { $1 } | innerDoc { $1 } @@ -1709,7 +1788,7 @@ export_attribute :: { Attribute Span } 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 # $>) } + | safety '{' stmts_possibly_no_semi '}' { Block $3 (unspan $1) ($1 # $2 # $>) } { -- | Parser for literals. @@ -1724,6 +1803,9 @@ parseTy :: P (Ty Span) -- | Parser for patterns. parsePat :: P (Pat Span) +-- | Parser for paths. +parsePath :: P (Path Span) + -- | Parser for statements. parseStmt :: P (Stmt Span) @@ -1748,11 +1830,8 @@ 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 generic parameters. +parseGenericParam :: P (GenericParam Span) -- | Parser for a where clause. parseWhereClause :: P (WhereClause Span) @@ -1793,7 +1872,7 @@ expParseError (Spanned t _, exps) = fail $ "Syntax error: unexpected `" ++ show , (byteStrLit, "a byte string" ) , (rawStrLit, "a raw string" ) , (rawByteStrLit, "a raw bytestring") - + , (doc, "a doc" ) , (outerDoc, "an outer doc" ) , (innerDoc, "an inner doc" ) @@ -1808,7 +1887,7 @@ expParseError (Spanned t _, exps) = fail $ "Syntax error: unexpected `" ++ show 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" + words "auto yield try async" lit = boolLit ++ byteLit ++ charLit ++ intLit ++ floatLit ++ strLit ++ byteStrLit ++ rawStrLit ++ rawByteStrLit @@ -1821,12 +1900,12 @@ expParseError (Spanned t _, exps) = fail $ "Syntax error: unexpected `" ++ show byteStrLit = words "byteStr" rawStrLit = words "rawStr" rawByteStrLit = words "rawByteStr" - + doc = outerDoc ++ innerDoc outerDoc = words "outerDoc" innerDoc = words "innerDoc" - identifier = words "IDENT" + identifier = words "IDENT union default auto macro_rules" lifetime = words "LIFETIME" -- | Convert an 'IdentTok' into an 'Ident' @@ -1840,6 +1919,10 @@ 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 +-- | A path containing only the `macro_rules` segment +macroRulesPath :: Spanned a -> Path Span +macroRulesPath (Spanned _ s) = Path False [PathSegment "macro_rules" Nothing s] s + -- | Return the second argument, as long as the visibility is 'InheritedV' noVis :: Spanned (Visibility Span) -> a -> P a noVis (Spanned InheritedV _) x = pure x @@ -1847,25 +1930,19 @@ 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 +withWhere (Generics ps _ x) w = Generics ps 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 (MethodCall as' i p a s) = MethodCall (as ++ as') i p a 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 @@ -1879,9 +1956,11 @@ 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 (Closure as' c a m f e s) = Closure (as ++ as') c a m f e s +addAttrs as (BlockExpr as' b l s) = BlockExpr (as ++ as') b l s +addAttrs as (TryBlock as' b s) = TryBlock (as ++ as') b s +addAttrs as (Async as' c b s) = Async (as ++ as') c b s +addAttrs as (Await as' e s) = Await (as ++ as') e 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 @@ -1903,31 +1982,32 @@ 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 +lit :: Spanned Token -> P (Lit Span) +lit (Spanned (IdentTok (Ident "true" False _)) s) = pure (Bool True Unsuffixed s) +lit (Spanned (IdentTok (Ident "false" False _)) s) = pure (Bool False Unsuffixed s) +lit (Spanned (LiteralTok litTok suffix_m) s) = do + suffix <- case suffix_m of + Nothing -> pure Unsuffixed + Just "_" -> pure Unsuffixed -- See https://github.com/rust-lang/rust/issues/42326 + Just "isize" -> pure Is + Just "usize" -> pure Us + Just "i8" -> pure I8 + Just "u8" -> pure U8 + Just "i16" -> pure I16 + Just "u16" -> pure U16 + Just "i32" -> pure I32 + Just "u32" -> pure U32 + Just "i64" -> pure I64 + Just "u64" -> pure U64 + Just "i128" -> pure I128 + Just "u128" -> pure U128 + Just "f32" -> pure F32 + Just "f64" -> pure F64 + _ -> fail "invalid literal suffix" + pure (translateLit litTok suffix s) + +isTraitBound TraitBound{} = True +isTraitBound _ = False -- | Parse a source file parseSourceFile :: P (SourceFile Span) diff --git a/src/Language/Rust/Parser/Lexer.x b/src/Language/Rust/Parser/Lexer.x index 0f44c80..66cf702 100644 --- a/src/Language/Rust/Parser/Lexer.x +++ b/src/Language/Rust/Parser/Lexer.x @@ -2,7 +2,7 @@ {-| Module : Language.Rust.Parser.Lexer Description : Rust lexer -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -18,16 +18,16 @@ bitwise and, and unary reference), @&&&x&&&y@ lexes into 'AmpersandAmpersand', ' @'IdentTok' "x"@, 'AmpersandAmpersand', 'Ampersand', @'IdentTok' "y"@. Although the parser sometimes needs to "break apart" tokens, it never has to think about putting them together. That means it can easily figure out that @&&&x&&&y@ parses as @&(&(&x)) && (&y)@ and not @&(&(&x)) & (&(&y))@ even if -bitwise conjunctions bind more tightly that logical conjunctions. +bitwise conjunctions bind more tightly that logical conjunctions. -This sort of amguity where one token need to be broken up by the parser occurs for +This sort of ambiguity where one token need to be broken up by the parser occurs for * @&&@ in patterns like @&&mut x@ * @||@ in closures with no arguments like @|| x@ * @<<@ in qualified type paths like @FromIterator\<\::Item\>@ * @>>@ in qualified paths like @\\>::Bar@ * @>=@ in equality predicates like @F\=i32@ - * @>>=@ in equality predicates like @F\\>=i32@ + * @>>=@ in equality predicates like @F\\>=i32@ -} module Language.Rust.Parser.Lexer ( @@ -44,6 +44,10 @@ module Language.Rust.Parser.Lexer ( lexicalError, ) where + +import Prelude hiding ( fail ) +import Control.Monad.Fail ( fail ) + import Language.Rust.Data.Ident ( mkIdent, Ident(..) ) import Language.Rust.Data.InputStream import Language.Rust.Data.Position @@ -63,6 +67,9 @@ import Data.Word ( Word8 ) } +-- Whitespace +$whitespace = [ $white \x0085 \x200e \x200f \x2028 \x2029 ] + -- XID_START unicode character class @xid_start = [\x0041-\x005a] @@ -923,12 +930,7 @@ $hexit = [0-9a-fA-F] @char_escape = [nrt\\'"0] | [xX] [0-7] $hexit - | u\{ $hexit \} - | u\{ $hexit $hexit \} - | u\{ $hexit $hexit $hexit \} - | u\{ $hexit $hexit $hexit $hexit \} - | u\{ $hexit $hexit $hexit $hexit $hexit \} - | u\{ $hexit $hexit $hexit $hexit $hexit $hexit \} + | u\{ _* ( $hexit _* ){1,6} \} @byte_escape = [xX] $hexit $hexit @@ -944,7 +946,7 @@ $hexit = [0-9a-fA-F] \' @lit_byte - = b\' ( \\ @byte_escape + = b\' ( \\ @byte_escape | [^\\'\n\t\r] [ \udc00-\udfff ]? ) \' @@ -985,7 +987,7 @@ $hexit = [0-9a-fA-F] tokens :- -$white+ { \s -> pure (Space Whitespace s) } +$whitespace+ { \s -> pure (Space Whitespace s) } "=" { token Equal } "<" { token Less } @@ -1020,28 +1022,28 @@ $white+ { \s -> pure (Space Whitespace s) } "/=" { token SlashEqual } "^=" { token CaretEqual } "%=" { token PercentEqual } - - -"@" { token At } -"." { token Dot } -".." { token DotDot } -"..." { token DotDotDot } -"..=" { token DotDotEqual } -"," { token Comma } -";" { token Semicolon } + + +"@" { token At } +"." { token Dot } +".." { token DotDot } +"..." { token DotDotDot } +"..=" { token DotDotEqual } +"," { token Comma } +";" { token Semicolon } ":" { token Colon } "::" { token ModSep } "->" { token RArrow } "<-" { token LArrow } "=>" { token FatArrow } -"(" { token (OpenDelim Paren) } -")" { token (CloseDelim Paren) } +"(" { token (OpenDelim Paren) } +")" { token (CloseDelim Paren) } "[" { token (OpenDelim Bracket) } "]" { token (CloseDelim Bracket) } -"{" { token (OpenDelim Brace) } -"}" { token (CloseDelim Brace) } -"#" { token Pound } -"$" { token Dollar } +"{" { token (OpenDelim Brace) } +"}" { token (CloseDelim Brace) } +"#" { token Pound } +"$" { token Dollar } @lit_integer { \i -> literal (IntegerTok i) } @lit_float { \f -> literal (FloatTok f) } @@ -1058,26 +1060,26 @@ $white+ { \s -> pure (Space Whitespace s) } @lit_raw_str { \s -> let n = length s - 2 in do str <- cleanWindowsNewlines `fmap` rawString n - literal (StrRawTok str (fromIntegral n)) + literal (StrRawTok str n) } @lit_raw_bstr { \s -> let n = length s - 3 in do str <- cleanWindowsNewlines `fmap` rawString n - literal (ByteStrRawTok str (fromIntegral n)) + literal (ByteStrRawTok str n) } "" ; @ident { \s -> pure (IdentTok (mkIdent s)) } \? { token Question } -@raw_ident { \s -> pure (IdentTok ((mkIdent (drop 2 s)){ raw = True })) } -@ident { \s -> pure (IdentTok (mkIdent s)) } +@raw_ident { \s -> pure (IdentTok ((mkIdent (drop 2 s)){ raw = True })) } +@ident { \s -> pure (IdentTok (mkIdent s)) } @lifetime { \s -> (pure (LifetimeTok (mkIdent (tail s))) :: P Token) } -@outer_doc_line { \c -> pure (Doc (drop 3 c) Outer False) } -@outer_doc_line \r { \c -> pure (Doc (drop 3 (init c)) Outer False) } -@outer_doc_inline / ( [^\*] | \r | \n ) +@outer_doc_line { \c -> pure (Doc (drop 3 c) Outer False) } +@outer_doc_line \r { \c -> pure (Doc (drop 3 (init c)) Outer False) } +@outer_doc_inline / ( [^\*\/] | \r | \n ) { \_ -> Doc <$> nestedComment <*> pure Outer <*> pure True } @inner_doc_line { \c -> pure (Doc (drop 3 c) Inner False) } @@ -1095,8 +1097,8 @@ token t _ = pure t -- | Given the first part of a literal, try to parse also a suffix. Even if -- the allowed suffixes are very well defined and only valid on integer and -- float literals, we need to put in the same token whatever suffix follows. --- This is for backwards compatibility if Rust decides to ever add suffixes. -literal :: LitTok -> P Token +-- This is for backwards compatibility if Rust decides to ever add suffixes. +literal :: LitTok -> P Token literal lit = do pos <- getPosition inp <- getInput @@ -1119,20 +1121,20 @@ rawString n = do case c_m of -- The string was never closed Nothing -> fail "Invalid raw (byte)string" - + -- The string has a chance of being closed Just '"' -> do n' <- greedyChar '#' n if n' == n then pure "" - else (('"' : replicate n' '#') ++) <$> rawString n + else (('"' : replicate n' '#') ++) <$> rawString n -- Just another character... - Just c -> ([c] ++) <$> rawString n + Just c -> ([c] ++) <$> rawString n -- | Consume a full inline comment (which may be nested). nestedComment :: P String -nestedComment = go 1 "" +nestedComment = fmap cleanWindowsNewlines (go 1 "") where go :: Int -> String -> P String go 0 s = pure (reverse (drop 2 s)) @@ -1142,15 +1144,15 @@ nestedComment = go 1 "" Nothing -> fail "Unclosed comment" Just '*' -> do c' <- peekChar - case c' of + case c' of Nothing -> fail "Unclosed comment" Just '/' -> nextChar *> go (n-1) ('/':'*':s) Just _ -> go n ('*':s) Just '/' -> do c' <- peekChar - case c' of + case c' of Nothing -> fail "Unclosed comment" - Just '*' -> nextChar *> go (n+1) ('*':'/':s) + Just '*' -> nextChar *> go (n+1) ('*':'/':s) Just _ -> go n ('/':s) Just c' -> go n (c':s) @@ -1162,7 +1164,7 @@ nextChar :: P (Maybe Char) nextChar = do pos <- getPosition inp <- getInput - if inputStreamEmpty inp + if inputStreamEmpty inp then pure Nothing else let (c,inp') = takeChar inp pos' = alexMove pos c @@ -1173,7 +1175,7 @@ nextChar = do peekChar :: P (Maybe Char) peekChar = do inp <- getInput - if inputStreamEmpty inp + if inputStreamEmpty inp then pure Nothing else let (c,_) = takeChar inp in pure (Just c) @@ -1195,7 +1197,7 @@ lexicalError = do fail ("Lexical error: the character " ++ show c ++ " does not fit here") --- Functions required by Alex +-- Functions required by Alex -- | type passed around by Alex functions (required by Alex) type AlexInput = (Position, -- current position, @@ -1223,7 +1225,7 @@ alexMove pos '\n' = retPos pos alexMove pos '\r' = incOffset pos 1 alexMove pos _ = incPos pos 1 --- | Lexer for one 'Token'. The only token this cannot produce is 'Interpolated'. +-- | Lexer for one 'Token'. The only token this cannot produce is 'Interpolated'. lexToken :: P (Spanned Token) lexToken = do tok_maybe <- popToken @@ -1245,7 +1247,7 @@ lexToken = do return (Spanned tok' (Span pos pos'')) -- | Lexer for one non-whitespace 'Token'. The only tokens this cannot produce are 'Interpolated' --- and 'Space' (which includes comments that aren't doc comments). +-- and @Space@ (which includes comments that aren't doc comments). lexNonSpace :: P (Spanned Token) lexNonSpace = do tok <- lexToken diff --git a/src/Language/Rust/Parser/Literals.hs b/src/Language/Rust/Parser/Literals.hs index f136364..ebb135b 100644 --- a/src/Language/Rust/Parser/Literals.hs +++ b/src/Language/Rust/Parser/Literals.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Parser.Literals Description : Parsing literals -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -29,16 +29,16 @@ import Text.Read ( readMaybe ) translateLit :: LitTok -> Suffix -> a -> Lit a translateLit (ByteTok s) = Byte (unescapeByte' s) translateLit (CharTok s) = Char (unescapeChar' s) -translateLit (FloatTok s) = Float (unescapeFloat s) +translateLit (FloatTok s) = Float (unescapeFloat s) translateLit (StrTok s) = Str (unfoldr (unescapeChar True) s) Cooked translateLit (StrRawTok s n) = Str s (Raw n) translateLit (ByteStrTok s) = ByteStr (unfoldr (unescapeByte True) s) Cooked -translateLit (ByteStrRawTok s n) = ByteStr (map (fromIntegral . ord) s) (Raw n) +translateLit (ByteStrRawTok s n) = ByteStr (map (fromIntegral . ord) s) (Raw n) translateLit (IntegerTok s) = \suf -> case (suf, unescapeInteger s) of (F32, (Dec, n)) -> Float (fromInteger n) F32 - (F64, (Dec, n)) -> Float (fromInteger n) F64 + (F64, (Dec, n)) -> Float (fromInteger n) F64 (_, (rep, n)) -> Int rep n suf - + -- | Given a string of characters read from a Rust source, extract the next underlying char taking -- into account escapes and unicode. unescapeChar :: Bool -- ^ multi-line strings allowed @@ -56,17 +56,14 @@ unescapeChar multiline ('\\':c:cs) = case c of 'X' -> do (h,cs') <- readHex 2 cs; pure (chr h, cs') 'U' -> do (h,cs') <- readHex 8 cs; pure (chr h, cs') 'u' -> case cs of - '{':x1:'}':cs' -> do (h,_) <- readHex 1 [x1]; pure (chr h, cs') - '{':x1:x2:'}':cs' -> do (h,_) <- readHex 2 [x1,x2]; pure (chr h, cs') - '{':x1:x2:x3:'}':cs' -> do (h,_) <- readHex 3 [x1,x2,x3]; pure (chr h, cs') - '{':x1:x2:x3:x4:'}':cs' -> do (h,_) <- readHex 4 [x1,x2,x3,x4]; pure (chr h, cs') - '{':x1:x2:x3:x4:x5:'}':cs' -> do (h,_) <- readHex 5 [x1,x2,x3,x4,x5]; pure (chr h, cs') - '{':x1:x2:x3:x4:x5:x6:'}':cs' -> do (h,_) <- readHex 6 [x1,x2,x3,x4,x5,x6]; pure (chr h, cs') - _ -> do (h,cs') <- readHex 4 cs; pure (chr h, cs') + '{':rest | (xs, '}':cs') <- span (/= '}') rest + , xs' <- filter (/= '_') xs + -> do (h, _) <- readHex (length xs') xs'; pure (chr h, cs') + _ -> do (h,cs') <- readHex 4 cs; pure (chr h, cs') '\n' | multiline -> unescapeChar multiline $ dropWhile isSpace cs _ -> error "unescape char: bad escape sequence" unescapeChar _ (c:cs) = Just (c, cs) -unescapeChar _ [] = fail "unescape char: empty string" +unescapeChar _ [] = Nothing -- unescape char: empty string -- | Given a string of characters read from a Rust source, extract the next underlying byte taking -- into account escapes. @@ -86,13 +83,13 @@ unescapeByte multiline ('\\':c:cs) = case c of '\n' | multiline -> unescapeByte multiline $ dropWhile isSpace cs _ -> error "unescape byte: bad escape sequence" unescapeByte _ (c:cs) = Just (toEnum $ fromEnum c, cs) -unescapeByte _ [] = fail "unescape byte: empty string" +unescapeByte _ [] = Nothing -- unescape byte: empty string -- | Given a string Rust representation of a character, parse it into a character unescapeChar' :: String -> Char unescapeChar' s = case unescapeChar False s of Just (c, "") -> c - _ -> error "unescape char: bad character literal" + _ -> error $ "unescape char: bad character literal " ++ s -- | Given a string Rust representation of a byte, parse it into a byte unescapeByte' :: String -> Word8 diff --git a/src/Language/Rust/Parser/ParseMonad.hs b/src/Language/Rust/Parser/ParseMonad.hs index 40f6d11..4ee8860 100644 --- a/src/Language/Rust/Parser/ParseMonad.hs +++ b/src/Language/Rust/Parser/ParseMonad.hs @@ -1,13 +1,13 @@ {-| Module : Language.Rust.Parser.ParseMonad Description : Parsing monad for lexer/parser -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental Portability : GHC -Both the lexer and the parser run inside of the 'P' monad. As detailed in the section on +Both the lexer and the parser run inside of the 'P' monad. As detailed in the section on on [threaded-lexers](https://www.haskell.org/happy/doc/html/sec-monads.html#sec-lexers) in Happy's instruction manual, the benefits of this are that: @@ -126,15 +126,15 @@ swapToken t = P $ \ !s@PState{ swapFunction = f } pOk _ -> pOk (f $! t) s -- | Extract the state stored in the parser. getPState :: P PState -getPState = P $ \ !s pOk _ -> pOk s s +getPState = P $ \ !s pOk _ -> pOk s s -- | Update the state stored in the parser. setPState :: PState -> P () -setPState s = P $ \ _ pOk _ -> pOk () s +setPState s = P $ \ _ pOk _ -> pOk () s -- | Modify the state stored in the parser. modifyPState :: (PState -> PState) -> P () -modifyPState f = P $ \ !s pOk _ -> pOk () (f $! s) +modifyPState f = P $ \ !s pOk _ -> pOk () (f $! s) -- | Retrieve the current position of the parser. getPosition :: P Position @@ -146,7 +146,7 @@ setPosition pos = modifyPState $ \ s -> s{ curPos = pos } -- | Retrieve the current 'InputStream' of the parser. getInput :: P InputStream -getInput = curInput <$> getPState +getInput = curInput <$> getPState -- | Update the current 'InputStream' of the parser. setInput :: InputStream -> P () diff --git a/src/Language/Rust/Parser/Reversed.hs b/src/Language/Rust/Parser/Reversed.hs index 2c14511..5c79209 100644 --- a/src/Language/Rust/Parser/Reversed.hs +++ b/src/Language/Rust/Parser/Reversed.hs @@ -1,21 +1,20 @@ {-| Module : Language.Rust.Parser.Reversed Description : Parsing literals -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental Portability : GHC -Datatypes wrapping lists and non-empty lists designed for fast append (as opposed to prepend) +Datatypes wrapping lists and non-empty lists designed for fast append (as opposed to prepend) along with the usual class instances. -} -{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} -#if __GLASGOW_HASKELL__ < 800 -{-# LANGUAGE FlexibleContexts #-} -#endif + +-- my `Monoid` instance is not canonical, but it wouldn't compile on GHC<=8.2 if it was +{-# OPTIONS_GHC -Wno-compat #-} module Language.Rust.Parser.Reversed ( Reversed(..), diff --git a/src/Language/Rust/Pretty.hs b/src/Language/Rust/Pretty.hs index accb0fb..3c272a7 100644 --- a/src/Language/Rust/Pretty.hs +++ b/src/Language/Rust/Pretty.hs @@ -1,20 +1,20 @@ {-| Module : Language.Rust.Pretty Description : Pretty printing -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental Portability : portable -This module provides functions for turning ASTs into values of type 'Doc'. These values can then be -rendered into concrete string types using functions from the @prettyprinter@ package. This has some -advantages over printing plain old strings: +This module provides functions for turning ASTs into values of type 'Language.Rust.Pretty.Doc'. +These values can then be rendered into concrete string types using functions from the +@prettyprinter@ package. This has some advantages over printing plain old strings: * /Backend independent/: you can use a variety of existing backends to efficiently render to all sorts of formats like 'Data.Text.Text', 'String', HTML, and terminal. - * /Dynamic layouts/: the AST will render differently depending on the desired page width + * /Dynamic layouts/: the AST will render differently depending on the desired page width >>> :set -XTypeApplications -XOverloadedStrings >>> import Language.Rust.Parser @@ -34,8 +34,8 @@ advantages over printing plain old strings: x - y + z } - * /Annotations/: Depending on the backend you are using to render the 'Doc', annotations can - determine colours, styling, links, etc. + * /Annotations/: Depending on the backend you are using to render the 'Language.Rust.Pretty.Doc', + annotations can determine colours, styling, links, etc. The examples below assume the following GHCi flag and import: @@ -56,7 +56,7 @@ module Language.Rust.Pretty ( Pretty(..), PrettyAnnotated(..), Doc, - + -- * Resolving Resolve(..), @@ -93,7 +93,7 @@ import Control.Exception ( throw ) -- Right (1 + 2) * 3 -- >>> pretty (Binary [] AddOp one bogusVar ()) -- Left (invalid AST (identifier `let' is a keyword)) --- +-- pretty :: (Resolve a, Pretty a) => a -> Either ResolveFail (Doc b) pretty = fmap prettyUnresolved . resolve @@ -172,10 +172,10 @@ instance Pretty (FieldPat a) where prettyUnresolved = PP.unAnnotate . pret instance Pretty (FnDecl a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (ForeignItem a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (Generics a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved +instance Pretty (GenericArg a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (ImplItem a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (Item a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (Lifetime a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved -instance Pretty (LifetimeDef a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (Lit a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (Mac a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (Nonterminal a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved @@ -187,8 +187,8 @@ instance Pretty (StructField a) where prettyUnresolved = PP.unAnnotate . pret instance Pretty (TraitItem a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (TraitRef a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (Ty a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved -instance Pretty (TyParam a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved -instance Pretty (TyParamBound a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved +instance Pretty (GenericParam a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved +instance Pretty (GenericBound a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (Variant a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (UseTree a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved instance Pretty (Visibility a) where prettyUnresolved = PP.unAnnotate . prettyAnnUnresolved @@ -199,8 +199,8 @@ instance Pretty Span where prettyUnresolved = PP.pretty . prettySp -- | Similar to 'Pretty', but for types which are parametrized over an annotation type. class PrettyAnnotated p where - -- | Pretty print the given value without resolving it, adding annotations in the 'Doc' whenever - -- possible. + -- | Pretty print the given value without resolving it, adding annotations in the + -- 'Language.Rust.Pretty.Doc' whenever possible. prettyAnnUnresolved :: p a -> Doc a -- | This instance prints attributes inline @@ -213,10 +213,10 @@ instance PrettyAnnotated FieldPat where prettyAnnUnresolved = printFieldPa instance PrettyAnnotated FnDecl where prettyAnnUnresolved = printFnArgsAndRet instance PrettyAnnotated ForeignItem where prettyAnnUnresolved = printForeignItem instance PrettyAnnotated Generics where prettyAnnUnresolved = printGenerics +instance PrettyAnnotated GenericArg where prettyAnnUnresolved = printGenericArg instance PrettyAnnotated ImplItem where prettyAnnUnresolved = printImplItem instance PrettyAnnotated Item where prettyAnnUnresolved = printItem instance PrettyAnnotated Lifetime where prettyAnnUnresolved = printLifetime -instance PrettyAnnotated LifetimeDef where prettyAnnUnresolved = printLifetimeDef instance PrettyAnnotated Lit where prettyAnnUnresolved = printLit instance PrettyAnnotated Mac where prettyAnnUnresolved = printMac Paren instance PrettyAnnotated Nonterminal where prettyAnnUnresolved = printNonterminal @@ -228,8 +228,8 @@ instance PrettyAnnotated StructField where prettyAnnUnresolved = printStructF instance PrettyAnnotated TraitItem where prettyAnnUnresolved = printTraitItem instance PrettyAnnotated TraitRef where prettyAnnUnresolved = printTraitRef instance PrettyAnnotated Ty where prettyAnnUnresolved = printType -instance PrettyAnnotated TyParam where prettyAnnUnresolved = printTyParam -instance PrettyAnnotated TyParamBound where prettyAnnUnresolved = printBound +instance PrettyAnnotated GenericParam where prettyAnnUnresolved = printGenericParam +instance PrettyAnnotated GenericBound where prettyAnnUnresolved = printBound instance PrettyAnnotated Variant where prettyAnnUnresolved = printVariant instance PrettyAnnotated UseTree where prettyAnnUnresolved = printUseTree instance PrettyAnnotated Visibility where prettyAnnUnresolved = printVis diff --git a/src/Language/Rust/Pretty/Internal.hs b/src/Language/Rust/Pretty/Internal.hs index 1562b1a..641add4 100644 --- a/src/Language/Rust/Pretty/Internal.hs +++ b/src/Language/Rust/Pretty/Internal.hs @@ -1,15 +1,15 @@ {-| Module : Language.Rust.Pretty.Internal Description : Rust pretty printer -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental Portability : portable The pretty printing facilities in this file are re-exported to 'Language.Rust.Pretty' via the -'Pretty' and 'PrettyAnnotated' classes. There may be invariants in this module that are not properly -documented. +'Language.Rust.Pretty.Pretty' and 'Language.Rust.Pretty.PrettyAnnotated' classes. There may be +invariants in this module that are not properly documented. -} {-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-} {-# OPTIONS_HADDOCK hide, not-home #-} @@ -23,24 +23,24 @@ module Language.Rust.Pretty.Internal ( -- ** Top level printSourceFile, - + -- ** General printMutability, printUnsafety, printFnArgsAndRet, printIdent, - + -- ** Paths printPath, - + -- ** Attributes printAttr, - + -- ** Literals printLit, printLitSuffix, printLitTok, - + -- ** Expressions printExpr, printAbi, @@ -48,27 +48,27 @@ module Language.Rust.Pretty.Internal ( printBinOp, printField, printRangeLimits, - + -- ** Types and lifetimes printType, + printGenericArg, printGenerics, printLifetime, - printLifetimeDef, - printTyParam, + printGenericParam, printBound, printWhereClause, printWherePredicate, printPolyTraitRef, printTraitRef, - + -- ** Patterns printPat, printBindingMode, printFieldPat, - + -- ** Statements printStmt, - + -- ** Items printItem, printForeignItem, @@ -79,7 +79,7 @@ module Language.Rust.Pretty.Internal ( printVariant, printUseTree, printVis, - + -- ** Blocks printBlock, @@ -108,7 +108,6 @@ import Data.Text.Prettyprint.Doc hiding ( (<+>), hsep, indent, vsep ) import Data.Maybe ( maybeToList, fromMaybe ) import Data.Foldable ( toList ) import Data.List ( unfoldr ) -import qualified Data.List.NonEmpty as N -- | Print a source file printSourceFile :: SourceFile a -> Doc a @@ -139,15 +138,14 @@ printType (TupTy [elt] x) = annotate x (block Paren True "" mempty [ prin printType (TupTy elts x) = annotate x (block Paren True "," mempty (printType `map` elts)) printType (PathTy Nothing p x) = annotate x (printPath p False) printType (PathTy (Just q) p x) = annotate x (printQPath p q False) -printType (TraitObject bs x) = let prefix = if null (N.tail bs) then "dyn" else mempty - in annotate x (printBounds prefix (toList bs)) +printType (TraitObject bs x) = annotate x (printBounds "dyn" (toList bs)) printType (ImplTrait bs x) = annotate x (printBounds "impl" (toList bs)) printType (ParenTy ty x) = annotate x ("(" <> printType ty <> ")") printType (Typeof e x) = annotate x ("typeof" <> block Paren True mempty mempty [ printExpr e ]) printType (Infer x) = annotate x "_" printType (MacTy m x) = annotate x (printMac Bracket m) printType (BareFn u a l d x) = annotate x (printFormalLifetimeList l - <+> printFnHeaderInfo u NotConst a InheritedV + <+> printFnHeaderInfo u NotAsync NotConst a <> printFnArgsAndRet d) -- | Print a macro (@print_mac@) @@ -160,14 +158,14 @@ printSpaceBetween :: Bool -> Span -> Span -> Maybe (Doc a) printSpaceBetween spaceNeeded (Span _ (Position _ y1 x1)) (Span (Position _ y2 x2) _) | y2 == y1 && x2 > x1 = Just $ hcat (replicate (x2 - x1) space) | y2 > y1 = Just $ hcat (replicate (y2 - y1) line) <> column (\x1' -> hcat (replicate (x2 - x1') space)) - | spaceNeeded = Just space + | spaceNeeded = Just space | otherwise = Just mempty -printSpaceBetween _ _ _ = Nothing +printSpaceBetween _ _ _ = Nothing -- | Print a token tree (@print_tt@) printTt :: TokenTree -> Doc a printTt (Token _ t) = printToken t -printTt (Delimited _ d ts) = block d True mempty mempty [ printTokenStream ts ] +printTt (Delimited _ d ts) = block d True mempty mempty [ printTokenStream ts ] -- | Print a list of token trees, with the right amount of space between successive elements printTokenTrees :: [TokenTree] -> Doc a @@ -193,14 +191,14 @@ printTokenTrees (tt1:tt2:tts) = printTt tt1 <> sp <> printTokenTrees (tt2:tts) (Semicolon, _) -> space (_, OpenDelim Brace) -> space (CloseDelim Brace, _) -> space - (t1, t2) | t1 `elem` toksRequiringSp || t2 `elem` toksRequiringSp -> space + (t1, t2) | t1 `elem` toksRequiringSp || t2 `elem` toksRequiringSp -> space | otherwise -> if spNeeded then space else mempty -- List of tokens that want to have space on either side of them toksRequiringSp = [ Equal, GreaterEqual, GreaterGreaterEqual, EqualEqual, NotEqual, LessEqual, LessLessEqual, MinusEqual, AmpersandEqual, PipeEqual, PlusEqual, StarEqual, SlashEqual, CaretEqual, PercentEqual, RArrow, LArrow, FatArrow ] - + -- Use 'spPos' with 'spTok' as a fallback sp = fromMaybe spTok spPos @@ -284,10 +282,10 @@ printToken (Space Whitespace _) = " " printToken (Space Comment n) = "/*" <> printName n <> " */" printToken (Doc d Inner True) = "/*!" <> printName d <> "*/" printToken (Doc d Outer True) = "/**" <> printName d <> "*/" -printToken (Doc d Inner False) = "//!" <> printName d -printToken (Doc d Outer False) = "///" <> printName d +printToken (Doc d Inner False) = "//!" <> printName d <> hardline +printToken (Doc d Outer False) = "///" <> printName d <> hardline printToken Shebang = "#!" --- Macro related +-- Macro related printToken (Interpolated n) = unAnnotate (printNonterminal n) -- Other printToken t = error $ "printToken: " ++ show t @@ -339,6 +337,7 @@ printStmt (NoSemi expr x) = annotate x (printExprOuterAttrStyle expr False < requiresSemi Loop{} = False requiresSemi Match{} = False requiresSemi BlockExpr{} = False + requiresSemi Async{} = False requiresSemi _ = True printStmt (Semi expr x) = annotate x (printExprOuterAttrStyle expr False <> ";") printStmt (MacStmt m ms as x) = annotate x (printOuterAttrs as printMac delim m <> end) @@ -347,6 +346,7 @@ printStmt (MacStmt m ms as x) = annotate x (printOuterAttrs as printMac deli printStmt (Local p ty i as x) = annotate x (printOuterAttrs as <#> group ("let" <+> binding <+> initializer <> ";")) where binding = group (printPat p <> perhaps (\t -> ":" <#> indent n (printType t)) ty) initializer = perhaps (\e -> "=" <#> indent n (printExpr e)) i +printStmt (StandaloneSemi x) = annotate x ";" -- | Print an expression printExpr :: Expr a -> Doc a @@ -362,7 +362,6 @@ printExprOuterAttrStyle :: Expr a -> Bool -> Doc a printExprOuterAttrStyle expr isInline = glue (printEitherAttrs (expressionAttrs expr) Outer isInline) $ case expr of Box _ e x -> annotate x ("box" <+> printExpr e) - InPlace _ place e x -> annotate x (hsep [ printExpr place, "<-", printExpr e ]) Vec as exprs x -> annotate x (block Bracket True "," (printInnerAttrs as) (printExpr <$> exprs)) Call _ func [arg] x -> annotate x (printExpr func <> parens (printExpr arg)) Call _ func args x -> annotate x (printExpr func <> block Paren True "," mempty (printExpr <$> args)) @@ -376,17 +375,22 @@ printExprOuterAttrStyle expr isInline = glue (printEitherAttrs (expressionAttrs in annotate x (hsep [ f e, "as", printType ty ]) TypeAscription _ e ty x -> annotate x (printExpr e <> ":" <+> printType ty) If _ test blk els x -> annotate x (hsep [ "if", printExpr test, printBlock blk, printElse els ]) - IfLet _ pats e blk els x -> annotate x (hsep [ "if let", printPats pats, "=", printExpr e, printBlock blk, printElse els ]) + IfLet _ pats e blk els x -> annotate x (hsep [ "if let", printPat pats, "=", printExpr e, printBlock blk, printElse els ]) While as test blk lbl x -> annotate x (hsep [ printLbl lbl, "while", printExpr test, printBlockWithAttrs True blk as ]) - WhileLet as ps e blk lbl x -> annotate x (hsep [ printLbl lbl, "while let", printPats ps, "=", printExpr e, printBlockWithAttrs True blk as ]) + WhileLet as ps e blk lbl x -> annotate x (hsep [ printLbl lbl, "while let", printPat ps, "=", printExpr e, printBlockWithAttrs True blk as ]) ForLoop as pat e blk lbl x -> annotate x (hsep [ printLbl lbl, "for", printPat pat, "in", printExpr e, printBlockWithAttrs True blk as ]) Loop as blk lbl x -> annotate x (hsep [ printLbl lbl, "loop", printBlockWithAttrs True blk as ]) Match as e arms x -> annotate x (hsep [ "match", printExpr e, block Brace False "," (printInnerAttrs as) (printArm `map` arms) ]) - Closure _ s cap decl body x -> annotate x (hsep [ when (s == Immovable) "static" - , when (cap == Value) "move" + Closure _ c a s decl body x -> annotate x (hsep [ when (s == Immovable) "static" + , when (a == IsAsync) "async" + , when (c == Value) "move" , printFnBlockArgs decl <+> printExpr body]) - BlockExpr attrs blk x -> annotate x (printBlockWithAttrs True blk attrs) - Catch attrs blk x -> annotate x ("do catch" <+> printBlockWithAttrs True blk attrs) + BlockExpr attrs blk lbl x -> annotate x (hsep [ printLbl lbl, printBlockWithAttrs True blk attrs ]) + Async attrs cap blk x -> annotate x (hsep [ "async" + , when (cap == Value) "move" + , printBlockWithAttrs True blk attrs]) + TryBlock attrs blk x -> annotate x ("try" <+> printBlockWithAttrs True blk attrs) + Await{} -> chainedMethodCalls expr False id Assign _ lhs rhs x -> annotate x (hsep [ printExpr lhs, "=", printExpr rhs ]) AssignOp _ op lhs rhs x -> annotate x (hsep [ printExpr lhs, printBinOp op <> "=", printExpr rhs ]) FieldAccess{} -> chainedMethodCalls expr False id @@ -402,7 +406,7 @@ printExprOuterAttrStyle expr isInline = glue (printEitherAttrs (expressionAttrs Yield _ result x -> annotate x ("yield" <+> perhaps printExpr result) MacExpr _ m x -> annotate x (printMac Paren m) Struct as p fs Nothing x -> annotate x (printPath p True <+> block Brace True "," (printInnerAttrs as) (printField `map` fs)) - Struct as p fs (Just d) x -> let body = [ printField f <> "," | f <- fs ] ++ [ ".." <> printExpr d ] + Struct as p fs (Just d) x -> let body = [ printField f <> "," | f <- fs ] ++ [ ".." <> printExpr d ] in annotate x (printPath p True <+> block Brace True mempty (printInnerAttrs as) body) Repeat attrs e cnt x -> annotate x (brackets (printInnerAttrs attrs <+> printExpr e <> ";" <+> printExpr cnt)) ParenExpr attrs e x -> annotate x (parens (printInnerAttrs attrs <+> printExpr e)) @@ -429,16 +433,18 @@ printExprOuterAttrStyle expr isInline = glue (printEitherAttrs (expressionAttrs -- to prevent them from looking like a float literal) -> (Doc a -> Doc a) -- ^ suffix to the expression -> Doc a - chainedMethodCalls (MethodCall _ s i ts' as x) _ fdoc - = let tys = perhaps (\ts -> "::<" <> commas ts printType <> ">") ts' + chainedMethodCalls (MethodCall _ s (PathSegment i ts' y) as x) _ fdoc + = let tys = perhaps (printGenericArgs True) ts' as' = case as of [a] -> parens (printExpr a) _ -> block Paren True "," mempty (printExpr <$> as) - in chainedMethodCalls s False (annotate x . (<##> fdoc (indent n (hcat [ ".", printIdent i, tys, as' ])))) + in chainedMethodCalls s False (annotate x . (<##> fdoc (indent n (hcat [ ".", annotate y (printIdent i <> tys), as' ])))) chainedMethodCalls (FieldAccess _ s i x) _ fdoc = chainedMethodCalls s False (annotate x . (<##> fdoc (indent n (hcat [ ".", printIdent i ])))) chainedMethodCalls (Try _ s x) _ fdoc = chainedMethodCalls s False (annotate x . (<> fdoc "?")) + chainedMethodCalls (Await _ s x) _ fdoc + = chainedMethodCalls s False (annotate x . (<##> fdoc (indent n (hcat [ ".", "await" ])))) chainedMethodCalls (Index _ s i x) _ fdoc = chainedMethodCalls s False (annotate x . (<> fdoc ("[" <> block NoDelim True mempty mempty [printExpr i] <> "]"))) chainedMethodCalls (TupField _ s i x) t fdoc @@ -452,10 +458,9 @@ printStr sty str = unAnnotate (printLit (Str str sty Unsuffixed ())) -- | Extract from an expression its attributes expressionAttrs :: Expr a -> [Attribute a] expressionAttrs (Box as _ _) = as -expressionAttrs (InPlace as _ _ _) = as expressionAttrs (Vec as _ _) = as expressionAttrs (Call as _ _ _) = as -expressionAttrs (MethodCall as _ _ _ _ _) = as +expressionAttrs (MethodCall as _ _ _ _) = as expressionAttrs (TupExpr as _ _) = as expressionAttrs (Binary as _ _ _ _) = as expressionAttrs (Unary as _ _ _) = as @@ -469,9 +474,11 @@ expressionAttrs (WhileLet as _ _ _ _ _) = as expressionAttrs (ForLoop as _ _ _ _ _) = as expressionAttrs (Loop as _ _ _) = as expressionAttrs (Match as _ _ _) = as -expressionAttrs (Closure as _ _ _ _ _) = as -expressionAttrs (BlockExpr as _ _) = as -expressionAttrs (Catch as _ _) = as +expressionAttrs (Closure as _ _ _ _ _ _) = as +expressionAttrs (BlockExpr as _ _ _) = as +expressionAttrs (TryBlock as _ _) = as +expressionAttrs (Async as _ _ _) = as +expressionAttrs (Await as _ _) = as expressionAttrs (Assign as _ _ _) = as expressionAttrs (AssignOp as _ _ _ _) = as expressionAttrs (FieldAccess as _ _ _) = as @@ -492,8 +499,10 @@ expressionAttrs (Yield as _ _) = as -- | Print a field printField :: Field a -> Doc a -printField (Field ident Nothing x) = annotate x (printIdent ident) -printField (Field ident (Just expr) x) = annotate x (printIdent ident <>":" <+> printExpr expr) +printField (Field ident Nothing as x) = + annotate x (printOuterAttrs as printIdent ident) +printField (Field ident (Just expr) as x) = + annotate x (printOuterAttrs as printIdent ident <> ":" <+> printExpr expr) -- | Print range limits printRangeLimits :: RangeLimits -> Doc a @@ -508,15 +517,12 @@ printFnBlockArgs (FnDecl args ret _ x) = annotate x ("|" <> args' <> "|" <+> ret -- | Print the arm of a match expression (@print_arm@) printArm :: Arm a -> Doc a -printArm (Arm as pats guard body x) = annotate x $ printOuterAttrs as - printPats pats +printArm (Arm as pat guard body x) = annotate x $ printOuterAttrs as + printPat pat <+> perhaps (\e -> "if" <+> printExpr e) guard <+> "=>" <+> printExpr body -printPats :: Foldable f => f (Pat a) -> Doc a -printPats pats = group (foldr1 (\a b -> a <+> "|" <#> b) (printPat `map` toList pats)) - -- | Print a block printBlock :: Block a -> Doc a printBlock blk = printBlockWithAttrs True blk [] @@ -529,7 +535,7 @@ printBlockWithAttrs b (Block stmts rules x) as = annotate x (printUnsafety rules | otherwise = body ++ [ lastStmt ] body = printStmt `map` Prelude.init stmts - + lastStmt = case last stmts of NoSemi expr _ -> printExprOuterAttrStyle expr False stmt -> printStmt stmt @@ -537,12 +543,12 @@ printBlockWithAttrs b (Block stmts rules x) as = annotate x (printUnsafety rules -- | Print an @else@ expression (@print_else@) printElse :: Maybe (Expr a) -> Doc a printElse Nothing = mempty -printElse (Just (If _ e t s x)) = annotate x (hsep [ "else if", printExpr e, printBlock t, printElse s ]) -printElse (Just (IfLet _ p e t s x)) = annotate x (hsep [ "else if let", printPats p, "=", printExpr e, printBlock t, printElse s ]) -printElse (Just (BlockExpr _ blk x)) = annotate x (hsep [ "else", printBlock blk ]) +printElse (Just (If _ e t s x)) = annotate x (hsep [ "else if", printExpr e, printBlock t, printElse s ]) +printElse (Just (IfLet _ p e t s x)) = annotate x (hsep [ "else if let", printPat p, "=", printExpr e, printBlock t, printElse s ]) +printElse (Just (BlockExpr _ blk _ x)) = annotate x (hsep [ "else", printBlock blk ]) printElse _ = error "printElse saw `if` with a weird alternative" --- | Print a binary operator +-- | Print a binary operator printBinOp :: BinOp -> Doc a printBinOp AddOp = "+" printBinOp SubOp = "-" @@ -567,7 +573,7 @@ printBinOp GtOp = ">" printUnOp :: UnOp -> Doc a printUnOp Deref = "*" printUnOp Not = "!" -printUnOp Neg = "-" +printUnOp Neg = "-" -- | Print inner attributes (@print_inner_attributes@ or @print_inner_attributes_inline@ -- or @print_inner_attributes_nodbreak@ - distinction has to be made at callsite @@ -601,7 +607,7 @@ printAttr (SugaredDoc Outer False c x) _ = annotate x (flatAlt ("///" <> pretty printCookedIdent :: Ident -> Doc a printCookedIdent ident@(Ident str raw _) | '-' `elem` str && not raw = printStr Cooked str - | otherwise = printIdent ident + | otherwise = printIdent ident -- | Print an item (@print_item@) @@ -618,8 +624,8 @@ printItem (Static as vis ident ty m e x) = annotate x $ align $ printOuterAttrs printItem (ConstItem as vis ident t e x) = annotate x $ align $ printOuterAttrs as <#> hsep [ printVis vis, "const", printIdent ident <> ":", printType t, "=", printExpr e <> ";" ] -printItem (Fn as vis ident d s c a t b x) = annotate x $ align $ printOuterAttrs as <#> - printFn d s c a (Just ident) t vis (Just (b, as)) +printItem (Fn as vis ident d (FnHeader s async c a y) t b x) = annotate x $ align $ printOuterAttrs as <#> + printFn d s async c a (Just y) (Just ident) t vis (Just (b, as)) printItem (Mod as vis ident items x) = annotate x $ align $ printOuterAttrs as <#> hsep [ printVis vis, "mod", printMod ident items as ] @@ -643,7 +649,7 @@ printItem (StructItem as vis ident s g x) = annotate x $ align $ printOuterAttrs printItem (Union as vis ident s g x) = annotate x $ align $ printOuterAttrs as <#> hsep [ printVis vis, "union", printStruct s g ident True True ] -printItem (Trait as vis ident a u g tys i x) = annotate x $ align $ printOuterAttrs as <#> +printItem (Trait as vis ident a u g tys i x) = annotate x $ align $ printOuterAttrs as <#> let leading = hsep [ printVis vis, printUnsafety u, when a "auto", "trait" , printIdent ident <> printGenerics g <> printBounds ":" tys ] @@ -655,10 +661,12 @@ printItem (Trait as vis ident a u g tys i x) = annotate x $ align $ printOuterAt printItem (TraitAlias as vis ident g bds x) = annotate x $ align $ printOuterAttrs as <#> let leading = printVis vis <+> "trait" <+> printIdent ident <> printGenerics g - in group (leading <#> indent n (printBounds "=" (toList bds)) <> ";") + lagging = indent n (if null bds then "=" else printBounds "=" bds) <+> wc <> ";" + wc = printWhereClause True (whereClause g) + in group (leading <#> lagging) -printItem (Impl as vis d u p g t ty i x) = annotate x $ align $ printOuterAttrs as <#> - let generics = case g of { Generics [] [] _ _ -> mempty; _ -> printGenerics g } +printItem (Impl as vis d u p g t ty i x) = annotate x $ align $ printOuterAttrs as <#> + let generics = case g of { Generics [] _ _ -> mempty; _ -> printGenerics g } traitref = perhaps (\t' -> printPolarity p <> printTraitRef t' <+> "for") t leading = hsep [ printVis vis, printDef d, printUnsafety u , "impl" <> generics, traitref, printType ty @@ -669,11 +677,10 @@ printItem (Impl as vis d u p g t ty i x) = annotate x $ align $ printOuterAttrs (\w -> vsep [leading, w, lagging]) wc -printItem (MacItem as i (Mac p ts y) x) = annotate x $ annotate y $ align $ printOuterAttrs as <#> - (printPath p True <> "!" <+> perhaps printIdent i <+> block Brace True mempty mempty [ printTokenStream ts ]) +printItem (MacItem as m x) = annotate x $ printOuterAttrs as <#> printMac Brace m -printItem (MacroDef as i ts x) = annotate x $ align $ printOuterAttrs as <#> - ("macro_rules" <> "!" <+> printIdent i <+> block Brace True mempty mempty [ printTokenStream ts ]) +printItem (MacroDef as v i ts x) = annotate x $ align $ printOuterAttrs as <#> + (printVis v <+> "macro" <+> printIdent i <+> block Brace True mempty mempty [ printTokenStream ts ]) -- | Print a trait item (@print_trait_item@) @@ -684,20 +691,21 @@ printTraitItem (TypeT as ident bounds ty x) = annotate x $ printOuterAttrs as <# printTraitItem (MacroT as m x) = annotate x $ printOuterAttrs as <#> printMac Paren m <> ";" -- | Print type parameter bounds with the given prefix, but only if there are any bounds (@print_bounds@) -printBounds :: Doc a -> [TyParamBound a] -> Doc a +printBounds :: Doc a -> [GenericBound a] -> Doc a printBounds _ [] = mempty +printBounds prefix [b] = group (prefix <#> ungroup (block NoDelim False mempty mempty [printBound b])) printBounds prefix bs = group (prefix <#> ungroup (block NoDelim False " +" mempty (printBound `map` bs))) -- | Print a type parameter bound -printBound :: TyParamBound a -> Doc a -printBound (RegionTyParamBound lt x) = annotate x $ printLifetime lt -printBound (TraitTyParamBound tref modi x) = annotate x $ when (modi == Maybe) "?" <> printPolyTraitRef tref +printBound :: GenericBound a -> Doc a +printBound (OutlivesBound lt x) = annotate x $ printLifetime lt +printBound (TraitBound tref modi x) = annotate x $ when (modi == Maybe) "?" <> printPolyTraitRef tref -- | Print the formal lifetime list (@print_formal_lifetime_list@) -printFormalLifetimeList :: [LifetimeDef a] -> Doc a +printFormalLifetimeList :: [GenericParam a] -> Doc a printFormalLifetimeList [] = mempty printFormalLifetimeList defs = "for" <> angles (align (fillSep (punctuate "," (printDef `map` defs)))) - where printDef (LifetimeDef as lt bds x) = annotate x (printOuterAttrs as <+> flatten (printLifetimeBounds lt bds)) + where printDef = flatten . printGenericParam -- | Print an impl item (@print_impl_item@) printImplItem :: ImplItem a -> Doc a @@ -713,10 +721,10 @@ printImplItem (MacroI as def mac x) = annotate x $ printOuterAttrs as <#> -- | Print defaultness (@Defaultness@) printDef :: Defaultness -> Doc a printDef Default = "default" -printDef Final = mempty +printDef Final = mempty -- | Print an associated type (@printAssociatedType@) -printAssociatedType :: Ident -> Maybe [TyParamBound a] -> Maybe (Ty a) -> Doc a +printAssociatedType :: Ident -> Maybe [GenericBound a] -> Maybe (Ty a) -> Doc a printAssociatedType ident bounds_m ty_m = "type" <+> (printIdent ident <> perhaps (printBounds ":") bounds_m) <+> perhaps (\ty -> "=" <+> printType ty) ty_m @@ -724,8 +732,8 @@ printAssociatedType ident bounds_m ty_m = "type" <+> (printIdent ident -- | Print a method signature (@print_method_sig@) printMethodSig :: Ident -> Generics a -> MethodSig a -> Visibility a -> Maybe (Block a, [Attribute a]) -> Doc a -printMethodSig ident generics (MethodSig unsafety constness abi decl) - = printFn decl unsafety constness abi (Just ident) generics +printMethodSig ident generics (MethodSig (FnHeader unsafety async constness abi y) decl) + = printFn decl unsafety async constness abi (Just y) (Just ident) generics -- | Print an associated constant (@print_associated_const@) printAssociatedConst :: Ident -> Ty a -> Maybe (Expr a) -> Visibility a -> Doc a @@ -751,21 +759,23 @@ printVis InheritedV = mempty -- | Print a foreign item (@print_foreign_item@) printForeignItem :: ForeignItem a -> Doc a printForeignItem (ForeignFn attrs vis ident decl generics x) = annotate x $ - printOuterAttrs attrs <#> printFn decl Normal NotConst Rust (Just ident) generics vis Nothing + printOuterAttrs attrs <#> printFn decl Normal NotAsync NotConst Rust Nothing (Just ident) generics vis Nothing printForeignItem (ForeignStatic attrs vis ident ty mut x) = annotate x $ printOuterAttrs attrs <#> printVis vis <+> "static" <+> printMutability mut <+> printIdent ident <> ":" <+> printType ty <> ";" printForeignItem (ForeignTy attrs vis ident x) = annotate x $ printOuterAttrs attrs <#> printVis vis <+> "type" <+> printIdent ident <> ";" +printForeignItem (ForeignMac attrs mac x) = annotate x $ + printOuterAttrs attrs <#> printMac Brace mac -- | Print a struct definition (@print_struct@) printStruct :: VariantData a -> Generics a -> Ident -> Bool -> Bool -> Doc a printStruct structDef generics ident printFinalizer annotateGenerics = printIdent ident <> gen - <> case (structDef, whereClause generics) of + <> case (structDef, whereClause generics) of (StructD fields x, WhereClause [] _) -> annotate x $ space <> block Brace False "," mempty (printStructField `map` fields) (StructD fields x, wc) -> annotate x $ line <> printWhereClause True wc <#> block Brace False "," mempty (printStructField `map` fields) - (TupleD fields x, WhereClause [] _) -> annotate x $ block Paren True "," mempty (printStructField `map` fields) <> when printFinalizer ";" - (TupleD fields x, wc) -> annotate x $ block Paren True "," mempty (printStructField `map` fields) <#> printWhereClause (not printFinalizer) wc <> when printFinalizer ";" + (TupleD fields x, WhereClause [] _) -> annotate x $ block Paren True "," mempty (printStructField `map` fields) <> when printFinalizer ";" + (TupleD fields x, wc) -> annotate x $ block Paren True "," mempty (printStructField `map` fields) <#> printWhereClause (not printFinalizer) wc <> when printFinalizer ";" (UnitD x, WhereClause [] _) -> annotate x $ when printFinalizer ";" (UnitD x, wc) -> annotate x $ line <> printWhereClause (not printFinalizer) wc <> when printFinalizer ";" where gen = if annotateGenerics then printGenerics generics else unAnnotate (printGenerics generics) @@ -791,11 +801,11 @@ printEnumDef variants generics ident vis = -- | Print a variant (@print_variant@) printVariant :: Variant a -> Doc a printVariant (Variant i _ _data e x) = annotate x (body <+> disc) - where body = printStruct _data (Generics [] [] (WhereClause [] undefined) undefined) i False False + where body = printStruct _data (Generics [] (WhereClause [] undefined) undefined) i False False disc = perhaps (\e' -> "=" <+> printExpr e') e --- | Print a where clause (@print_where_clause@). The 'Bool' argument indicates whether to have a --- trailing comma or not. +-- | Print a where clause (@print_where_clause@). The 'Prelude.Bool' argument indicates whether to +-- have a trailing comma or not. printWhereClause :: Bool -> WhereClause a -> Doc a printWhereClause trailing (WhereClause predicates x) | null predicates = mempty @@ -804,14 +814,26 @@ printWhereClause trailing (WhereClause predicates x) -- | Print a where clause predicate printWherePredicate :: WherePredicate a -> Doc a -printWherePredicate (BoundPredicate blt ty bds y) = annotate y (printFormalLifetimeList blt <+> printType ty <> printBounds ":" bds) +printWherePredicate (BoundPredicate blt ty bds y) = annotate y (printFormalLifetimeList blt <+> printType ty <> ":" <+> printBounds mempty bds) printWherePredicate (RegionPredicate lt bds y) = annotate y (printLifetimeBounds lt bds) printWherePredicate (EqPredicate lhs rhs y) = annotate y (printType lhs <+> "=" <+> printType rhs) -- | Print a function (@print_fn@) -printFn :: FnDecl a -> Unsafety -> Constness -> Abi -> Maybe Ident -> Generics a -> Visibility a -> Maybe (Block a, [Attribute a]) -> Doc a -printFn decl unsafety constness abi name generics vis blkAttrs = - printFnHeaderInfo unsafety constness abi vis +printFn + :: FnDecl a + -> Unsafety + -> IsAsync + -> Constness + -> Abi + -> Maybe a -- ^ we might have an annotation if the header info came from 'FnHeader' + -> Maybe Ident + -> Generics a + -> Visibility a + -> Maybe (Block a, [Attribute a]) + -> Doc a +printFn decl unsafety async constness abi y name generics vis blkAttrs = + printVis vis + <+> (maybe id annotate y) (printFnHeaderInfo unsafety async constness abi) <+> perhaps printIdent name <> printGenerics generics <> printFnArgsAndRet decl @@ -831,29 +853,26 @@ printFnArgsAndRet (FnDecl args ret var x) | otherwise = annotate x (block Paren True "," mempty [ printArg a False | a <- args ] <+> ret') where ret' = perhaps (\t -> "->" <+> printType t) ret + -- | Print an argument (@print_arg@) printArg :: Arg a -> Bool -> Doc a -printArg (Arg (Just pat) (Infer x') x) True = annotate x $ annotate x' (printPat pat) -printArg (Arg Nothing ty x) _ = annotate x (printType ty) -printArg (Arg (Just pat) ty x) _ = annotate x (printPat pat <> ":" <+> printType ty) -printArg (SelfValue mut x) _ = annotate x (printMutability mut <+> "self") -printArg (SelfRegion lt mut x) _ = annotate x ("&" <> hsep [perhaps printLifetime lt, printMutability mut, "self"]) -printArg (SelfExplicit ty mut x) _ = annotate x (printMutability mut <+> "self" <> ":" <+> printType ty) +printArg (Arg as (Just pat) (Infer x') x) True = annotate x $ printOuterAttrs as <+> annotate x' (printPat pat) +printArg (Arg as Nothing ty x) _ = annotate x (printOuterAttrs as <+> printType ty) +printArg (Arg as (Just pat) ty x) _ = annotate x (printOuterAttrs as <+> printPat pat <> ":" <+> printType ty) +printArg (SelfValue as mut x) _ = annotate x (printOuterAttrs as <+> printMutability mut <+> "self") +printArg (SelfRegion as lt mut x) _ = annotate x (printOuterAttrs as <+> "&" <> hsep [perhaps printLifetime lt, printMutability mut, "self"]) +printArg (SelfExplicit as ty mut x) _ = annotate x (printOuterAttrs as <+> printMutability mut <+> "self" <> ":" <+> printType ty) -- | Print a lifetime (@print_lifetime@) printLifetime :: Lifetime a -> Doc a printLifetime (Lifetime n x) = annotate x ("'" <> printName n) --- | Print a lifetime definition -printLifetimeDef :: LifetimeDef a -> Doc a -printLifetimeDef (LifetimeDef as lt bds x) = annotate x (printOuterAttrs as <+> printLifetimeBounds lt bds) - -- | Print mutability (@print_mutability@) printMutability :: Mutability -> Doc a printMutability Mutable = "mut" printMutability Immutable = mempty --- | Like 'printMutability', but prints @const@ in the immutable case +-- | Like 'printMutability', but prints @const@ in the immutable case printFullMutability :: Mutability -> Doc a printFullMutability Mutable = "mut" printFullMutability Immutable = "const" @@ -861,38 +880,31 @@ printFullMutability Immutable = "const" -- | Print a pattern (@print_pat@) printPat :: Pat a -> Doc a printPat (WildP x) = annotate x "_" +printPat (RestP x) = annotate x ".." printPat (IdentP bm p s x) = annotate x (printBindingMode bm <+> printIdent p <+> perhaps (\p' -> "@" <+> printPat p') s) printPat (StructP p fs False x) = annotate x (printPath p True <+> block Brace True "," mempty (printFieldPat `map` fs)) printPat (StructP p fs True x) = annotate x (printPath p True <+> block Brace True mempty mempty ([ printFieldPat f <> "," | f <- fs ] ++ [ ".." ])) -printPat (TupleStructP p es Nothing x) = annotate x (printPath p True <> "(" <> commas es printPat <> ")") -printPat (TupleStructP p es (Just d) x) = let (before,after) = splitAt d es - in annotate x (printPath p True <> "(" <> commas before printPat <> when (d /= 0) "," - <+> ".." <> when (d /= length es) ("," <+> commas after printPat) <> ")") +printPat (TupleStructP p es x) = annotate x (printPath p True <> "(" <> commas es printPat <> ")") printPat (PathP Nothing path x) = annotate x (printPath path True) printPat (PathP (Just qself) path x) = annotate x (printQPath path qself True) -printPat (TupleP [elt] Nothing x) = annotate x ("(" <> printPat elt <> ",)") -printPat (TupleP elts Nothing x) = annotate x ("(" <> commas elts printPat <> ")") -printPat (TupleP elts (Just ddpos) _) = let (before,after) = splitAt ddpos elts - in "(" <> commas before printPat <> unless (null before) "," - <+> ".." <> unless (null after) ("," <+> commas after printPat) <> ")" +printPat (TupleP [RestP y] x) = annotate x ("(" <> annotate y ".." <> ")") +printPat (TupleP [elt] x) = annotate x ("(" <> printPat elt <> ",)") +printPat (TupleP elts x) = annotate x ("(" <> commas elts printPat <> ")") +printPat (OrP ps x) = annotate x (group (foldr1 (\a b -> a <+> "|" <#> b) (printPat `map` toList ps))) printPat (BoxP inner x) = annotate x ("box" <+> printPat inner) printPat (RefP inner mutbl x) = annotate x ("&" <> printMutability mutbl <+> printPat inner) printPat (LitP expr x) = annotate x (printExpr expr) -printPat (RangeP lo hi x) = annotate x (printExpr lo <+> "..=" <+> printExpr hi) -printPat (SliceP pb Nothing pa x) = annotate x ("[" <> commas (pb ++ pa) printPat <> "]") -printPat (SliceP pb (Just ps) pa x) = annotate x ("[" <> commas pb printPat <> ps' <+> commas pa printPat <> "]") - where ps' = hcat [ unless (null pb) "," - , space - , case ps of WildP{} -> mempty - _ -> printPat ps - , ".." - , unless (null pa) "," - ] +printPat (RangeP lo hi rl x) = annotate x (printExpr lo <+> printRangeLimits rl <+> printExpr hi) +printPat (SliceP ps x) = annotate x ("[" <> commas ps printPat <> "]") printPat (MacP m x) = annotate x (printMac Paren m) +printPat (ParenP p x) = annotate x ("(" <> printPat p <> ")") -- | Print a field pattern printFieldPat :: FieldPat a -> Doc a -printFieldPat (FieldPat i p x) = annotate x (perhaps (\i -> printIdent i <> ":") i <+> printPat p) +printFieldPat (FieldPat i p as x) = annotate x (attrs i' <+> printPat p) + where + i' = perhaps (\i -> printIdent i <> ":") i + attrs = printOuterAttrs as -- | Print a binding mode printBindingMode :: BindingMode -> Doc a @@ -901,9 +913,12 @@ printBindingMode (ByValue Immutable) = mempty printBindingMode (ByValue Mutable) = "mut" -- | Print the prefix of a function - all the stuff up to and including @fn@ (@print_fn_header_info@) -printFnHeaderInfo :: Unsafety -> Constness -> Abi -> Visibility a -> Doc a -printFnHeaderInfo u c a v = hsep [ printVis v, case c of { Const -> "const"; _ -> mempty } - , printUnsafety u, printAbi a, "fn" ] +printFnHeaderInfo :: Unsafety -> IsAsync -> Constness -> Abi -> Doc a +printFnHeaderInfo unsafe async constness abi = hsep [ when (constness == Const) "const" + , when (async == IsAsync) "async" + , printUnsafety unsafe + , printAbi abi + , "fn" ] -- | Print the ABI printAbi :: Abi -> Doc a @@ -914,6 +929,7 @@ printAbi abi = "extern" <+> "\"" <> root abi <> "\"" root Cdecl = "cdecl" root Stdcall = "stdcall" root Fastcall = "fastcall" + root Thiscall = "thiscall" root Vectorcall = "vectorcall" root Aapcs = "aapcs" root Win64 = "win64" @@ -921,6 +937,7 @@ printAbi abi = "extern" <+> "\"" <> root abi <> "\"" root PtxKernel = "ptx-kernel" root Msp430Interrupt = "msp430-interrupt" root X86Interrupt = "x86-interrupt" + root AmdGpuKernel = "amd-gpu-kernel" root Rust = "Rust" root C = "C" root System = "system" @@ -929,7 +946,7 @@ printAbi abi = "extern" <+> "\"" <> root abi <> "\"" root PlatformIntrinsic = "platform-intrinsic" root Unadjusted = "unadjusted" - + -- | Print the interior of a module given the list of items and attributes in it (@print_mod@) printMod :: Ident -> Maybe [Item a] -> [Attribute a] -> Doc a printMod i (Just items) attrs = printIdent i <+> block Brace False mempty (printInnerAttrs attrs) (punctuate line' (printItem `map` items)) @@ -943,11 +960,10 @@ printForeignMod items attrs = block Brace False mempty (printInnerAttrs attrs) ( -- Remark: we are discarding the where clause because it gets printed seperately from the rest of -- the generic. printGenerics :: Generics a -> Doc a -printGenerics (Generics lifetimes tyParams _ x) - | null lifetimes && null tyParams = mempty - | otherwise = let lifetimes' = printLifetimeDef `map` lifetimes - bounds' = [ printTyParam param | param<-tyParams ] - in annotate x (group ("<" <##> ungroup (block NoDelim True "," mempty (lifetimes' ++ bounds')) <##> ">")) +printGenerics (Generics params _ x) + | null params = mempty + | otherwise = let params' = printGenericParam `map` params + in annotate x (group ("<" <##> ungroup (block NoDelim True "," mempty params') <##> ">")) -- | Print a poly-trait ref (@print_poly_trait_ref@) printPolyTraitRef :: PolyTraitRef a -> Doc a @@ -958,15 +974,28 @@ printTraitRef :: TraitRef a -> Doc a printTraitRef (TraitRef path) = printPath path False -- | Print a path parameter and signal whether its generic (if any) should start with a colon (@print_path_parameters@) -printPathParameters :: PathParameters a -> Bool -> Doc a -printPathParameters (Parenthesized ins out x) colons = annotate x $ - when colons "::" <> parens (commas ins printType) <+> perhaps (\t -> "->" <+> printType t) out -printPathParameters (AngleBracketed lts tys bds x) colons = annotate x (when colons "::" <> "<" <> hsep (punctuate "," (lts' ++ tys' ++ bds')) <> ">") +printGenericArgs :: Bool -> GenericArgs a -> Doc a +printGenericArgs colons (Parenthesized ins out x) = annotate x (when colons "::" <> parenStuff <+> out') where - lts' = printLifetime <$> lts - tys' = printType <$> tys - bds' = (\(ident,ty) -> printIdent ident <+> "=" <+> printType ty) <$> bds + ins' = printType <$> ins + out' = perhaps (\t -> "->" <+> printType t) out + parenStuff = block Paren True "," mempty ins' +printGenericArgs colons (AngleBracketed args bds x) = annotate x (when colons "::" <> angleStuff) + where + args' = printGenericArg <$> args + bds' = printAssocTyConstraint <$> bds + angleStuff = group ("<" <##> ungroup (block NoDelim True "," mempty (args' ++ bds')) <##> ">") + +-- | Print a generic argument +printGenericArg :: GenericArg a -> Doc a +printGenericArg (LifetimeArg l) = printLifetime l +printGenericArg (TypeArg t) = printType t +printGenericArg (ConstArg e) = printExpr e +-- | Print an associated type constraint +printAssocTyConstraint :: AssocTyConstraint a -> Doc a +printAssocTyConstraint (EqualityConstraint i t x) = annotate x (printIdent i <+> "=" <+> printType t) +printAssocTyConstraint (BoundConstraint i b x) = annotate x (printIdent i <> printBounds ":" (toList b)) -- | Print a path, specifiying explicitly whether to include colons (@::@) before generics -- or not (so expression style or type style generics) (@print_path@) @@ -976,7 +1005,7 @@ printPath (Path global segs x) colons = annotate x (when global "::" <> hcat (pu -- | Print a path segment printSegment :: PathSegment a -> Bool -> Doc a printSegment (PathSegment i ps x) colons = annotate x (printIdent i <> params) - where params = perhaps (\p -> printPathParameters p colons) ps + where params = perhaps (printGenericArgs colons) ps -- | Print a qualified path, specifiying explicitly whether to include colons (@::@) before @@ -984,8 +1013,9 @@ printSegment (PathSegment i ps x) colons = annotate x (printIdent i <> params) printQPath :: Path a -> QSelf a -> Bool -> Doc a printQPath (Path global segs x) (QSelf ty n) colons = hcat [ "<", printType ty <+> aliasedDoc, ">", "::", restDoc ] where - (aliased, rest) = splitAt n segs - + n' = if global then n-1 else n + (aliased, rest) = splitAt n' segs + aliasedDoc = case aliased of [] -> mempty segs -> "as" <+> printPath (Path global segs x) False @@ -1001,16 +1031,22 @@ printUseTree (UseTreeGlob p x) = annotate x (printPath p True <> "::*") printUseTree (UseTreeNested p@(Path _ [] _) n x) = annotate x (printPath p True <> "{" <> hcat (punctuate ", " (map printUseTree n)) <> "}") printUseTree (UseTreeNested p n x) = annotate x (printPath p True <> "::{" <> hcat (punctuate ", " (map printUseTree n)) <> "}") --- | Print a type parameters (@print_ty_param@) -printTyParam :: TyParam a -> Doc a -printTyParam (TyParam as i bds def x) = annotate x $ hsep +-- | Print a type parameter (@print_ty_param@) +printGenericParam :: GenericParam a -> Doc a +printGenericParam (LifetimeParam as lt bds x) = annotate x (printOuterAttrs as <+> printLifetime lt <> printBounds ":" bds) +printGenericParam (TypeParam as i bds def x) = annotate x $ hsep [ printOuterAttrs as , printIdent i <> printBounds ":" bds , perhaps (\def' -> "=" <+> printType def') def ] +printGenericParam (ConstParam as i ty x) = annotate x $ hsep + [ printOuterAttrs as + , "const" + , printIdent i <> ":" + , printType ty + ] -- | Print lifetime bounds (@print_lifetime_bounds@) printLifetimeBounds :: Lifetime a -> [Lifetime a] -> Doc a printLifetimeBounds lifetime bounds = printLifetime lifetime <> unless (null bounds) (":" <+> foldr1 (\x y -> x <+> "+" <+> y) (printLifetime <$> bounds)) - diff --git a/src/Language/Rust/Pretty/Literals.hs b/src/Language/Rust/Pretty/Literals.hs index f37d7e4..9be221d 100644 --- a/src/Language/Rust/Pretty/Literals.hs +++ b/src/Language/Rust/Pretty/Literals.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Pretty.Literals Description : Parsing literals -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -19,9 +19,10 @@ module Language.Rust.Pretty.Literals ( import Language.Rust.Syntax.AST import Language.Rust.Pretty.Util -import Data.Text.Prettyprint.Doc ( hcat, annotate, (<>), Doc, pretty, group, hardline, flatAlt ) +import Data.Text.Prettyprint.Doc ( hcat, annotate, Doc, pretty, group, hardline, flatAlt ) import Data.Char ( intToDigit, ord, chr ) +import Data.Semigroup as Sem import Data.Word ( Word8 ) -- | Print a literal (@print_literal@) @@ -42,7 +43,7 @@ printLit lit = noIndent $ case lit of pad m = pretty (replicate m '#') suf :: Suffix -> Doc a - suf = printLitSuffix + suf = printLitSuffix -- | Print literal suffix printLitSuffix :: Suffix -> Doc a @@ -90,8 +91,8 @@ printIntLit i r | i < 0 = "-" <> baseRep r <> toNBase (abs i) (baseVal r) -- | Extend a byte into a unicode character byte2Char :: Word8 -> Char -byte2Char = chr . fromIntegral - +byte2Char = chr . fromIntegral + -- | Constrain a unicode character to a byte -- This assumes the character is in the right range already char2Byte :: Char -> Word8 @@ -103,15 +104,15 @@ char2Byte = fromIntegral . ord -- too long. escapeByte :: Bool -> Word8 -> Doc a escapeByte nl w8 = case byte2Char w8 of - '\t' -> "\\t" + '\t' -> "\\t" '\r' -> "\\r" - '\\' -> "\\\\" + '\\' -> "\\\\" '\'' -> "\\'" '"' -> "\\\"" '\n'| nl -> flatAlt hardline "\\n" | otherwise -> "\\n" c | 0x20 <= w8 && w8 <= 0x7e -> pretty c - _ -> "\\x" <> padHex 2 w8 + _ -> "\\x" Sem.<> padHex 2 w8 -- | Escape a unicode character. Based on @std::ascii::escape_default@. -- @@ -121,7 +122,7 @@ escapeChar :: Bool -> Char -> Doc a escapeChar nl c | c <= '\x7f' = escapeByte nl (char2Byte c) | c <= '\xffff' = "\\u{" <> padHex 4 (ord c) <> "}" | otherwise = "\\u{" <> padHex 6 (ord c) <> "}" - + -- | Convert a number to its padded hexadecimal form padHex :: Integral a => Int -> a -> Doc b padHex i 0 = pretty (replicate i '0') diff --git a/src/Language/Rust/Pretty/Resolve.hs b/src/Language/Rust/Pretty/Resolve.hs index a4d791e..2915197 100644 --- a/src/Language/Rust/Pretty/Resolve.hs +++ b/src/Language/Rust/Pretty/Resolve.hs @@ -1,6 +1,6 @@ {-| Module : Language.Rust.Pretty.Resolve -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -81,11 +81,11 @@ import Control.Monad ( when ) import Control.Monad.Trans.RWS import Data.Dynamic ( Dynamic, toDyn, Typeable ) -import Data.List ( find ) +import Data.List ( find, sortBy ) import Data.List.NonEmpty ( NonEmpty(..) ) import qualified Data.List.NonEmpty as N -import Data.Maybe ( fromJust ) -import Data.Semigroup ( (<>) ) +import Data.Maybe ( fromJust, isJust ) +import Data.Semigroup as Sem ( (<>) ) {-# ANN module "HLint: ignore Reduce duplication" #-} @@ -105,7 +105,7 @@ data Severity data Issue = Issue { description :: String -- ^ Description of the issue - + , severity :: !Severity -- ^ Severity of the issue @@ -211,7 +211,7 @@ class Resolve a where -- -- * the shebang to be one-line not conflicting with attributes -- * the attributes to be inner --- * the items to be 'ModItems' +-- * the items to be `ModItem`'s -- resolveSourceFile :: (Typeable a, Monoid a) => SourceFile a -> ResolveM (SourceFile a) resolveSourceFile s@(SourceFile sh as is) = scope s $ do @@ -226,7 +226,7 @@ resolveSourceFile s@(SourceFile sh as is) = scope s $ do instance (Typeable a, Monoid a) => Resolve (SourceFile a) where resolveM = resolveSourceFile -- | An identifier can be invalid if --- +-- -- * it does not lex into an identifier -- * it is a keyword -- @@ -243,12 +243,12 @@ resolveIdent i@(Ident s r _) = where - keywords = map mkIdent $ words "as box break const continue crate else enum extern false fn for\ - \ if impl in let loop match mod move mut pub ref return Self self\ - \ static struct super trait true type unsafe use where while\ - \ abstract alignof become do final macro offsetof override priv\ - \ proc pure sizeof typeof unsized virtual yield" - + keywords = map mkIdent $ words "as async await box break const continue crate do dyn else enum \ + \extern false fn for if impl in let loop macro match mod move mut \ + \pub ref return Self self static struct super trait true try type \ + \unsafe use where while yield abstract become final override priv \ + \proc typeof unsized virtual" + s' = (if r then "r#" else "") ++ s toks = execParser (lexTokens lexToken) (inputStreamFromString s') initPos @@ -278,7 +278,7 @@ data AttrType -- * the tokenstream starts with a '::' -- resolveAttr :: (Typeable a, Monoid a) => AttrType -> Attribute a -> ResolveM (Attribute a) -resolveAttr typ s@(SugaredDoc sty inl con x) = scope s $ do +resolveAttr typ s@(SugaredDoc sty inl con x) = scope s $ do sty' <- case (typ, sty) of (OuterAttr, Inner) -> correct "inner attribute was turned into outer attribute" *> pure Outer (InnerAttr, Outer) -> correct "outer attribute was turned into inner attribute" *> pure Inner @@ -353,21 +353,10 @@ resolvePath :: (Typeable a, Monoid a) => PathType -> Path a -> ResolveM (Path a) resolvePath t p@(Path _ [] _) | t /= UsePath = scope p $ err p "path must have at least one segment" resolvePath t p@(Path g segs x) = scope p $ if null [ () | PathSegment _ (Just a) _ <- segs, not (isParamsForPath t a) ] - then Path g <$> traverse resolveSeg segs <*> pure x + then Path g <$> traverse resolvePathSegment segs <*> pure x else err p "path parameter is not valid for this type of path" where - resolveSeg :: (Typeable a, Monoid a) => PathSegment a -> ResolveM (PathSegment a) - resolveSeg (PathSegment i a x') = do - i' <- case i of - Ident "self" False _ -> pure i - Ident "Self" False _ -> pure i - Ident "super" False _ -> pure i - Ident "crate" False _ -> pure i - _ -> resolveIdent i - a' <- traverse resolvePathParameters a - pure (PathSegment i' a' x') - - isParamsForPath :: PathType -> PathParameters a -> Bool + isParamsForPath :: PathType -> GenericArgs a -> Bool isParamsForPath t' AngleBracketed{} = t' `elem` ([TypePath, ExprPath] :: [PathType]) isParamsForPath t' Parenthesized{} = t' `elem` ([TypePath] :: [PathType]) @@ -376,19 +365,45 @@ resolvePath t p@(Path g segs x) = scope p $ instance (Typeable a, Monoid a) => Resolve (Path a) where resolveM = resolvePath TypePath + +resolvePathSegment :: (Typeable a, Monoid a) => PathSegment a -> ResolveM (PathSegment a) +resolvePathSegment (PathSegment i a x') = do + i' <- case i of + Ident "self" False _ -> pure i + Ident "Self" False _ -> pure i + Ident "super" False _ -> pure i + Ident "crate" False _ -> pure i + _ -> resolveIdent i + a' <- traverse resolveGenericArgs a + pure (PathSegment i' a' x') + -- | A path parameter can be invalid if any of its constituent components are invalid -resolvePathParameters :: (Typeable a, Monoid a) => PathParameters a -> ResolveM (PathParameters a) -resolvePathParameters p@(AngleBracketed lts tys bds x) = scope p $ do - lts' <- traverse resolveLifetime lts - tys' <- traverse (resolveTy AnyType) tys - bds' <- traverse (\(i,t) -> (,) <$> resolveIdent i <*> resolveTy NoSumType t) bds - pure (AngleBracketed lts' tys' bds' x) -resolvePathParameters p@(Parenthesized tys tym x) = scope p $ do +resolveGenericArgs :: (Typeable a, Monoid a) => GenericArgs a -> ResolveM (GenericArgs a) +resolveGenericArgs p@(Parenthesized tys tym x) = scope p $ do tys' <- traverse (resolveTy AnyType) tys tym' <- traverse (resolveTy NoSumType) tym pure (Parenthesized tys' tym' x) +resolveGenericArgs p@(AngleBracketed args bds x) = scope p $ do + args' <- if isSorted genericArgOrder args + then pure args + else do correct "sorted generic arguments" + pure (sortBy genericArgOrder args) + args'' <- traverse resolveGenericArg args' + bds' <- traverse resolveAssocTyConstraint bds + pure (AngleBracketed args'' bds' x) + +instance (Typeable a, Monoid a) => Resolve (GenericArgs a) where resolveM = resolveGenericArgs + +resolveGenericArg :: (Typeable a, Monoid a) => GenericArg a -> ResolveM (GenericArg a) +resolveGenericArg (LifetimeArg l) = LifetimeArg <$> resolveLifetime l +resolveGenericArg (TypeArg t) = TypeArg <$> resolveTy AnyType t +resolveGenericArg (ConstArg e) = ConstArg <$> resolveExpr LitOrBlockExpr e -instance (Typeable a, Monoid a) => Resolve (PathParameters a) where resolveM = resolvePathParameters +instance (Typeable a, Monoid a) => Resolve (GenericArg a) where resolveM = resolveGenericArg + +resolveAssocTyConstraint :: (Typeable a, Monoid a) => AssocTyConstraint a -> ResolveM (AssocTyConstraint a) +resolveAssocTyConstraint (EqualityConstraint i t x) = EqualityConstraint <$> resolveIdent i <*> resolveTy NoSumType t <*> pure x +resolveAssocTyConstraint (BoundConstraint i b x) = BoundConstraint <$> resolveIdent i <*> traverse (resolveGenericBound ModBound) b <*> pure x -- | A QSelf by itself is only invalid when the underlying type is resolveQSelf :: (Typeable a, Monoid a) => QSelf a -> ResolveM (QSelf a) @@ -405,8 +420,8 @@ instance (Typeable a, Monoid a) => Resolve (QSelf a) where resolveM = resolveQSe -- keywords. resolveLifetime :: Typeable a => Lifetime a -> ResolveM (Lifetime a) resolveLifetime l@(Lifetime n _) - | n == "static" = pure l - | n == "_" = pure l + | n == "static" = pure l + | n == "_" = pure l | otherwise = scope l (resolveIdent (mkIdent n) *> pure l) instance Typeable a => Resolve (Lifetime a) where resolveM = resolveLifetime @@ -420,38 +435,37 @@ instance (Typeable a, Monoid a) => Resolve (TraitRef a) where resolveM = resolve -- | There a a variety of constraints imposed on types, representing different invariants data TyType = AnyType -- ^ No restrictions - | NoSumType -- ^ Any type except for 'TraitObject' with a '+' - | PrimParenType -- ^ Types not starting with '<' or '(', or paren types with no sum types inside - | NoForType -- ^ Non-sum types not starting with a 'for' + | NoSumType -- ^ Any type except for 'TraitObject' with a @+@ + | PrimParenType -- ^ Types not starting with @<@ or @(@, or paren types with no sum types inside + | NoForType -- ^ Non-sum types not starting with a @for@ -- | Resolve a given type, and a constraint on it (see the parser 'Internal.y' for more details on --- these cases). +-- these cases). resolveTy :: (Typeable a, Monoid a) => TyType -> Ty a -> ResolveM (Ty a) -- TraitObject resolveTy NoSumType o@(TraitObject b _) | length b > 1 = scope o (correct "added parens around trait object type" *> resolveTy NoSumType (ParenTy o mempty)) -resolveTy NoForType o@TraitObject{} = scope o (correct "added parens around trait object type" *> resolveTy NoForType (ParenTy o mempty)) -resolveTy _ o@(TraitObject bds@(TraitTyParamBound{} :| _) x) - = scope o (TraitObject <$> traverse (resolveTyParamBound ModBound) bds <*> pure x) -resolveTy _ o@TraitObject{} = scope o (err o "first bound in trait object should be a trait bound") -- ParenTy resolveTy PrimParenType p@(ParenTy ty' x) = scope p (ParenTy <$> resolveTy NoSumType ty' <*> pure x) resolveTy _ p@(ParenTy ty' x) = scope p (ParenTy <$> resolveTy AnyType ty' <*> pure x) -- TupTy resolveTy PrimParenType t@TupTy{} = scope t (correct "added parens around tuple type" *> resolveTy PrimParenType (ParenTy t mempty)) resolveTy _ t@(TupTy tys x) = scope t (TupTy <$> traverse (resolveTy AnyType) tys <*> pure x) --- ImplTrait -resolveTy _ i@(ImplTrait bds x) = scope i (ImplTrait <$> traverse (resolveTyParamBound ModBound) bds <*> pure x) +-- ImplTrait/TraitObject +resolveTy _ i@(ImplTrait bds x) = scope i (ImplTrait <$> traverse (resolveGenericBound ModBound) bds <*> pure x) +resolveTy _ o@(TraitObject bds x) = scope o (TraitObject <$> traverse (resolveGenericBound ModBound) bds <*> pure x) -- PathTy resolveTy PrimParenType p@(PathTy (Just _) _ _) = scope p (correct "added parents around path type" *> resolveTy PrimParenType (ParenTy p mempty)) -resolveTy _ p@(PathTy q p'@(Path _ s _) x) = scope p $ +resolveTy _ p@(PathTy q p'@(Path g s _) x) = scope p $ + let sLen = if g then length s + 1 else length s in case q of Just (QSelf _ i) - | 0 <= i && i < length s -> PathTy <$> traverse resolveQSelf q <*> resolvePath TypePath p' <*> pure x - | otherwise -> err p "index given by QSelf is outside the possible range" - Nothing -> PathTy Nothing <$> resolvePath TypePath p' <*> pure x + | 0 <= i + , i < sLen -> PathTy <$> traverse resolveQSelf q <*> resolvePath TypePath p' <*> pure x + | otherwise -> err p "index given by QSelf is outside the possible range" + Nothing -> PathTy Nothing <$> resolvePath TypePath p' <*> pure x -- BareFn resolveTy NoForType f@(BareFn _ _ (_:_) _ _) = scope f (correct "added parens around `for' function type" *> resolveTy NoForType (ParenTy f mempty)) -resolveTy _ f@(BareFn u a lts fd x) = scope f (BareFn u a <$> traverse resolveLifetimeDef lts <*> resolveFnDecl declTy GeneralArg fd <*> pure x) +resolveTy _ f@(BareFn u a lts fd x) = scope f (BareFn u a <$> traverse resolveGenericParam lts <*> resolveFnDecl declTy GeneralArg fd <*> pure x) where declTy = if a == C then VarNoSelf else NoSelf -- Other types (don't care about the context) resolveTy _ (Never x) = pure (Never x) @@ -489,22 +503,24 @@ isSelfArg _ = True instance (Typeable a, Monoid a) => Resolve (FnDecl a) where resolveM = resolveFnDecl AllowSelf NamedArg --- | Only some type parameter bounds allow trait bounds to start with ? -data TyParamBoundType - = NoneBound -- ^ Don't allow '? poly_trait_ref' - | ModBound -- ^ Allow '? poly_trait_ref' +-- | Only some type parameter bounds allow trait bounds to start with @?@ +data GenericBoundType + = OnlyLifetimes -- ^ Allow /only/ lifetime bounds + | NoneBound -- ^ Don't allow @? poly_trait_ref@ + | ModBound -- ^ Allow @? poly_trait_ref@ -- | A type parameter bound is invalid if -- -- * an underlying lifetime or traitref is --- * it is 'NoneBound' but is a trait bound with a '?' (as in 'ObjectTrait') +-- * it is 'NoneBound' but is a trait bound with a @?@ (as in 'TraitObject') -- -resolveTyParamBound :: (Typeable a, Monoid a) => TyParamBoundType -> TyParamBound a -> ResolveM (TyParamBound a) -resolveTyParamBound _ b@(RegionTyParamBound lt x) = scope b (RegionTyParamBound <$> resolveLifetime lt <*> pure x) -resolveTyParamBound NoneBound b@(TraitTyParamBound _ Maybe _) = scope b (err b "? trait is not allowed in this type param bound") -resolveTyParamBound _ b@(TraitTyParamBound p t x) = scope b (TraitTyParamBound <$> resolvePolyTraitRef p <*> pure t <*> pure x) +resolveGenericBound :: (Typeable a, Monoid a) => GenericBoundType -> GenericBound a -> ResolveM (GenericBound a) +resolveGenericBound _ b@(OutlivesBound lt x) = scope b (OutlivesBound <$> resolveLifetime lt <*> pure x) +resolveGenericBound OnlyLifetimes b@TraitBound{} = scope b (err b "? trait is not allowed in this type param bound") +resolveGenericBound NoneBound b@(TraitBound _ Maybe _) = scope b (err b "a trait cannot bound a lifetime") +resolveGenericBound _ b@(TraitBound p t x) = scope b (TraitBound <$> resolvePolyTraitRef p <*> pure t <*> pure x) -instance (Typeable a, Monoid a) => Resolve (TyParamBound a) where resolveM = resolveTyParamBound ModBound +instance (Typeable a, Monoid a) => Resolve (GenericBound a) where resolveM = resolveGenericBound ModBound -- | There are several restricted forms of arguments allowed data ArgType @@ -514,38 +530,48 @@ data ArgType -- | The only types of patterns supported by arguments are wild or identifiers resolveArg :: (Typeable a, Monoid a) => ArgType -> Arg a -> ResolveM (Arg a) -resolveArg _ s@SelfValue{} = pure s -resolveArg _ a@(SelfRegion lt m x) = scope a (SelfRegion <$> traverse resolveLifetime lt <*> pure m <*> pure x) -resolveArg _ a@(SelfExplicit t m x) = scope a (SelfExplicit <$> resolveTy AnyType t <*> pure m <*> pure x) -resolveArg NamedArg a@(Arg Nothing _ _) = scope a (err a "named arguments must have patterns") -resolveArg NamedArg a@(Arg p t x) = scope a $ do +resolveArg _ s@(SelfValue as m x) = scope s $ do + as' <- traverse (resolveAttr OuterAttr) as + pure (SelfValue as' m x) +resolveArg _ a@(SelfRegion as lt m x) = scope a $ do + as' <- traverse (resolveAttr OuterAttr) as + lt' <- traverse resolveLifetime lt + pure (SelfRegion as' lt' m x) +resolveArg _ a@(SelfExplicit as t m x) = scope a $ do + as' <- traverse (resolveAttr OuterAttr) as + t' <- resolveTy AnyType t + pure (SelfExplicit as' t' m x) +resolveArg NamedArg a@(Arg _ Nothing _ _) = scope a (err a "named arguments must have patterns") +resolveArg NamedArg a@(Arg as p t x) = scope a $ do when (isSelfAlike a) $ warn "argument looks like a self argument - did you mean to use 'SelfValue', 'SelfRegion', or 'SelfExplicit'?" - p' <- traverse resolvePat p + as' <- traverse (resolveAttr OuterAttr) as + p' <- traverse (resolvePat NoOrPattern) p t' <- resolveTy AnyType t - pure (Arg p' t' x) + pure (Arg as' p' t' x) -resolveArg GeneralArg a@(Arg p t x) = scope a $ do +resolveArg GeneralArg a@(Arg as p t x) = scope a $ do when (isSelfAlike a) $ warn "argument looks like a self argument - did you mean to use 'SelfValue', 'SelfRegion', or 'SelfExplicit'?" - + + as' <- traverse (resolveAttr OuterAttr) as p' <- case p of Nothing -> pure Nothing - Just WildP{} -> traverse resolvePat p - Just IdentP{} -> traverse resolvePat p - Just (RefP WildP{} Immutable _) -> traverse resolvePat p - Just (RefP (IdentP (ByValue Immutable) _ _ _) Immutable _) -> traverse resolvePat p - Just (RefP (RefP WildP{} Immutable _) Immutable _) -> traverse resolvePat p - Just (RefP (RefP (IdentP (ByValue Immutable) _ _ _) Immutable _) Immutable _) -> traverse resolvePat p + Just WildP{} -> traverse (resolvePat NoOrPattern) p + Just IdentP{} -> traverse (resolvePat NoOrPattern) p + Just (RefP WildP{} Immutable _) -> traverse (resolvePat NoOrPattern) p + Just (RefP (IdentP (ByValue Immutable) _ _ _) Immutable _) -> traverse (resolvePat NoOrPattern) p + Just (RefP (RefP WildP{} Immutable _) Immutable _) -> traverse (resolvePat NoOrPattern) p + Just (RefP (RefP (IdentP (ByValue Immutable) _ _ _) Immutable _) Immutable _) -> traverse (resolvePat NoOrPattern) p _ -> scope p (err p "this pattern is not allowed for this type of argument") t' <- resolveTy AnyType t - pure (Arg p' t' x) + pure (Arg as' p' t' x) -- | Check whether an argument is one of the "self"-alike forms isSelfAlike :: Arg a -> Bool -isSelfAlike (Arg Nothing (PathTy Nothing (Path False [PathSegment (Ident "self" False _) Nothing _] _) _) _) = True -isSelfAlike (Arg Nothing (Rptr _ _ (PathTy Nothing (Path False [PathSegment (Ident "self" False _) Nothing _] _) _) _) _) = True +isSelfAlike (Arg _ Nothing (PathTy Nothing (Path False [PathSegment (Ident "self" False _) Nothing _] _) _) _) = True +isSelfAlike (Arg _ Nothing (Rptr _ _ (PathTy Nothing (Path False [PathSegment (Ident "self" False _) Nothing _] _) _) _) _) = True isSelfAlike _ = False instance (Typeable a, Monoid a) => Resolve (Arg a) where resolveM = resolveArg NamedArg @@ -553,82 +579,88 @@ instance (Typeable a, Monoid a) => Resolve (Arg a) where resolveM = resolveArg N -- | A Poly trait ref is valid whenever the underlying trait ref is. resolvePolyTraitRef :: (Typeable a, Monoid a) => PolyTraitRef a -> ResolveM (PolyTraitRef a) resolvePolyTraitRef p@(PolyTraitRef lts t x) = scope p $ do - lts' <- traverse resolveLifetimeDef lts + lts' <- traverse resolveGenericParam lts t' <- resolveTraitRef t pure (PolyTraitRef lts' t' x) instance (Typeable a, Monoid a) => Resolve (PolyTraitRef a) where resolveM = resolvePolyTraitRef --- | A lifetime def is invalid if it has non-outer attributes -resolveLifetimeDef :: (Typeable a, Monoid a) => LifetimeDef a -> ResolveM (LifetimeDef a) -resolveLifetimeDef lts@(LifetimeDef as l bds x) = scope lts $ do - as' <- traverse (resolveAttr OuterAttr) as - l' <- resolveLifetime l - bds' <- traverse resolveLifetime bds - pure (LifetimeDef as' l' bds' x) - -instance (Typeable a, Monoid a) => Resolve (LifetimeDef a) where resolveM = resolveLifetimeDef - -------------- -- Patterns -- -------------- +-- | There a a variety of constraints imposed on patterns, representing different invariants +data PatType + = TopPattern -- ^ No restrictions, can have @|@ patterns + | NoOrPattern -- ^ Can't have @|@ patterns + +parenthesizeP :: (Typeable a, Monoid a) => Pat a -> ResolveM (Pat a) +parenthesizeP p = do + correct "added parens around pattern" + p' <- resolvePat TopPattern p + pure (ParenP p' mempty) + -- | A pattern can be invalid of -- --- * the index of the '...' in the tuple/tuple-struct is out of range -- * the index of the qself path is out of range -- * any underlying component is invalid -- -resolvePat :: (Typeable a, Monoid a) => Pat a -> ResolveM (Pat a) +resolvePat :: (Typeable a, Monoid a) => PatType -> Pat a -> ResolveM (Pat a) -- TupleStruct -resolvePat t@(TupleStructP p fs im x) = scope t $ do +resolvePat _ t@(TupleStructP p fs x) = scope t $ do p' <- resolvePath ExprPath p - fs' <- traverse resolvePat fs - im' <- case im of - Nothing -> pure Nothing - Just i | 0 <= i && i <= length fs -> pure (Just i) - _ -> err im "index of ... in tuple struct pattern is outside of field range" - pure (TupleStructP p' fs' im' x) + fs' <- traverse (resolvePat TopPattern) fs + pure (TupleStructP p' fs' x) -- PathP -resolvePat p@(PathP Nothing a x) = scope p (PathP Nothing <$> resolvePath ExprPath a <*> pure x) -resolvePat p@(PathP q@(Just (QSelf _ i)) p'@(Path g s x) x') - | i < 0 || i >= length s = scope p (err p "index given by QSelf is outside the possible range") +resolvePat _ p@(PathP Nothing a x) = scope p (PathP Nothing <$> resolvePath ExprPath a <*> pure x) +resolvePat _ p@(PathP q@(Just (QSelf _ i)) p'@(Path g s x) x') + | iMax <- if g then length s + 1 else length s + , i < 0 || i >= iMax = scope p (err p "index given by QSelf is outside the possible range") | i == 0 = scope p (PathP <$> traverse resolveQSelf q <*> resolvePath ExprPath p' <*> pure x) | otherwise = scope p $ do Path _ tyPSegs _ <- resolvePath TypePath $ Path g (take i s) mempty Path _ exprPSegs _ <- resolvePath ExprPath $ Path False (drop i s) x q' <- traverse resolveQSelf q - pure (PathP q' (Path g (tyPSegs <> exprPSegs) x) x') + pure (PathP q' (Path g (tyPSegs Sem.<> exprPSegs) x) x') -- TupleP -resolvePat p@(TupleP ps i x) = scope p $ do - ps' <- traverse resolvePat ps - i' <- case i of - Nothing -> pure Nothing - Just j | 0 <= j && j <= length ps -> pure i - | otherwise -> err i "index of ... in tuple pattern is outside of range" - pure (TupleP ps' i' x) +resolvePat _ p@(TupleP ps x) = scope p $ do + ps' <- traverse (resolvePat TopPattern) ps + pure (TupleP ps' x) +-- OrP +resolvePat NoOrPattern p@OrP{} = parenthesizeP p +resolvePat TopPattern p@(OrP ps x) = scope p $ do + ps' <- traverse (resolvePat NoOrPattern) ps + pure (OrP ps' x) -- Everything else... -resolvePat p@(LitP e x) = scope p (LitP <$> resolveExpr LitExpr e <*> pure x) -resolvePat p@(RangeP l h x) = scope p (RangeP <$> resolveExpr LitOrPathExpr l <*> resolveExpr LitOrPathExpr h <*> pure x) -resolvePat p@(WildP x) = scope p (pure (WildP x)) -resolvePat p@(IdentP m i p' x) = scope p (IdentP m <$> resolveIdent i <*> traverse resolvePat p' <*> pure x) -resolvePat p@(StructP p' fs b x) = scope p (StructP <$> resolvePath ExprPath p' <*> traverse resolveFieldPat fs <*> pure b <*> pure x) -resolvePat p@(BoxP p' x) = scope p (BoxP <$> resolvePat p' <*> pure x) -resolvePat p@(RefP p' m x) = scope p (RefP <$> resolvePat p' <*> pure m <*> pure x) -resolvePat p@(SliceP b m a x) = scope p (SliceP <$> traverse resolvePat b <*> traverse resolvePat m <*> traverse resolvePat a <*> pure x) -resolvePat p@(MacP m x) = scope p (MacP <$> resolveMac ExprPath m <*> pure x) - -instance (Typeable a, Monoid a) => Resolve (Pat a) where resolveM = resolvePat +resolvePat _ p@(LitP e x) = scope p (LitP <$> resolveExpr LitExpr e <*> pure x) +resolvePat _ p@(RangeP l h rl x) = scope p (RangeP <$> resolveExpr LitOrPathExpr l <*> resolveExpr LitOrPathExpr h <*> pure rl <*> pure x) +resolvePat _ p@(WildP x) = scope p (pure (WildP x)) +resolvePat _ p@(IdentP m i p' x) = scope p (IdentP m <$> resolveIdent i <*> traverse (resolvePat NoOrPattern) p' <*> pure x) +resolvePat _ p@(StructP p' fs b x) = scope p (StructP <$> resolvePath ExprPath p' <*> traverse resolveFieldPat fs <*> pure b <*> pure x) +resolvePat _ p@(BoxP p' x) = scope p (BoxP <$> resolvePat NoOrPattern p' <*> pure x) +resolvePat _ p@(RefP p' m x) = scope p (RefP <$> resolvePat NoOrPattern p' <*> pure m <*> pure x) +resolvePat _ p@(SliceP ps x) = scope p (SliceP <$> traverse (resolvePat TopPattern) ps <*> pure x) +resolvePat _ p@(RestP x) = scope p (pure (RestP x)) +resolvePat _ p@(ParenP p' x) = scope p (ParenP <$> (resolvePat TopPattern) p' <*> pure x) +resolvePat _ p@(MacP m x) = scope p (MacP <$> resolveMac ExprPath m <*> pure x) + +instance (Typeable a, Monoid a) => Resolve (Pat a) where resolveM = resolvePat TopPattern -- | Field patterns are only invalid if the underlying pattern / identifier is resolveFieldPat :: (Typeable a, Monoid a) => FieldPat a -> ResolveM (FieldPat a) -resolveFieldPat f@(FieldPat Nothing p x) = scope f $ - case p of (IdentP _ _ Nothing _) -> FieldPat Nothing <$> resolvePat p <*> pure x - (BoxP (IdentP _ _ Nothing _) _) -> FieldPat Nothing <$> resolvePat p <*> pure x - _ -> err f "patterns for fields without an identifier must be (possibly box) identifiers" -resolveFieldPat f@(FieldPat i p x) = scope f (FieldPat <$> traverse resolveIdent i <*> resolvePat p <*> pure x) +resolveFieldPat f@(FieldPat Nothing p as x) = scope f $ + let as' = traverse (resolveAttr OuterAttr) as + in case p of (IdentP _ _ Nothing _) -> FieldPat Nothing <$> resolvePat TopPattern p <*> as' <*> pure x + (BoxP (IdentP _ _ Nothing _) _) -> FieldPat Nothing <$> resolvePat TopPattern p <*> as' <*> pure x + _ -> err f "patterns for fields without an identifier must be (possibly box) identifiers" +resolveFieldPat f@(FieldPat i p as x) = scope f $ + FieldPat <$> + traverse resolveIdent i <*> + resolvePat TopPattern p <*> + traverse (resolveAttr OuterAttr) as <*> + pure x instance (Typeable a, Monoid a) => Resolve (FieldPat a) where resolveM = resolveFieldPat @@ -642,6 +674,7 @@ data ExprType = AnyExpr -- ^ Any expression, no restrictions | LitExpr -- ^ Either an immediate literal, or a negated literal | LitOrPathExpr -- ^ A literal, negated literal, expression path, or qualified expression path + | LitOrBlockExpr -- ^ A literal, negated literal, or (safe, not async, un-labeled) block expression | NoStructExpr -- ^ No struct literals are allowed | NoStructBlockExpr -- ^ No struct literals or block expressions (block-like things like 'if' are fine) | SemiExpr -- ^ Forbids expressions starting with blocks (things like '{ 1 } + 2') unless @@ -654,9 +687,8 @@ data ExprType -- -- ie: `if i[0] == j[0] { i } else { j } [1]` lhsSemiExpr :: (Typeable a, Monoid a) => Int -> Expr a -> ResolveM (Expr a) -lhsSemiExpr p t@(Try _ e _) = resolveExprP p AnyExpr - -lhsSemiExpr p (FieldAccess _ e _ _) | isBlockLike e = +lhsSemiExpr p t@(Try _ e _) = resolveExprP p AnyExpr +lhsSemiExpr p (FieldAccess _ e _ _) | isBlockLike e = lhsSemiExpr p (Try _ e _) lhsSemiExpr p (Try _ e _) @@ -664,16 +696,18 @@ lhsSemiExpr p (Try _ e _) resolveLhsExprP :: (Typeable a, Monoid a) => Int -> ExprType -> Expr a -> ResolveM (Expr a) resolveLhsExprP p SemiExpr l@Try{} = resolveExprP p AnyExpr l -resolveLhsExprP p SemiExpr l@FieldAccess{} = resolveExprP p AnyExpr l +resolveLhsExprP p SemiExpr l@FieldAccess{} = resolveExprP p AnyExpr l resolveLhsExprP p SemiExpr l@MethodCall{} = resolveExprP p AnyExpr l resolveLhsExprP p SemiExpr l@TupField{} = resolveExprP p AnyExpr l -resolveLhsExprP _ SemiExpr l | isBlockLike l = parenthesize l +resolveLhsExprP p SemiExpr l@Await{} = resolveExprP p AnyExpr l +resolveLhsExprP _ SemiExpr l | isBlockLike l = parenthesizeE l resolveLhsExprP p t l = resolveExprP p (lhs t) l where -- | Given the type of expression, what type of expression is allowed on the LHS lhs :: ExprType -> ExprType lhs LitExpr = error "literal expressions never have a left hand side" lhs LitOrPathExpr = error "literal or path expressions never have a left hand side" + lhs LitOrBlockExpr = error "literal or path expressions never have a left hand side" lhs AnyExpr = AnyExpr lhs NoStructExpr = NoStructExpr lhs NoStructBlockExpr = NoStructBlockExpr @@ -683,15 +717,17 @@ resolveLhsExprP p t l = resolveExprP p (lhs t) l rhs :: ExprType -> ExprType rhs LitExpr = error "literal expressions never have a right hand side" rhs LitOrPathExpr = error "literal or path expressions never have a right hand side" +rhs LitOrBlockExpr = error "literal or path expressions never have a left hand side" rhs AnyExpr = AnyExpr rhs NoStructExpr = NoStructExpr rhs NoStructBlockExpr = NoStructExpr rhs SemiExpr = AnyExpr --- | Given the type of expression, what type of expression is allowed on the RHS (after '..'/'...') +-- | Given the type of expression, what type of expression is allowed on the RHS (after @..@/@...@) rhs2 :: ExprType -> ExprType rhs2 LitExpr = error "literal expressions never have a right hand side (2)" rhs2 LitOrPathExpr = error "literal or path expressions never have a right hand side (2)" +rhs2 LitOrBlockExpr = error "literal or path expressions never have a left hand side" rhs2 AnyExpr = AnyExpr rhs2 NoStructExpr = NoStructBlockExpr rhs2 NoStructBlockExpr = NoStructBlockExpr @@ -703,8 +739,8 @@ resolveExpr = resolveExprP 0 instance (Typeable a, Monoid a) => Resolve (Expr a) where resolveM = resolveExpr AnyExpr -parenthesize :: (Typeable a, Monoid a) => Expr a -> ResolveM (Expr a) -parenthesize e = do +parenthesizeE :: (Typeable a, Monoid a) => Expr a -> ResolveM (Expr a) +parenthesizeE e = do correct "added parens around expression" e' <- resolveExprP 0 AnyExpr e pure (ParenExpr [] e' mempty) @@ -745,6 +781,14 @@ resolveExprP p LitOrPathExpr l@Lit{} = resolveExprP p AnyExpr l resolveExprP p LitOrPathExpr n@(Unary _ Neg Lit{} _) = resolveExprP p AnyExpr n resolveExprP p LitOrPathExpr p'@PathExpr{} = resolveExprP p AnyExpr p' resolveExprP _ LitOrPathExpr l = scope l (err l "expression is not literal, negated literal, path, or qualified path") +-- Conver the 'LitOrBlockExpr' type of expression +resolveExprP p LitOrBlockExpr l@Lit{} = resolveExprP p AnyExpr l +resolveExprP p LitOrBlockExpr n@(Unary _ Neg Lit{} _) = resolveExprP p AnyExpr n +resolveExprP p LitOrBlockExpr b@(BlockExpr _ (Block _ Normal _) Nothing _) = resolveExprP p AnyExpr b +resolveExprP _ LitOrBlockExpr e = scope e $ do + correct "added braces around expression" + e' <- resolveExpr AnyExpr e + pure (BlockExpr [] (Block [NoSemi e' mempty] Normal mempty) Nothing mempty) -- The following group of expression variants work in all of the remaining contexts (see -- 'gen_expression' in the parser) resolveExprP p c b@(Box as e x) = scope b $ parenE (p > 0) $ do @@ -763,30 +807,30 @@ resolveExprP p c b@(Break as ml me x) = scope b $ parenE (p > 0) $ do as' <- traverse (resolveAttr OuterAttr) as ml' <- traverse resolveLbl ml me' <- traverse (resolveExprP 0 (rhs c)) me - pure (Break as' ml' me' x) -resolveExprP p _ c@(Continue as ml x) = scope c $ parenE (p > 0) $ do + pure (Break as' ml' me' x) +resolveExprP p _ c@(Continue as ml x) = scope c $ parenE (p > 0) $ do as' <- traverse (resolveAttr OuterAttr) as ml' <- traverse resolveLbl ml pure (Continue as' ml' x) -- Closures -resolveExprP _ _ c@(Closure _ _ _ (FnDecl _ _ True _) _ _) = scope c (err c "closures can never be variadic") -resolveExprP p c e@(Closure as m cb fn@(FnDecl _ ret _ _) b x) = scope c $ +resolveExprP _ _ c@(Closure _ _ _ _ (FnDecl _ _ True _) _ _) = scope c (err c "closures can never be variadic") +resolveExprP p c e@(Closure as cb a m fn@(FnDecl _ ret _ _) b x) = scope c $ case (c, ret, b) of - (NoStructExpr, Just _, BlockExpr{}) -> parenthesize e - (NoStructBlockExpr, Just _, BlockExpr{}) -> parenthesize e - (NoStructExpr, Just _, _ ) -> parenthesize (Closure as m cb fn (asBlock b) x) - (NoStructBlockExpr, Just _, _ ) -> parenthesize (Closure as m cb fn (asBlock b) x) + (NoStructExpr, Just _, BlockExpr{}) -> parenthesizeE e + (NoStructBlockExpr, Just _, BlockExpr{}) -> parenthesizeE e + (NoStructExpr, Just _, _ ) -> parenthesizeE (Closure as cb a m fn (asBlock b) x) + (NoStructBlockExpr, Just _, _ ) -> parenthesizeE (Closure as cb a m fn (asBlock b) x) (_, Just _, BlockExpr{}) -> resolved AnyExpr - (_, Just _, _ ) -> parenthesize (Closure as m cb fn (asBlock b) x) + (_, Just _, _ ) -> parenthesizeE (Closure as cb a m fn (asBlock b) x) _ -> resolved (rhs c) where - asBlock ex = BlockExpr [] (Block [NoSemi ex mempty] Normal mempty) mempty + asBlock ex = BlockExpr [] (Block [NoSemi ex mempty] Normal mempty) Nothing mempty resolved c' = parenE (p > 0) $ do as' <- traverse (resolveAttr OuterAttr) as fn' <- resolveFnDecl NoSelf NamedArg fn b' <- resolveExprP 0 c' b - pure (Closure as' m cb fn' b' x) + pure (Closure as' cb a m fn' b' x) -- Assignment/in-place expressions resolveExprP p c a@(Assign as l r x) = scope a $ parenE (p > 1) $ do as' <- traverse (resolveAttr OuterAttr) as @@ -800,12 +844,6 @@ resolveExprP p c a@(AssignOp as o l r x) = scope a $ parenE (p > 1) $ do l' <- resolveLhsExprP 2 c l r' <- resolveExprP 1 (rhs c) r pure (AssignOp as' o l' r' x) -resolveExprP p c i@(InPlace as l r x) = scope i $ parenE (p > 2) $ do - as' <- traverse (resolveAttr OuterAttr) as - --l' <- resolveExprP 3 (lhs c) l - l' <- resolveLhsExprP 3 c l - r' <- resolveExprP 2 (rhs c) r - pure (InPlace as' l' r' x) -- Range expressions resolveExprP _ _ r@(Range _ _ Nothing Closed _) = scope r (err r "inclusive ranges must be bounded at the end") resolveExprP _ _ r@(Range as Nothing Nothing rl x) = scope r $ do @@ -829,9 +867,9 @@ resolveExprP p c a@(Range as Nothing (Just r) rl x) = scope a $ parenE (p > 5) $ -- Binary expressions resolveExprP p c b@(Binary as o l r x) = scope b $ parenE (p > p') $ do as' <- traverse (resolveAttr OuterAttr) as - -- l' <- resolveExprP p' (lhs c) l + -- l' <- resolveExprP p' (lhs c) l l' <- resolveLhsExprP p' c l - r' <- resolveExprP (p' + 1) (rhs c) r + r' <- resolveExprP (p' + 1) (rhs c) r pure (Binary as' o l' r' x) where p' = opPrec o @@ -889,7 +927,7 @@ resolveExprP p c t@(Try as e x) = scope t $ parenE (p > 17) $ do as' <- traverse (resolveAttr OuterAttr) as --e' <- resolveExprP 17 (lhs c) e e' <- resolveLhsExprP 17 c e - pure (Try as' e' x) + pure (Try as' e' x) resolveExprP p c a@(Call as f xs x) = scope a $ parenE (p > 17) $ do as' <- traverse (resolveAttr OuterAttr) as --f' <- resolveExprP 17 (lhs c) f @@ -897,16 +935,13 @@ resolveExprP p c a@(Call as f xs x) = scope a $ parenE (p > 17) $ do xs' <- traverse (resolveExprP 0 AnyExpr) xs pure (Call as' f' xs' x) resolveExprP p SemiExpr m@MethodCall{} = resolveExprP p AnyExpr m -resolveExprP p c m@(MethodCall as e i mt es x) = scope m $ parenE (p > 17) $ do +resolveExprP p c m@(MethodCall as e seg es x) = scope m $ parenE (p > 17) $ do as' <- traverse (resolveAttr OuterAttr) as --e' <- resolveExprP 17 (lhs c) e e' <- resolveLhsExprP 17 c e - i' <- resolveIdent i - mt' <- case mt of - Just t -> Just <$> traverse (resolveTy AnyType) t - Nothing -> pure Nothing + seg' <- resolvePathSegment seg es' <- traverse (resolveExprP 0 AnyExpr) es - pure (MethodCall as' e' i' mt' es' x) + pure (MethodCall as' e' seg' es' x) resolveExprP p SemiExpr t@TupField{} = resolveExprP p AnyExpr t resolveExprP p c t@(TupField as e i x) = scope t $ parenE (p > 17) $ do as' <- traverse (resolveAttr OuterAttr) as @@ -920,17 +955,24 @@ resolveExprP p c f@(FieldAccess as e i x) = scope f $ parenE (p > 17) $ do e' <- resolveLhsExprP 17 c e i' <- resolveIdent i pure (FieldAccess as' e' i' x) +resolveExprP p SemiExpr a@Await{} = resolveExprP p AnyExpr a +resolveExprP p c a@(Await as e x) = scope a $ parenE (p > 17) $ do + as' <- traverse (resolveAttr OuterAttr) as + --e' <- resolveExprP 17 (lhs c) e + e' <- resolveLhsExprP 17 c e + pure (Await as' e' x) -- Immediate expressions resolveExprP _ _ v@(Vec as es x) = scope v $ do as' <- traverse (resolveAttr EitherAttr) as es' <- traverse (resolveExprP 0 AnyExpr) es - pure (Vec as' es' x) + pure (Vec as' es' x) resolveExprP _ _ p@(PathExpr as Nothing p' x) = scope p $ do as' <- traverse (resolveAttr OuterAttr) as p'' <- resolvePath ExprPath p' pure (PathExpr as' Nothing p'' x) resolveExprP _ _ p@(PathExpr as q@(Just (QSelf _ i)) p'@(Path g s x) x') - | i < 0 || i >= length s = scope p (err p "index given by QSelf is outside the possible range") + | iMax <- if g then length s + 1 else length s + , i < 0 || i >= iMax = scope p (err p "index given by QSelf is outside the possible range") | i == 0 = scope p $ do as' <- traverse (resolveAttr OuterAttr) as q' <- traverse resolveQSelf q @@ -941,7 +983,7 @@ resolveExprP _ _ p@(PathExpr as q@(Just (QSelf _ i)) p'@(Path g s x) x') Path _ tyPSegs _ <- resolvePath TypePath $ Path g (take i s) mempty Path _ exprPSegs _ <- resolvePath ExprPath $ Path False (drop i s) x q' <- traverse resolveQSelf q - pure (PathExpr as' q' (Path g (tyPSegs <> exprPSegs) x) x') + pure (PathExpr as' q' (Path g (tyPSegs Sem.<> exprPSegs) x) x') resolveExprP _ _ i@(Lit as l x) = scope i $ do as' <- traverse (resolveAttr OuterAttr) as l' <- resolveLit l @@ -966,14 +1008,21 @@ resolveExprP _ _ t@(TupExpr as es x) = scope t $ do es' <- traverse (resolveExprP 0 AnyExpr) es pure (TupExpr as' es' x) -- Block expressions -resolveExprP _ NoStructBlockExpr e@BlockExpr{} = parenthesize e -resolveExprP _ _ l@(BlockExpr as b x) = scope l $ do +resolveExprP _ NoStructBlockExpr e@BlockExpr{} = parenthesizeE e +resolveExprP _ _ l@(BlockExpr as b l' x) = scope l $ do + as' <- traverse (resolveAttr EitherAttr) as + b' <- resolveBlock b + l'' <- traverse resolveLbl l' + pure (BlockExpr as' b' l'' x) +-- Async expressions +resolveExprP _ NoStructBlockExpr e@Async{} = parenthesizeE e +resolveExprP _ _ c@(Async as c' b x) = scope c $ do as' <- traverse (resolveAttr EitherAttr) as b' <- resolveBlock b - pure (BlockExpr as' b' x) + pure (Async as' c' b' x) -- Struct expressions -resolveExprP _ NoStructExpr e@Struct{} = parenthesize e -resolveExprP _ NoStructBlockExpr e@Struct{} = parenthesize e +resolveExprP _ NoStructExpr e@Struct{} = parenthesizeE e +resolveExprP _ NoStructBlockExpr e@Struct{} = parenthesizeE e resolveExprP _ _ s@(Struct as p' fs e x) = scope s $ do as' <- traverse (resolveAttr OuterAttr) as p'' <- resolvePath ExprPath p' @@ -989,20 +1038,20 @@ resolveExprP p c i@(If as e b es x) = scope i $ do Nothing -> pure Nothing (Just If{}) -> traverse (resolveExprP p c) es (Just IfLet{}) -> traverse (resolveExprP p c) es - (Just BlockExpr{}) -> traverse (resolveExprP p c) es - (Just e'') -> Just <$> resolveExprP p c (BlockExpr [] (Block [NoSemi e'' mempty] Normal mempty) mempty) + (Just (BlockExpr _ _ Nothing _)) -> traverse (resolveExprP p c) es + (Just e'') -> Just <$> resolveExprP p c (BlockExpr [] (Block [NoSemi e'' mempty] Normal mempty) Nothing mempty) pure (If as' e' b' es' x) resolveExprP p c i@(IfLet as p' e b es x) = scope i $ do as' <- traverse (resolveAttr OuterAttr) as - p'' <- traverse resolvePat p' + p'' <- resolvePat TopPattern p' e' <- resolveExprP 0 NoStructExpr e b' <- resolveBlock b es' <- case es of Nothing -> pure Nothing (Just If{}) -> traverse (resolveExprP p c) es (Just IfLet{}) -> traverse (resolveExprP p c) es - (Just BlockExpr{}) -> traverse (resolveExprP p c) es - (Just e'') -> Just <$> resolveExprP p c (BlockExpr [] (Block [NoSemi e'' mempty] Normal mempty) mempty) + (Just (BlockExpr _ _ Nothing _)) -> traverse (resolveExprP p c) es + (Just e'') -> Just <$> resolveExprP p c (BlockExpr [] (Block [NoSemi e'' mempty] Normal mempty) Nothing mempty) pure (IfLet as' p'' e' b' es' x) resolveExprP _ _ w@(While as e b l x) = scope w $ do as' <- traverse (resolveAttr EitherAttr) as @@ -1012,14 +1061,14 @@ resolveExprP _ _ w@(While as e b l x) = scope w $ do pure (While as' e' b' l' x) resolveExprP _ _ w@(WhileLet as p' e b l x) = scope w $ do as' <- traverse (resolveAttr EitherAttr) as - p'' <- traverse resolvePat p' + p'' <- resolvePat TopPattern p' e' <- resolveExprP 0 NoStructExpr e b' <- resolveBlock b l' <- traverse resolveLbl l pure (WhileLet as' p'' e' b' l' x) resolveExprP _ _ f@(ForLoop as p' e b l x) = scope f $ do as' <- traverse (resolveAttr EitherAttr) as - p'' <- resolvePat p' + p'' <- resolvePat TopPattern p' e' <- resolveExprP 0 NoStructExpr e b' <- resolveBlock b l' <- traverse resolveLbl l @@ -1034,10 +1083,10 @@ resolveExprP _ _ m@(Match as e ar x) = scope m $ do e' <- resolveExprP 0 AnyExpr e ar' <- traverse resolveArm ar pure (Match as' e' ar' x) -resolveExprP _ _ c@(Catch as b x) = scope c $ do +resolveExprP _ _ c@(TryBlock as b x) = scope c $ do as' <- traverse (resolveAttr EitherAttr) as b' <- resolveBlock b - pure (Catch as' b' x) + pure (TryBlock as' b' x) isBlockLike :: Expr a -> Bool isBlockLike If{} = True @@ -1048,33 +1097,35 @@ isBlockLike While{} = True isBlockLike WhileLet{} = True isBlockLike Match{} = True isBlockLike BlockExpr{} = True +isBlockLike Async{} = True isBlockLike _ = False resolveLbl :: Typeable a => Label a -> ResolveM (Label a) resolveLbl l@(Label n _) = scope l (resolveIdent (mkIdent n) *> pure l) -- | Wrap an expression in parens if the condition given holds -parenE :: (Typeable a, Monoid a) => Bool -> ResolveM (Expr a) -> ResolveM (Expr a) +parenE :: (Monoid a) => Bool -> ResolveM (Expr a) -> ResolveM (Expr a) parenE True e = ParenExpr [] <$> e <*> pure mempty parenE False e = e -- | A field just requires the identifier and expression to be valid resolveField :: (Typeable a, Monoid a) => Field a -> ResolveM (Field a) -resolveField f@(Field i e x) = scope f $ do +resolveField f@(Field i e as x) = scope f $ do i' <- resolveIdent i e' <- traverse (resolveExpr AnyExpr) e - pure (Field i' e' x) + as' <- traverse (resolveAttr OuterAttr) as + pure (Field i' e' as' x) instance (Typeable a, Monoid a) => Resolve (Field a) where resolveM = resolveField -- | Arms are invalid only if the underlying consitutents are resolveArm :: (Typeable a, Monoid a) => Arm a -> ResolveM (Arm a) -resolveArm a@(Arm as ps g b x) = scope a $ do +resolveArm a@(Arm as p g b x) = scope a $ do as' <- traverse (resolveAttr OuterAttr) as - ps' <- traverse resolvePat ps + p' <- resolvePat TopPattern p g' <- traverse (resolveExpr AnyExpr) g b' <- resolveExpr SemiExpr b - pure (Arm as' ps' g' b' x) + pure (Arm as' p' g' b' x) instance (Typeable a, Monoid a) => Resolve (Arm a) where resolveM = resolveArm @@ -1091,7 +1142,7 @@ data StmtType -- | Statements are invalid only when the underlying components are. resolveStmt :: (Typeable a, Monoid a) => StmtType -> Stmt a -> ResolveM (Stmt a) resolveStmt _ l@(Local p t i as x) = scope l $ do - p' <- resolvePat p + p' <- resolvePat TopPattern p t' <- traverse (resolveTy AnyType) t i' <- traverse (resolveExpr AnyExpr) i as' <- traverse (resolveAttr OuterAttr) as @@ -1101,11 +1152,12 @@ resolveStmt _ s@(Semi e x) | isBlockLike e = scope s (Semi <$> resolveExpr AnyEx resolveStmt _ s@(Semi e x) = scope s (Semi <$> resolveExpr SemiExpr e <*> pure x) resolveStmt _ n@(NoSemi e x) | isBlockLike e = scope n (NoSemi <$> resolveExpr AnyExpr e <*> pure x) resolveStmt AnyStmt n@(NoSemi e x) = scope n (NoSemi <$> resolveExpr SemiExpr e <*> pure x) -resolveStmt TermStmt n@(NoSemi e x) = scope n (NoSemi <$> resolveExpr AnyExpr (BlockExpr [] (Block [NoSemi e mempty] Normal mempty) mempty) <*> pure x) +resolveStmt TermStmt n@(NoSemi e x) = scope n (NoSemi <$> resolveExpr AnyExpr (BlockExpr [] (Block [NoSemi e mempty] Normal mempty) Nothing mempty) <*> pure x) resolveStmt _ a@(MacStmt m s as x) = scope a $ do - m' <- resolveMac ExprPath m + m' <- resolveMac ModPath m as' <- traverse (resolveAttr OuterAttr) as pure (MacStmt m' s as' x) +resolveStmt _ s@StandaloneSemi{} = pure s instance (Typeable a, Monoid a) => Resolve (Stmt a) where resolveM = resolveStmt AnyStmt @@ -1124,133 +1176,127 @@ instance (Typeable a, Monoid a) => Resolve (Block a) where resolveM = resolveBlo -- Items -- ----------- --- Whether the item is a statement item, or a general item data ItemType - = StmtItem -- ^ Corresponds to 'stmt_item' - basically limited visbility and no macros + = StmtItem -- ^ Corresponds to @stmt_item@ - basically no macros | ModItem -- ^ General item -resolveVisibility' :: Typeable a => ItemType -> Visibility a -> ResolveM (Visibility a) -resolveVisibility' StmtItem PublicV = pure PublicV -resolveVisibility' StmtItem InheritedV = pure InheritedV -resolveVisibility' StmtItem v = scope v $ err v "statement items can only have public or inherited visibility" -resolveVisibility' ModItem v = pure v - -- | An item can be invalid if -- -- * it is a macro but has 'StmtItem' restriction --- * it has visibility other than public/inherited but has 'StmtItem' restriction -- * an underlying component is invalid -- resolveItem :: (Typeable a, Monoid a) => ItemType -> Item a -> ResolveM (Item a) -resolveItem t e@(ExternCrate as v i r x) = scope e $ do +resolveItem _ e@(ExternCrate as v i r x) = scope e $ do + let resolveSelfIdent j | j == mkIdent "self" = pure j + | otherwise = resolveIdent j as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v - i' <- resolveIdent i - r' <- traverse resolveIdent r + v' <- resolveVisibility v + i' <- if isJust r then resolveIdent i else resolveSelfIdent i + r' <- traverse resolveSelfIdent r pure (ExternCrate as' v' i' r' x) -resolveItem t u@(Use as v p x) = scope u $ do +resolveItem _ u@(Use as v p x) = scope u $ do as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v p' <- resolveUseTree p pure (Use as' v' p' x) -resolveItem t s@(Static as v i t' m e x) = scope s $ do +resolveItem _ s@(Static as v i t' m e x) = scope s $ do as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i t'' <- resolveTy AnyType t' e' <- resolveExpr AnyExpr e pure (Static as' v' i' t'' m e' x) -resolveItem t c@(ConstItem as v i t' e x) = scope c $ do +resolveItem _ c@(ConstItem as v i t' e x) = scope c $ do as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i t'' <- resolveTy AnyType t' e' <- resolveExpr AnyExpr e pure (ConstItem as' v' i' t'' e' x) -resolveItem t f@(Fn as v i d u c a g b x) = scope f $ do +resolveItem _ f@(Fn as v i d h g b x) = scope f $ do as' <- traverse (resolveAttr EitherAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i d' <- resolveFnDecl NoSelf NamedArg d g' <- resolveGenerics g b' <- resolveBlock b - pure (Fn as' v' i' d' u c a g' b' x) + pure (Fn as' v' i' d' h g' b' x) -resolveItem t m@(Mod as v i (Just is) x) = scope m $ do +resolveItem _ m@(Mod as v i (Just is) x) = scope m $ do as' <- traverse (resolveAttr EitherAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i is' <- traverse (resolveItem ModItem) is pure (Mod as' v' i' (Just is') x) -resolveItem t m@(Mod as v i Nothing x) = scope m $ do +resolveItem _ m@(Mod as v i Nothing x) = scope m $ do as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i pure (Mod as' v' i' Nothing x) -resolveItem t m@(ForeignMod as v a is x) = scope m $ do +resolveItem _ m@(ForeignMod as v a is x) = scope m $ do as' <- traverse (resolveAttr EitherAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v is' <- traverse (resolveForeignItem a) is pure (ForeignMod as' v' a is' x) -resolveItem t a@(TyAlias as v i t' g x) = scope a $ do +resolveItem _ a@(TyAlias as v i t' g x) = scope a $ do as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i t'' <- resolveTy AnyType t' g' <- resolveGenerics g pure (TyAlias as' v' i' t'' g' x) -resolveItem t e@(Enum as v i vs g x) = scope e $ do +resolveItem _ e@(Enum as v i vs g x) = scope e $ do as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i vs' <- traverse resolveVariant vs g' <- resolveGenerics g pure (Enum as' v' i' vs' g' x) - -resolveItem t s@(StructItem as v i vd g x) = scope s $ do + +resolveItem _ s@(StructItem as v i vd g x) = scope s $ do as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i vd' <- resolveVariantData vd g' <- resolveGenerics g pure (StructItem as' v' i' vd' g' x) -resolveItem t u@(Union as v i vd g x) = scope u $ do +resolveItem _ u@(Union as v i vd g x) = scope u $ do as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i vd' <- resolveVariantData vd g' <- resolveGenerics g pure (Union as' v' i' vd' g' x) -resolveItem t r@(Trait as v i a u g bd is x) = scope r $ do +resolveItem _ r@(Trait as v i a u g bd is x) = scope r $ do as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i g' <- resolveGenerics g - bd' <- traverse (resolveTyParamBound NoneBound) bd + bd' <- traverse (resolveGenericBound NoneBound) bd is' <- traverse resolveTraitItem is pure (Trait as' v' i' a u g' bd' is' x) -resolveItem t r@(TraitAlias as v i g bd x) = scope r $ do +resolveItem _ r@(TraitAlias as v i g bd x) = scope r $ do as' <- traverse (resolveAttr OuterAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v i' <- resolveIdent i g' <- resolveGenerics g - bd' <- traverse (resolveTyParamBound NoneBound) bd + bd' <- traverse (resolveGenericBound ModBound) bd pure (TraitAlias as' v' i' g' bd' x) -resolveItem t i'@(Impl as v d u i g mt t' is x) = scope i' $ do +resolveItem _ i'@(Impl as v d u i g mt t' is x) = scope i' $ do as' <- traverse (resolveAttr EitherAttr) as - v' <- resolveVisibility' t v + v' <- resolveVisibility v g' <- resolveGenerics g mt' <- traverse resolveTraitRef mt t'' <- case mt of @@ -1260,21 +1306,21 @@ resolveItem t i'@(Impl as v d u i g mt t' is x) = scope i' $ do pure (Impl as' v' d u i g' mt' t'' is' x) resolveItem StmtItem m@MacItem{} = scope m (err m "macro items cannot be in statement items") -resolveItem _ a@(MacItem as i m x) = scope a $ do +resolveItem _ a@(MacItem as m x) = scope a $ do as' <- traverse (resolveAttr OuterAttr) as - i' <- traverse resolveIdent i m' <- resolveMac ExprPath m - pure (MacItem as' i' m' x) + pure (MacItem as' m' x) -resolveItem _ m@(MacroDef as i ts x) = scope m $ do +resolveItem _ m@(MacroDef as v i ts x) = scope m $ do as' <- traverse (resolveAttr OuterAttr) as + v' <- resolveVisibility v i' <- resolveIdent i ts' <- resolveTokenStream ts - pure (MacroDef as' i' ts' x) + pure (MacroDef as' v' i' ts' x) instance (Typeable a, Monoid a) => Resolve (Item a) where resolveM = resolveItem ModItem --- | A foreign item is invalid only if any of its underlying constituents are +-- | A foreign item is invalid only if any of its underlying constituents are resolveForeignItem :: (Typeable a, Monoid a) => Abi -> ForeignItem a -> ResolveM (ForeignItem a) resolveForeignItem a f@(ForeignFn as v i fn g x) = scope f $ do as' <- traverse (resolveAttr OuterAttr) as @@ -1294,6 +1340,10 @@ resolveForeignItem _ f@(ForeignTy as v i x) = scope f $ do v' <- resolveVisibility v i' <- resolveIdent i pure (ForeignTy as' v' i' x) +resolveForeignItem _ f@(ForeignMac as m x) = scope f $ do + as' <- traverse (resolveAttr OuterAttr) as + m' <- resolveMac ModPath m + pure (ForeignMac as' m' x) instance (Typeable a, Monoid a) => Resolve (ForeignItem a) where resolveM = resolveForeignItem C @@ -1305,24 +1355,38 @@ instance (Typeable a, Monoid a) => Resolve (WhereClause a) where resolveM = reso -- | Generics are only invalid if the underlying lifetimes or type parameters are resolveGenerics :: (Typeable a, Monoid a) => Generics a -> ResolveM (Generics a) -resolveGenerics g@(Generics lts typ wc x) = scope g $ do - lts' <- traverse resolveLifetimeDef lts - typ' <- traverse resolveTyParam typ +resolveGenerics g@(Generics params wc x) = scope g $ do + params' <- if isSorted genericParamOrder params + then pure params + else do correct "sorted generic parameters" + pure (sortBy genericParamOrder params) + params'' <- traverse resolveGenericParam params' wc' <- resolveWhereClause wc - pure (Generics lts' typ' wc' x) + pure (Generics params'' wc' x) instance (Typeable a, Monoid a) => Resolve (Generics a) where resolveM = resolveGenerics -- | A type parameter is invalid only when the underlying components are -resolveTyParam :: (Typeable a, Monoid a) => TyParam a -> ResolveM (TyParam a) -resolveTyParam p@(TyParam as i bds t x) = scope p $ do +resolveGenericParam :: (Typeable a, Monoid a) => GenericParam a -> ResolveM (GenericParam a) +resolveGenericParam p@(TypeParam as i bds t x) = scope p $ do as' <- traverse (resolveAttr OuterAttr) as i' <- resolveIdent i - bds' <- traverse (resolveTyParamBound ModBound) bds + bds' <- traverse (resolveGenericBound ModBound) bds t' <- traverse (resolveTy AnyType) t - pure (TyParam as' i' bds' t' x) + pure (TypeParam as' i' bds' t' x) +resolveGenericParam lts@(LifetimeParam as l bds x) = scope lts $ do + as' <- traverse (resolveAttr OuterAttr) as + l' <- resolveLifetime l + bds' <- traverse (resolveGenericBound OnlyLifetimes) bds + pure (LifetimeParam as' l' bds' x) +resolveGenericParam lts@(ConstParam as i t x) = scope lts $ do + as' <- traverse (resolveAttr OuterAttr) as + i' <- resolveIdent i + t' <- resolveTy AnyType t + pure (ConstParam as' i' t' x) + +instance (Typeable a, Monoid a) => Resolve (GenericParam a) where resolveM = resolveGenericParam -instance (Typeable a, Monoid a) => Resolve (TyParam a) where resolveM = resolveTyParam -- Invariants for struct fields data StructFieldType @@ -1379,9 +1443,9 @@ resolveWherePredicate p@(RegionPredicate l ls x) = scope p $ do ls' <- traverse resolveLifetime ls pure (RegionPredicate l' ls' x) resolveWherePredicate p@(BoundPredicate lts t bds x) = scope p $ do - lts' <- traverse resolveLifetimeDef lts + lts' <- traverse resolveGenericParam lts t' <- resolveTy NoForType t - bds' <- traverse (resolveTyParamBound ModBound) bds + bds' <- traverse (resolveGenericBound ModBound) bds pure (BoundPredicate lts' t' bds' x) instance (Typeable a, Monoid a) => Resolve (WherePredicate a) where resolveM = resolveWherePredicate @@ -1398,13 +1462,13 @@ resolveTraitItem n@(MethodT as i g m b x) = scope n $ do as' <- traverse (resolveAttr OuterAttr) as i' <- resolveIdent i g' <- resolveGenerics g - m' <- resolveMethodSig GeneralArg m + m' <- resolveMethodSig NamedArg m b' <- traverse resolveBlock b pure (MethodT as' i' g' m' b' x) resolveTraitItem n@(TypeT as i bd t x) = scope n $ do as' <- traverse (resolveAttr OuterAttr) as i' <- resolveIdent i - bd' <- traverse (resolveTyParamBound ModBound) bd + bd' <- traverse (resolveGenericBound ModBound) bd t' <- traverse (resolveTy AnyType) t pure (TypeT as' i' bd' t' x) resolveTraitItem n@(MacroT as m x) = scope n $ do @@ -1428,7 +1492,7 @@ resolveImplItem n@(MethodI as v d i g m b x) = scope n $ do v' <- resolveVisibility v i' <- resolveIdent i g' <- resolveGenerics g - m' <- resolveMethodSig NamedArg m + m' <- resolveMethodSig NamedArg m b' <- resolveBlock b pure (MethodI as' v' d i' g' m' b' x) resolveImplItem n@(TypeI as v d i t x) = scope n $ do @@ -1456,19 +1520,19 @@ instance (Typeable a, Monoid a) => Resolve (Visibility a) where resolveM = resol -- | A method signature is valid if the underlying components are resolveMethodSig :: (Typeable a, Monoid a) => ArgType -> MethodSig a -> ResolveM (MethodSig a) -resolveMethodSig at m@(MethodSig u c a f) = scope m (MethodSig u c a <$> resolveFnDecl AllowSelf at f) +resolveMethodSig at m@(MethodSig h f) = scope m (MethodSig h <$> resolveFnDecl AllowSelf at f) instance (Typeable a, Monoid a) => Resolve (MethodSig a) where resolveM = resolveMethodSig NamedArg -- | A view path is valid if the underlying components are resolveUseTree :: (Typeable a, Monoid a) => UseTree a -> ResolveM (UseTree a) resolveUseTree v@(UseTreeSimple p i x) = scope v $ do - p' <- resolvePath ModPath p + p' <- resolvePath ModPath p i' <- traverse resolveIdent i pure (UseTreeSimple p' i' x) resolveUseTree v@(UseTreeGlob p x) = scope v $ do - p' <- resolvePath UsePath p - pure (UseTreeGlob p' x) + p' <- resolvePath UsePath p + pure (UseTreeGlob p' x) resolveUseTree v@(UseTreeNested p ns x) = scope v $ do p' <- resolvePath UsePath p ns' <- traverse resolveUseTree ns @@ -1486,7 +1550,7 @@ resolveMac :: (Typeable a, Monoid a) => PathType -> Mac a -> ResolveM (Mac a) resolveMac t m@(Mac p ts x) = scope m (Mac <$> resolvePath t p <*> resolveTokenStream ts <*> pure x) instance (Typeable a, Monoid a) => Resolve (Mac a) where - resolveM m@(Mac p ts x) = scope m (Mac <$> resolveM p <*> resolveTokenStream ts <*> pure x) + resolveM m@(Mac p ts x) = scope m (Mac <$> resolveM p <*> resolveTokenStream ts <*> pure x) -- | A token tree is invalid when -- @@ -1507,3 +1571,15 @@ resolveTokenStream s@(Stream ts) = scope s (Stream <$> mapM resolveTokenStream t instance Resolve TokenStream where resolveM = resolveTokenStream + + +------------- +-- Utility -- +------------- + +-- Check in a manner that shortcuts if a list is already sorted +isSorted :: (a -> a -> Ordering) -> [a] -> Bool +isSorted _ [] = True +isSorted f (w:ws) = go w ws + where go _ [] = True + go y (z:zs) = ((y `f` z) /= GT) && go z zs diff --git a/src/Language/Rust/Pretty/Util.hs b/src/Language/Rust/Pretty/Util.hs index 509c62d..25818a8 100644 --- a/src/Language/Rust/Pretty/Util.hs +++ b/src/Language/Rust/Pretty/Util.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Pretty.Util Description : pretty printing utilities -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -49,10 +49,10 @@ d1 <##> d2 = d1 M.<> PP.line' M.<> d2 -- | Flatten a 'Doc' flatten :: Doc a -> Doc a flatten d@Fail{} = d -flatten d@Empty{} = d -flatten d@Char{} = d -flatten d@Text{} = d -flatten d@Line{} = d +flatten d@Empty{} = d +flatten d@Char{} = d +flatten d@Text{} = d +flatten d@Line{} = d flatten (FlatAlt _ d) = d flatten (Cat d1 d2) = Cat (flatten d1) (flatten d2) flatten (Nest i d) = Nest i (flatten d) @@ -83,6 +83,7 @@ hsep = foldr (<+>) mempty -- | Lifted version of Wadler's @<#>@ (<#>) :: Doc a -> Doc a -> Doc a (<#>) = liftOp (\x y -> x <> PP.line <> y) +infixl 8 <#> -- | Lifted version of Wadler's @vsep@ vsep :: Foldable f => f (Doc a) -> Doc a @@ -118,7 +119,7 @@ ungroup y = y noIndent :: Doc a -> Doc a noIndent d = PP.nesting (\i -> PP.nest (negate i) d) --- | Translate '\n' in a string using the provided 'Doc' instead of 'line' +-- | Translate '\n' in a string using the provided 'Doc' instead of 'PP.line' string :: Doc a -> String -> Doc a string new = foldMap (\c -> case c of { '\n' -> new; _ -> Char c }) @@ -129,7 +130,7 @@ string new = foldMap (\c -> case c of { '\n' -> new; _ -> Char c }) -- Note that this will try to fit things on one line when possible, so if you want a block that is -- sure /not/ to be condensed on one line (e.g. for a function), you have to construct it manually. block :: Delim -- ^ outer delimiters - -> Bool -- ^ prefer to be on one line (as opposed to multiline)? + -> Bool -- ^ prefer to be on one line (as opposed to multiline)? -> Doc a -- ^ seperator -> Doc a -- ^ attributes doc, after which no seperator will (use 'mempty' to ignore) -> [Doc a] -- ^ entries @@ -157,5 +158,5 @@ block delim p s as xs = group' (lDel # PP.vsep (as' ++ ys) # rDel) ys = go xs where go [] = [] go [z] = [ PP.flatAlt (PP.indent n z <> s) (flatten z) ] go (z:zs) = PP.flatAlt (PP.indent n z <> s) (flatten z <> s) : go zs - + diff --git a/src/Language/Rust/Quote.hs b/src/Language/Rust/Quote.hs index d80a3ad..fd0e5e1 100644 --- a/src/Language/Rust/Quote.hs +++ b/src/Language/Rust/Quote.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Quote Description : Quasiquotes for Rust AST -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -23,7 +23,7 @@ The examples below assume the following GHCi flag and import: module Language.Rust.Quote ( - lit, attr, ty, pat, stmt, expr, item, sourceFile, implItem, traitItem, tokenTree, block + lit, attr, ty, pat, path, stmt, expr, item, sourceFile, implItem, traitItem, tokenTree, block ) where {- @@ -77,7 +77,7 @@ quoter p = QuasiQuoter -- | Given a parser and an input string, turn it into the corresponding Haskell expression/pattern. parse inp = do Loc{ loc_start = (r,c) } <- location - + -- Run the parser case execParser p (inputStreamFromString inp) (Position 0 r c) of Left (ParseFail _ msg) -> fail msg @@ -114,13 +114,21 @@ ty = quoter parseTy -- | Quasiquoter for patterns (see 'Language.Rust.Syntax.Pat') -- --- >>> void [pat| x @ 1...5 |] +-- >>> void [pat| x @ 1..=5 |] -- IdentP (ByValue Immutable) "x" (Just (RangeP (Lit [] (Int Dec 1 Unsuffixed ()) ()) --- (Lit [] (Int Dec 5 Unsuffixed ()) ()) ())) () +-- (Lit [] (Int Dec 5 Unsuffixed ()) ()) +-- Closed +-- ())) () -- pat :: QuasiQuoter pat = quoter parsePat +-- | Quasiquoter for paths (see 'Language.Rust.Syntax.Path') +-- +-- TODO example: +path :: QuasiQuoter +path = quoter parsePath + -- | Quasiquoter for statements (see 'Language.Rust.Syntax.Stmt') -- -- >>> void [stmt| let x = 4i32; |] diff --git a/src/Language/Rust/Syntax.hs b/src/Language/Rust/Syntax.hs index 50040cc..b881a34 100644 --- a/src/Language/Rust/Syntax.hs +++ b/src/Language/Rust/Syntax.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Syntax Description : Syntax data defintions -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -10,8 +10,7 @@ Portability : GHC This module defines Haskell data types corresponding to the abstract syntax tree(s) of the Rust language, based on the definitions @rustc@ uses (defined in @libsyntax@) whenever possible. Unfortunately, since the internals of @rustc@ are not exposed, there are no official -docs. are the -unofficial docs. +The official docs are: . -} module Language.Rust.Syntax ( @@ -22,7 +21,7 @@ module Language.Rust.Syntax ( ) where import Language.Rust.Syntax.AST -import Language.Rust.Syntax.Token +import Language.Rust.Syntax.Token -- Using import/export shortcut screws up Haddock {-# ANN module "HLint: ignore Use import/export shortcut" #-} diff --git a/src/Language/Rust/Syntax/AST.hs b/src/Language/Rust/Syntax/AST.hs index 1ddeed0..30acbbc 100644 --- a/src/Language/Rust/Syntax/AST.hs +++ b/src/Language/Rust/Syntax/AST.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Syntax.AST Description : Non-token AST definitions -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -21,10 +21,14 @@ module Language.Rust.Syntax.AST ( Unsafety(..), Arg(..), FnDecl(..), + FnHeader(..), -- ** Paths Path(..), - PathParameters(..), + GenericArg(..), + genericArgOrder, + GenericArgs(..), + AssocTyConstraint(..), PathSegment(..), QSelf(..), @@ -44,6 +48,7 @@ module Language.Rust.Syntax.AST ( Expr(..), Abi(..), Arm(..), + IsAsync(..), UnOp(..), BinOp(..), Label(..), @@ -56,10 +61,10 @@ module Language.Rust.Syntax.AST ( Ty(..), Generics(..), Lifetime(..), - LifetimeDef(..), - TyParam(..), - TyParamBound(..), - partitionTyParamBounds, + GenericParam(..), + genericParamOrder, + GenericBound(..), + partitionGenericBounds, WhereClause(..), whereClause, WherePredicate(..), @@ -115,6 +120,7 @@ import Data.Typeable ( Typeable ) import Data.Char ( ord ) import Data.List ( partition ) import Data.List.NonEmpty ( NonEmpty(..) ) +import Data.Ord ( comparing ) import Data.Semigroup as Sem ( Semigroup(..) ) import Data.Word ( Word8 ) @@ -128,6 +134,7 @@ data Abi = Cdecl | Stdcall | Fastcall + | Thiscall | Vectorcall | Aapcs | Win64 @@ -135,6 +142,7 @@ data Abi | PtxKernel | Msp430Interrupt | X86Interrupt + | AmdGpuKernel -- Cross-platform ABIs | Rust | C @@ -154,7 +162,7 @@ data Abi -- trait Foo { -- // Regular argument -- fn new(x: usize) -> Foo; --- +-- -- // Self argument, by value -- fn foo(self) -> i32; -- fn bar(mut self); @@ -168,17 +176,17 @@ data Abi -- } -- @ data Arg a - = Arg (Maybe (Pat a)) (Ty a) a -- ^ Regular argument - | SelfValue Mutability a -- ^ Self argument, by value - | SelfRegion (Maybe (Lifetime a)) Mutability a -- ^ Self argument, by reference - | SelfExplicit (Ty a) Mutability a -- ^ Explicit self argument + = Arg [Attribute a] (Maybe (Pat a)) (Ty a) a -- ^ Regular argument + | SelfValue [Attribute a] Mutability a -- ^ Self argument, by value + | SelfRegion [Attribute a] (Maybe (Lifetime a)) Mutability a -- ^ Self argument, by reference + | SelfExplicit [Attribute a] (Ty a) Mutability a -- ^ Explicit self argument deriving (Eq, Ord, Show, Functor, Typeable, Data, Generic, Generic1, NFData) instance Located a => Located (Arg a) where - spanOf (Arg _ _ s) = spanOf s - spanOf (SelfValue _ s) = spanOf s - spanOf (SelfRegion _ _ s) = spanOf s - spanOf (SelfExplicit _ _ s) = spanOf s + spanOf (Arg _ _ _ s) = spanOf s + spanOf (SelfValue _ _ s) = spanOf s + spanOf (SelfRegion _ _ _ s) = spanOf s + spanOf (SelfExplicit _ _ _ s) = spanOf s -- | An arm of a 'Match' expression (@syntax::ast::Arm@). An arm has at least one patten, possibly a -- guard expression, and a body expression. @@ -192,11 +200,23 @@ instance Located a => Located (Arg a) where -- _ => println!("{} % 2 = 0", n) -- } -- @ -data Arm a = Arm [Attribute a] (NonEmpty (Pat a)) (Maybe (Expr a)) (Expr a) a +data Arm a = Arm [Attribute a] (Pat a) (Maybe (Expr a)) (Expr a) a deriving (Eq, Ord, Show, Functor, Typeable, Data, Generic, Generic1, NFData) instance Located a => Located (Arm a) where spanOf (Arm _ _ _ _ s) = spanOf s +-- | A constraint on an associated type +data AssocTyConstraint a + -- | E.g., @A = Bar@ in @Foo\@ + = EqualityConstraint Ident (Ty a) a + -- | E.g. @A: TraitA + TraitB@ in @Foo\@ + | BoundConstraint Ident (NonEmpty (GenericBound a)) a + deriving (Eq, Ord, Show, Functor, Typeable, Data, Generic, Generic1, NFData) + +instance Located a => Located (AssocTyConstraint a) where + spanOf (EqualityConstraint _ _ s) = spanOf s + spanOf (BoundConstraint _ _ s) = spanOf s + -- | 'Attribute's are annotations for other AST nodes (@syntax::ast::Attribute@). Note that -- doc-comments are promoted to attributes. -- @@ -209,8 +229,8 @@ instance Located a => Located (Arm a) where spanOf (Arm _ _ _ _ s) = spanOf s data Attribute a -- | Regular attributes of the form @#[...]@ = Attribute AttrStyle (Path a) TokenStream a - -- | Doc comment attributes. The 'Bool' argument identifies if the comment is inline or not, and - -- the 'Name' contains the actual doc comment content. + -- | Doc comment attributes. The 'Prelude.Bool' argument identifies if the comment is inline or + -- not, and the 'Name' contains the actual doc comment content. | SugaredDoc AttrStyle Bool Name a deriving (Eq, Ord, Show, Functor, Typeable, Data, Generic, Generic1, NFData) @@ -252,7 +272,7 @@ data BinOp deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) -- | Describes how a value bound to an identifier in a pattern is going to be borrowed --- (@syntax::ast::BindingMode@). +-- (@syntax::ast::BindingMode@). -- -- Example: @&mut@ in @|&mut x: i32| -> { x += 1 }@ data BindingMode @@ -268,7 +288,7 @@ data Block a = Block [Stmt a] Unsafety a deriving (Eq, Ord, Show, Functor, Typeable, Data, Generic, Generic1, NFData) instance Located a => Located (Block a) where spanOf (Block _ _ s) = spanOf s - + -- | Describes how a 'Closure' should close over its free variables (@syntax::ast::CaptureBy@). data CaptureBy = Value -- ^ make copies of free variables closed over (@move@ closures) @@ -277,12 +297,12 @@ data CaptureBy -- | Const annotation to specify if a function or method is allowed to be called in constants -- context with constant arguments (@syntax::ast::Constness@). [Relevant --- RFC](https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md) +-- RFC](https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md) -- -- Example: @const@ in @const fn inc(x: i32) -> i32 { x + 1 }@ data Constness = Const | NotConst deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) --- | An 'ImplItem' can be marked @default@ (@syntax::ast::Defaultness@). +-- | An 'ImplItem' can be marked @default@ (@syntax::ast::Defaultness@). data Defaultness = Default | Final deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) -- | Expression (@syntax::ast::Expr@). Note that Rust pushes into expressions an unusual number @@ -290,8 +310,6 @@ data Defaultness = Default | Final deriving (Eq, Ord, Enum, Bounded, Show, Typea data Expr a -- | box expression (example: @box x@) = Box [Attribute a] (Expr a) a - -- | in-place expression - first 'Expr' is the place, second one is the value (example: @x <- y@) - | InPlace [Attribute a] (Expr a) (Expr a) a -- | array literal (example: @[a, b, c, d]@) | Vec [Attribute a] [Expr a] a -- | function call where the first 'Expr' is the function itself, and the @['Expr']@ is the list of @@ -300,7 +318,7 @@ data Expr a -- | method call where the first 'Expr' is the receiver, 'Ident' is the method name, @Maybe ['Ty']@ -- the list of type arguments and '[Expr]' the arguments to the method. -- (example: @x.foo::\(a, b, c, d)@ - | MethodCall [Attribute a] (Expr a) Ident (Maybe [Ty a]) [Expr a] a + | MethodCall [Attribute a] (Expr a) (PathSegment a) [Expr a] a -- | tuple (example: @(a, b, c ,d)@) | TupExpr [Attribute a] [Expr a] a -- | binary operation (example: @a + b@, @a * b@) @@ -311,17 +329,17 @@ data Expr a | Lit [Attribute a] (Lit a) a -- | cast (example: @foo as f64@) | Cast [Attribute a] (Expr a) (Ty a) a - -- | type annotation (example: @x: i32@) + -- | type annotation (example: @x: i32@) | TypeAscription [Attribute a] (Expr a) (Ty a) a -- | if expression, with an optional @else@ block. In the case the @else@ block is missing, the -- type of the @if@ is inferred to be @()@. (example: @if 1 == 2 { (1,1) } else { (2,2) }@ | If [Attribute a] (Expr a) (Block a) (Maybe (Expr a)) a -- | if-let expression with an optional else block (example: @if let Some(x) = None { () }@) - | IfLet [Attribute a] (NonEmpty (Pat a)) (Expr a) (Block a) (Maybe (Expr a)) a + | IfLet [Attribute a] (Pat a) (Expr a) (Block a) (Maybe (Expr a)) a -- | while loop, with an optional label (example: @'lbl: while 1 == 1 { break 'lbl }@) | While [Attribute a] (Expr a) (Block a) (Maybe (Label a)) a -- | while-let loop, with an optional label (example: @while let Some(x) = None { x }@) - | WhileLet [Attribute a] (NonEmpty (Pat a)) (Expr a) (Block a) (Maybe (Label a)) a + | WhileLet [Attribute a] (Pat a) (Expr a) (Block a) (Maybe (Label a)) a -- | for loop, with an optional label (example: @for i in 1..10 { println!("{}",i) }@) | ForLoop [Attribute a] (Pat a) (Expr a) (Block a) (Maybe (Label a)) a -- | conditionless loop (can be exited with 'Break', 'Continue', or 'Ret') @@ -329,11 +347,15 @@ data Expr a -- | match block | Match [Attribute a] (Expr a) [Arm a] a -- | closure (example: @move |a, b, c| { a + b + c }@) - | Closure [Attribute a] Movability CaptureBy (FnDecl a) (Expr a) a + | Closure [Attribute a] CaptureBy IsAsync Movability (FnDecl a) (Expr a) a -- | (possibly unsafe) block (example: @unsafe { 1 }@) - | BlockExpr [Attribute a] (Block a) a - -- | a catch block (example: @do catch { 1 }@) - | Catch [Attribute a] (Block a) a + | BlockExpr [Attribute a] (Block a) (Maybe (Label a)) a + -- | a try block (example: @try { 1 }@) + | TryBlock [Attribute a] (Block a) a + -- | an async block (example: @async move { 1 }@) + | Async [Attribute a] CaptureBy (Block a) a + -- | an await expression (example: @foo(1,2,3).await@) + | Await [Attribute a] (Expr a) a -- | assignment (example: @a = foo()@) | Assign [Attribute a] (Expr a) (Expr a) a -- | assignment with an operator (example: @a += 1@) @@ -346,12 +368,12 @@ data Expr a | Index [Attribute a] (Expr a) (Expr a) a -- | range (examples: @1..2@, @1..@, @..2@, @1...2@, @1...@, @...2@) | Range [Attribute a] (Maybe (Expr a)) (Maybe (Expr a)) RangeLimits a - -- | variable reference + -- | variable reference | PathExpr [Attribute a] (Maybe (QSelf a)) (Path a) a -- | referencing operation (example: @&a or &mut a@) | AddrOf [Attribute a] Mutability (Expr a) a -- | @break@ with an optional label and expression denoting what to break out of and what to - -- return (example: @break 'lbl 1@) + -- return (example: @break 'lbl 1@) | Break [Attribute a] (Maybe (Label a)) (Maybe (Expr a)) a -- | @continue@ with an optional label (example: @continue@) | Continue [Attribute a] (Maybe (Label a)) a @@ -373,10 +395,9 @@ data Expr a instance Located a => Located (Expr a) where spanOf (Box _ _ s) = spanOf s - spanOf (InPlace _ _ _ s) = spanOf s spanOf (Vec _ _ s) = spanOf s spanOf (Call _ _ _ s) = spanOf s - spanOf (MethodCall _ _ _ _ _ s) = spanOf s + spanOf (MethodCall _ _ _ _ s) = spanOf s spanOf (TupExpr _ _ s) = spanOf s spanOf (Binary _ _ _ _ s) = spanOf s spanOf (Unary _ _ _ s) = spanOf s @@ -390,9 +411,11 @@ instance Located a => Located (Expr a) where spanOf (ForLoop _ _ _ _ _ s) = spanOf s spanOf (Loop _ _ _ s) = spanOf s spanOf (Match _ _ _ s) = spanOf s - spanOf (Closure _ _ _ _ _ s) = spanOf s - spanOf (BlockExpr _ _ s) = spanOf s - spanOf (Catch _ _ s) = spanOf s + spanOf (Closure _ _ _ _ _ _ s) = spanOf s + spanOf (BlockExpr _ _ _ s) = spanOf s + spanOf (TryBlock _ _ s) = spanOf s + spanOf (Async _ _ _ s) = spanOf s + spanOf (Await _ _ s) = spanOf s spanOf (Assign _ _ _ s) = spanOf s spanOf (AssignOp _ _ _ _ s) = spanOf s spanOf (FieldAccess _ _ _ s) = spanOf s @@ -414,22 +437,22 @@ instance Located a => Located (Expr a) where -- | Field in a struct literal expression (@syntax::ast::Field@). -- -- Example: @x: 1@ in @Point { x: 1, y: 2 }@ -data Field a = Field Ident (Maybe (Expr a)) a +data Field a = Field Ident (Maybe (Expr a)) [Attribute a] a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) -instance Located a => Located (Field a) where spanOf (Field _ _ s) = spanOf s +instance Located a => Located (Field a) where spanOf (Field _ _ _ s) = spanOf s -- | Field in a struct literal pattern (@syntax::ast::FieldPat@). The field name 'Ident' is optional -- but, when it is 'Nothing', the pattern the field is destructured to must be 'IdentP'. -- -- Example: @x@ in @Point { x, y }@ -data FieldPat a = FieldPat (Maybe Ident) (Pat a) a +data FieldPat a = FieldPat (Maybe Ident) (Pat a) [Attribute a] a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) -instance Located a => Located (FieldPat a) where spanOf (FieldPat _ _ s) = spanOf s +instance Located a => Located (FieldPat a) where spanOf (FieldPat _ _ _ s) = spanOf s --- | Header (not the body) of a function declaration (@syntax::ast::FnDecl@). The 'Bool' argument --- indicates whether the header is variadic (so whether the argument list ends in @...@). +-- | Header (not the body) of a function declaration (@syntax::ast::FnDecl@). The 'Prelude.Bool' +-- argument indicates whether the header is variadic (so whether the argument list ends in @...@). -- -- Example: @(bar: i32) -> i32@ as in -- @@ -443,6 +466,13 @@ data FnDecl a = FnDecl [Arg a] (Maybe (Ty a)) Bool a instance Located a => Located (FnDecl a) where spanOf (FnDecl _ _ _ s) = spanOf s +-- | A function header, as seen on a method or function. All of the information between the +-- visibility and the name of the funciton is included in this struct. +data FnHeader a = FnHeader Unsafety IsAsync Constness Abi a + deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) + +instance Located a => Located (FnHeader a) where spanOf (FnHeader _ _ _ _ s) = spanOf s + -- | An item within an extern block (@syntax::ast::ForeignItem@ with @syntax::ast::ForeignItemKind@ -- inlined). -- @@ -460,12 +490,17 @@ data ForeignItem a -- -- Example: @type Boo;@ | ForeignTy [Attribute a] (Visibility a) Ident a + -- | Macro call + -- + -- Example: @foo!{ .. }@ + | ForeignMac [Attribute a] (Mac a) a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) instance Located a => Located (ForeignItem a) where spanOf (ForeignFn _ _ _ _ _ s) = spanOf s spanOf (ForeignStatic _ _ _ _ _ s) = spanOf s spanOf (ForeignTy _ _ _ s) = spanOf s + spanOf (ForeignMac _ _ s) = spanOf s -- | Represents lifetimes and type parameters attached to a declaration of a functions, enums, -- traits, etc. (@syntax::ast::Generics@). Note that lifetime definitions are always required to be @@ -479,28 +514,54 @@ instance Located a => Located (ForeignItem a) where -- -- @ -- fn nonsense\<\'a, \'b: \'c, T: \'a\>(x: i32) -\> i32 --- where Option\: Copy { +-- where Option\: Copy { -- 1 -- }@. -data Generics a = Generics [LifetimeDef a] [TyParam a] (WhereClause a) a +data Generics a = Generics [GenericParam a] (WhereClause a) a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) -- | Extract the where clause from a 'Generics'. whereClause :: Generics a -> WhereClause a -whereClause (Generics _ _ wc _) = wc +whereClause (Generics _ wc _) = wc -instance Located a => Located (Generics a) where spanOf (Generics _ _ _ s) = spanOf s +instance Located a => Located (Generics a) where spanOf (Generics _ _ s) = spanOf s instance Sem.Semigroup a => Sem.Semigroup (Generics a) where - Generics lt1 tp1 wc1 x1 <> Generics lt2 tp2 wc2 x2 = Generics lts tps wcs xs - where lts = lt1 ++ lt2 - tps = tp1 ++ tp2 + Generics prm1 wc1 x1 <> Generics prm2 wc2 x2 = Generics prm wcs xs + where prm = prm1 ++ prm2 wcs = wc1 <> wc2 xs = x1 <> x2 instance (Sem.Semigroup a, Monoid a) => Monoid (Generics a) where mappend = (<>) - mempty = Generics [] [] mempty mempty + mempty = Generics [] mempty mempty + +-- TODO document +data GenericParam a + -- | A lifetime definition, introducing a lifetime and the other lifetimes that bound it. + -- + -- Example: @\'a: \'b + \'c + \'d@ + = LifetimeParam [Attribute a] (Lifetime a) [GenericBound a] a + + -- | Type parameter definition used in 'Generics' (@syntax::ast::GenericParam@). Note that each + -- parameter can have any number of (lifetime or trait) bounds, as well as possibly a default type. + | TypeParam [Attribute a] Ident [GenericBound a] (Maybe (Ty a)) a + + -- TODO document + | ConstParam [Attribute a] Ident (Ty a) a + deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) + +instance Located a => Located (GenericParam a) where + spanOf (LifetimeParam _ _ _ s) = spanOf s + spanOf (TypeParam _ _ _ _ s) = spanOf s + spanOf (ConstParam _ _ _ s) = spanOf s + +genericParamOrder :: GenericParam a -> GenericParam a -> Ordering +genericParamOrder = comparing paramCompare + where paramCompare :: GenericParam a -> Int + paramCompare LifetimeParam{} = 0 + paramCompare TypeParam{} = 1 + paramCompare ConstParam{} = 2 -- | An item within an impl (@syntax::ast::ImplItem@ with @syntax::ast::ImplItemKind@ inlined). -- @@ -543,7 +604,14 @@ instance Located a => Located (ImplItem a) where -- traits](https://github.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md) -- -- Example: @!@ as in @impl !Trait for Foo { }@ -data ImplPolarity = Positive | Negative deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) +data ImplPolarity = Positive | Negative + deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) + +-- | Distinguishes async from not async elements, eg. closures. +-- +-- Example: @async@ in @async |x: i32| { ... }@ +data IsAsync = IsAsync | NotAsync + deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) -- | A top-level item, possibly in a 'Mod' or a 'ItemStmt' (@syntax::ast::Item@ with -- @syntax::ast::ItemKind@ inlined). @@ -564,7 +632,7 @@ data Item a | ConstItem [Attribute a] (Visibility a) Ident (Ty a) (Expr a) a -- | function declaration (@fn@ or @pub fn@). -- Example: @fn foo(bar: usize) -\> usize { .. }@ - | Fn [Attribute a] (Visibility a) Ident (FnDecl a) Unsafety Constness Abi (Generics a) (Block a) a + | Fn [Attribute a] (Visibility a) Ident (FnDecl a) (FnHeader a) (Generics a) (Block a) a -- | module declaration (@mod@ or @pub mod@) (@syntax::ast::Mod@). -- Example: @mod foo;@ or @mod foo { .. }@ | Mod [Attribute a] (Visibility a) Ident (Maybe [Item a]) a @@ -585,19 +653,19 @@ data Item a | Union [Attribute a] (Visibility a) Ident (VariantData a) (Generics a) a -- | trait declaration (@trait@ or @pub trait@). -- Example: @trait Foo { .. }@ or @trait Foo\ { .. }@ - | Trait [Attribute a] (Visibility a) Ident Bool Unsafety (Generics a) [TyParamBound a] [TraitItem a] a + | Trait [Attribute a] (Visibility a) Ident Bool Unsafety (Generics a) [GenericBound a] [TraitItem a] a -- | trait alias -- Example: @trait Foo = Bar + Quux;@ - | TraitAlias [Attribute a] (Visibility a) Ident (Generics a) (NonEmpty (TyParamBound a)) a + | TraitAlias [Attribute a] (Visibility a) Ident (Generics a) [GenericBound a] a -- | implementation -- Example: @impl\ Foo\ { .. }@ or @impl\ Trait for Foo\ { .. }@ | Impl [Attribute a] (Visibility a) Defaultness Unsafety ImplPolarity (Generics a) (Maybe (TraitRef a)) (Ty a) [ImplItem a] a - -- | generated from a call to a macro + -- | generated from a call to a macro -- Example: @foo!{ .. }@ - | MacItem [Attribute a] (Maybe Ident) (Mac a) a + | MacItem [Attribute a] (Mac a) a -- | definition of a macro via @macro_rules@ -- Example: @macro_rules! foo { .. }@ - | MacroDef [Attribute a] Ident TokenStream a + | MacroDef [Attribute a] (Visibility a) Ident TokenStream a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) instance Located a => Located (Item a) where @@ -605,7 +673,7 @@ instance Located a => Located (Item a) where spanOf (Use _ _ _ s) = spanOf s spanOf (Static _ _ _ _ _ _ s) = spanOf s spanOf (ConstItem _ _ _ _ _ s) = spanOf s - spanOf (Fn _ _ _ _ _ _ _ _ _ s) = spanOf s + spanOf (Fn _ _ _ _ _ _ _ s) = spanOf s spanOf (Mod _ _ _ _ s) = spanOf s spanOf (ForeignMod _ _ _ _ s) = spanOf s spanOf (TyAlias _ _ _ _ _ s) = spanOf s @@ -615,8 +683,8 @@ instance Located a => Located (Item a) where spanOf (Trait _ _ _ _ _ _ _ _ s) = spanOf s spanOf (TraitAlias _ _ _ _ _ s) = spanOf s spanOf (Impl _ _ _ _ _ _ _ _ _ s) = spanOf s - spanOf (MacItem _ _ _ s) = spanOf s - spanOf (MacroDef _ _ _ s) = spanOf s + spanOf (MacItem _ _ s) = spanOf s + spanOf (MacroDef _ _ _ _ s) = spanOf s -- | Used to annotate loops, breaks, continues, etc. data Label a = Label Name a @@ -635,15 +703,6 @@ data Lifetime a = Lifetime Name a instance Located a => Located (Lifetime a) where spanOf (Lifetime _ s) = spanOf s --- | A lifetime definition, introducing a lifetime and the other lifetimes that bound it --- (@syntax::ast::LifetimeDef@). --- --- Example: @\'a: \'b + \'c + \'d@ -data LifetimeDef a = LifetimeDef [Attribute a] (Lifetime a) [Lifetime a] a - deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) - -instance Located a => Located (LifetimeDef a) where spanOf (LifetimeDef _ _ _ s) = spanOf s - -- | This is the fundamental unit of parsing - it represents the contents of one source file. It is -- composed of an optional shebang line, inner attributes that follow, and then the module items. -- @@ -671,13 +730,13 @@ data SourceFile a -- Examples: @i32@, @isize@, and @f32@ data Suffix = Unsuffixed - | Is | I8 | I16 | I32 | I64 | I128 + | Is | I8 | I16 | I32 | I64 | I128 | Us | U8 | U16 | U32 | U64 | U128 | F32 | F64 - deriving (Eq, Ord, Show, Enum, Bounded, Typeable, Data, Generic, NFData) + deriving (Eq, Ord, Show, Enum, Bounded, Typeable, Data, Generic, NFData) -- | Literals in Rust (@syntax::ast::Lit@). As discussed in 'Suffix', Rust AST is designed to parse --- suffixes for all literals, even if they are currently only valid on 'Int' and 'Float' literals. +-- suffixes for all literals, even if they are currently only valid on integer and float literals. data Lit a = Str String StrStyle Suffix a -- ^ string (example: @"foo"@) | ByteStr [Word8] StrStyle Suffix a -- ^ byte string (example: @b"foo"@) @@ -701,15 +760,15 @@ instance Located a => Located (Lit a) where byteStr :: String -> StrStyle -> Suffix -> a -> Lit a byteStr s = ByteStr (map (fromIntegral . ord) s) --- | Extract the suffix from a 'Lit'. +-- | Extract the suffix from a literal. suffix :: Lit a -> Suffix suffix (Str _ _ s _) = s suffix (ByteStr _ _ s _) = s -suffix (Char _ s _) = s -suffix (Byte _ s _) = s -suffix (Int _ _ s _) = s +suffix (Char _ s _) = s +suffix (Byte _ s _) = s +suffix (Int _ _ s _) = s suffix (Float _ s _) = s -suffix (Bool _ s _) = s +suffix (Bool _ s _) = s -- | The base of the number in an @Int@ literal can be binary (e.g. @0b1100@), octal (e.g. @0o14@), -- decimal (e.g. @12@), or hexadecimal (e.g. @0xc@). @@ -728,7 +787,8 @@ data MacStmtStyle deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) -- | Represents a method's signature in a trait declaration, or in an implementation. -data MethodSig a = MethodSig Unsafety Constness Abi (FnDecl a) deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) +data MethodSig a = MethodSig (FnHeader a) (FnDecl a) + deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) -- | The movability of a generator / closure literal (@syntax::ast::Movability@). data Movability = Immovable | Movable deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) @@ -764,27 +824,32 @@ data Pat a -- const pattern. Disambiguation cannot be done with parser alone, so it happens during name -- resolution. (example: @mut x@) | IdentP BindingMode Ident (Maybe (Pat a)) a - -- | struct pattern. The 'Bool' signals the presence of a @..@. (example: @Variant { x, y, .. }@) + -- | struct pattern. The 'Prelude.Bool' signals the presence of a @..@. + -- (example: @Variant { x, y, .. }@) | StructP (Path a) [FieldPat a] Bool a - -- | tuple struct pattern. If the @..@ pattern is present, the 'Maybe Int' denotes its position. - -- (example: @Variant(x, y, .., z)@) - | TupleStructP (Path a) [Pat a] (Maybe Int) a + -- | tuple struct pattern (example: @Variant(x, y, z)@) + | TupleStructP (Path a) [Pat a] a -- | path pattern (example @A::B::C@) | PathP (Maybe (QSelf a)) (Path a) a - -- | tuple pattern. If the @..@ pattern is present, the 'Maybe Int' denotes its position. - -- (example: @(a, b)@) - | TupleP [Pat a] (Maybe Int) a + -- | tuple pattern (example: @(a, b)@) + | TupleP [Pat a] a + -- | or pattern, must have more than one variant (example: @Some(0) | None@) + | OrP (NonEmpty (Pat a)) a -- | box pattern (example: @box _@) | BoxP (Pat a) a -- | reference pattern (example: @&mut (a, b)@) | RefP (Pat a) Mutability a -- | literal (example: @1@) | LitP (Expr a) a - -- | range pattern (example: @1...2@) - | RangeP (Expr a) (Expr a) a - -- | slice pattern where, as per [this RFC](https://github.com/P1start/rfcs/blob/array-pattern-changes/text/0000-array-pattern-changes.md), - -- the pattern is split into the patterns before/after the @..@ and the pattern at the @..@. (example: @[a, b, ..i, y, z]@) - | SliceP [Pat a] (Maybe (Pat a)) [Pat a] a + -- | range pattern (example: @1..=4@) + | RangeP (Expr a) (Expr a) RangeLimits a + -- | slice pattern (example: @[a, b, .., y, z]@) + | SliceP [Pat a] a + -- | A rest pattern @..@. Syntactically it is valid anywhere, but semantically it only has meaning + -- immediately inside a 'SliceP', a 'TupleP', or a 'TupleStructP' (example @[a, .., b]@) + | RestP a + -- | A paren + | ParenP (Pat a) a -- | generated from a call to a macro (example: @LinkedList!(1,2,3)@) | MacP (Mac a) a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) @@ -793,14 +858,17 @@ instance Located a => Located (Pat a) where spanOf (WildP s) = spanOf s spanOf (IdentP _ _ _ s) = spanOf s spanOf (StructP _ _ _ s) = spanOf s - spanOf (TupleStructP _ _ _ s) = spanOf s + spanOf (TupleStructP _ _ s) = spanOf s spanOf (PathP _ _ s) = spanOf s - spanOf (TupleP _ _ s) = spanOf s + spanOf (TupleP _ s) = spanOf s + spanOf (OrP _ s) = spanOf s spanOf (BoxP _ s) = spanOf s spanOf (RefP _ _ s) = spanOf s spanOf (LitP _ s) = spanOf s - spanOf (RangeP _ _ s) = spanOf s - spanOf (SliceP _ _ _ s) = spanOf s + spanOf (RangeP _ _ _ s) = spanOf s + spanOf (SliceP _ s) = spanOf s + spanOf (RestP s) = spanOf s + spanOf (ParenP _ s) = spanOf s spanOf (MacP _ s) = spanOf s -- | Everything in Rust is namespaced using nested modules. A 'Path' represents a path into nested @@ -808,9 +876,9 @@ instance Located a => Located (Pat a) where -- file paths, these paths can be relative or absolute (global) with respect to the crate root. -- -- Paths are used to identify expressions (see 'PathExpr'), types (see 'PathTy'), and modules --- (indirectly through 'ViewPath' and such). +-- (indirectly through 'UseTree' and such). -- --- The 'Bool' argument identifies whether the path is relative or absolute. +-- The 'Prelude.Bool' argument identifies whether the path is relative or absolute. -- -- Example: @std::cmp::PartialEq@ data Path a = Path Bool [PathSegment a] a @@ -818,14 +886,32 @@ data Path a = Path Bool [PathSegment a] a instance Located a => Located (Path a) where spanOf (Path _ _ s) = spanOf s --- | Parameters on a path segment (@syntax::ast::PathParameters@). -data PathParameters a +data GenericArg a + = LifetimeArg (Lifetime a) + | TypeArg (Ty a) + | ConstArg (Expr a) + deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) + +instance Located a => Located (GenericArg a) where + spanOf (LifetimeArg s) = spanOf s + spanOf (TypeArg s) = spanOf s + spanOf (ConstArg s) = spanOf s + +genericArgOrder :: GenericArg a -> GenericArg a -> Ordering +genericArgOrder = comparing argCompare + where argCompare :: GenericArg a -> Int + argCompare LifetimeArg{} = 0 + argCompare TypeArg{} = 1 + argCompare ConstArg{} = 2 + +-- | Parameters on a path segment (@syntax::ast::GenericArgs@). +data GenericArgs a -- | Parameters in a chevron comma-delimited list (@syntax::ast::AngleBracketedParameterData@). -- Note that lifetimes must come before types, which must come before bindings. Bindings are -- equality constraints on associated types (example: @Foo\@) -- -- Example: @\<\'a,A,B,C=i32\>@ in a path segment like @foo::\<'a,A,B,C=i32\>@ - = AngleBracketed [Lifetime a] [Ty a] [(Ident, Ty a)] a + = AngleBracketed [GenericArg a] [AssocTyConstraint a] a -- | Parameters in a parenthesized comma-delimited list, with an optional output type -- (@syntax::ast::ParenthesizedParameterData@). -- @@ -833,24 +919,24 @@ data PathParameters a | Parenthesized [Ty a] (Maybe (Ty a)) a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) -instance Located a => Located (PathParameters a) where - spanOf (AngleBracketed _ _ _ s) = spanOf s +instance Located a => Located (GenericArgs a) where + spanOf (AngleBracketed _ _ s) = spanOf s spanOf (Parenthesized _ _ s) = spanOf s -- | Segment of a path (@syntax::ast::PathSegment@). data PathSegment a - = PathSegment Ident (Maybe (PathParameters a)) a + = PathSegment Ident (Maybe (GenericArgs a)) a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) instance Located a => Located (PathSegment a) where spanOf (PathSegment _ _ s) = spanOf s -- | Trait ref parametrized over lifetimes introduced by a @for@ (@syntax::ast::PolyTraitRef@). -- --- Example: @for\<\'a,'b\> Foo\<&\'a Bar\>@ -data PolyTraitRef a = PolyTraitRef [LifetimeDef a] (TraitRef a) a +-- Example: @for\<\'a,'b\> Foo\<&\'a Bar\>@ +data PolyTraitRef a = PolyTraitRef [GenericParam a] (TraitRef a) a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) -instance Located a => Located (PolyTraitRef a) where spanOf (PolyTraitRef _ _ s) = spanOf s +instance Located a => Located (PolyTraitRef a) where spanOf (PolyTraitRef _ _ s) = spanOf s -- | The explicit @Self@ type in a "qualified path". The actual path, including the trait and the -- associated item, is stored separately. The first argument is the type given to @Self@ and the @@ -875,6 +961,8 @@ data Stmt a | NoSemi (Expr a) a -- | Expression with a trailing semicolon (example: @x + 1;@) | Semi (Expr a) a + -- | Just a semicolon + | StandaloneSemi a -- | A macro call (example: @println!("hello world")@) | MacStmt (Mac a) MacStmtStyle [Attribute a] a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) @@ -884,6 +972,7 @@ instance Located a => Located (Stmt a) where spanOf (ItemStmt _ s) = spanOf s spanOf (NoSemi _ s) = spanOf s spanOf (Semi _ s) = spanOf s + spanOf (StandaloneSemi s) = spanOf s spanOf (MacStmt _ _ _ s) = spanOf s -- | Style of a string literal (@syntax::ast::StrStyle@). @@ -901,7 +990,7 @@ data StructField a = StructField (Maybe Ident) (Visibility a) (Ty a) [Attribute instance Located a => Located (StructField a) where spanOf (StructField _ _ _ _ s) = spanOf s -- | An abstract sequence of tokens, organized into a sequence (e.g. stream) of 'TokenTree', each of --- which is a single 'Token' or a 'Delimited' subsequence of tokens. +-- which is a single token or a delimited subsequence of tokens. data TokenStream = Tree TokenTree -- ^ a single token or a single set of delimited tokens | Stream [TokenStream] -- ^ stream of streams of tokens @@ -923,9 +1012,9 @@ instance Located TokenStream where spanOf (Stream tt) = spanOf tt -- | When the parser encounters a macro call, it parses what follows as a 'Delimited' token tree. --- Basically, token trees let you store raw tokens or 'Sequence' forms inside of balanced --- parens, braces, or brackets. This is a very loose structure, such that all sorts of different --- AST-fragments can be passed to syntax extensions using a uniform type. +-- Basically, token trees let you store raw tokens inside of balanced parens, braces, or brackets. +-- This is a very loose structure, such that all sorts of different AST-fragments can be passed to +-- syntax extensions using a uniform type. data TokenTree -- | A single token = Token Span Token @@ -944,7 +1033,8 @@ instance Located TokenTree where -- | Modifier on a bound, currently this is only used for @?Sized@, where the modifier is @Maybe@. -- Negative bounds should also be handled here. -data TraitBoundModifier = None | Maybe deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) +data TraitBoundModifier = None | Maybe + deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) -- | Item declaration within a trait declaration (@syntax::ast::TraitItem@ with -- @syntax::ast::TraitItemKind@ inlined), possibly including a default implementation. A trait item @@ -974,7 +1064,7 @@ data TraitItem a -- | Method with optional body | MethodT [Attribute a] Ident (Generics a) (MethodSig a) (Maybe (Block a)) a -- | Possibly abstract associated types - | TypeT [Attribute a] Ident [TyParamBound a] (Maybe (Ty a)) a + | TypeT [Attribute a] Ident [GenericBound a] (Maybe (Ty a)) a -- | Call to a macro | MacroT [Attribute a] (Mac a) a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) @@ -1001,7 +1091,7 @@ data Ty a -- | reference (example: @&\'a T@ or @&\'a mut T@) | Rptr (Maybe (Lifetime a)) Mutability (Ty a) a -- | bare function (example: @fn(usize) -> bool@) - | BareFn Unsafety Abi [LifetimeDef a] (FnDecl a) a + | BareFn Unsafety Abi [GenericParam a] (FnDecl a) a -- | never type: @!@ | Never a -- | tuple (example: @(i32, i32)@) @@ -1009,11 +1099,9 @@ data Ty a -- | path type (examples: @std::math::pi@, @\ as SomeTrait\>::SomeType@). | PathTy (Maybe (QSelf a)) (Path a) a -- | trait object type (example: @Bound1 + Bound2 + Bound3@) - | TraitObject (NonEmpty (TyParamBound a)) a - -- | impl trait type (see the - -- [RFC](https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md)) - -- (example: @impl Bound1 + Bound2 + Bound3@). - | ImplTrait (NonEmpty (TyParamBound a)) a + | TraitObject (NonEmpty (GenericBound a)) a + -- | impl trait type (example: @impl Bound1 + Bound2 + Bound3@). + | ImplTrait (NonEmpty (GenericBound a)) a -- | no-op; kept solely so that we can pretty print faithfully | ParenTy (Ty a) a -- | typeof, currently unsupported in @rustc@ (example: @typeof(1)@) @@ -1040,36 +1128,29 @@ instance Located a => Located (Ty a) where spanOf (Infer s) = spanOf s spanOf (MacTy _ s) = spanOf s --- | Type parameter definition used in 'Generics' (@syntax::ast::TyParam@). Note that each --- parameter can have any number of (lifetime or trait) bounds, as well as possibly a default type. -data TyParam a = TyParam [Attribute a] Ident [TyParamBound a] (Maybe (Ty a)) a - deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) - -instance Located a => Located (TyParam a) where spanOf (TyParam _ _ _ _ s) = spanOf s - --- | Bounds that can be placed on types (@syntax::ast::TyParamBound@). These can be either traits or +-- | Bounds that can be placed on types (@syntax::ast::GenericBound@). These can be either traits or -- lifetimes. -data TyParamBound a - = TraitTyParamBound (PolyTraitRef a) TraitBoundModifier a -- ^ trait bound - | RegionTyParamBound (Lifetime a) a -- ^ lifetime bound +data GenericBound a + = TraitBound (PolyTraitRef a) TraitBoundModifier a -- ^ trait bound + | OutlivesBound (Lifetime a) a -- ^ lifetime bound deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) -instance Located a => Located (TyParamBound a) where - spanOf (TraitTyParamBound _ _ s) = spanOf s - spanOf (RegionTyParamBound _ s) = spanOf s +instance Located a => Located (GenericBound a) where + spanOf (TraitBound _ _ s) = spanOf s + spanOf (OutlivesBound _ s) = spanOf s --- | Partition a list of 'TyParamBound' into a tuple of the 'TraitTyParamBound' and --- 'RegionTyParamBound' variants. -partitionTyParamBounds :: [TyParamBound a] -> ([TyParamBound a], [TyParamBound a]) -partitionTyParamBounds = partition isTraitBound +-- | Partition a list of 'GenericBound' into a tuple of the 'TraitBound' and +-- 'OutlivesBound' variants. +partitionGenericBounds :: [GenericBound a] -> ([GenericBound a], [GenericBound a]) +partitionGenericBounds = partition isTraitBound where - isTraitBound TraitTyParamBound{} = True - isTraitBound RegionTyParamBound{} = False + isTraitBound TraitBound{} = True + isTraitBound OutlivesBound{} = False -- | Unary operators, used in the 'Unary' constructor of 'Expr' (@syntax::ast::UnOp@). -- -- Example: @!@ as in @!true@ -data UnOp +data UnOp = Deref -- ^ @*@ operator (dereferencing) | Not -- ^ @!@ operator (logical inversion) | Neg -- ^ @-@ operator (negation) @@ -1081,9 +1162,9 @@ data UnOp -- an unsafe block is compiler generated. data Unsafety = Unsafe | Normal deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Data, Generic, NFData) --- | A variant in Rust is a constructor (either in a 'StructItem', 'Union', or 'Enum') which groups --- together fields (@syntax::ast::Variant@). In the case of a unit variant, there can also be an --- explicit discriminant expression. +-- | A variant in Rust is a constructor (either in a 'StructItem', 'Union', or +-- 'Language.Rust.Syntax.Enum') which groups together fields (@syntax::ast::Variant@). In the case +-- of a unit variant, there can also be an explicit discriminant expression. data Variant a = Variant Ident [Attribute a] (VariantData a) (Maybe (Expr a)) a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) @@ -1136,7 +1217,7 @@ data UseTree a = UseTreeSimple (Path a) (Maybe Ident) a -- | Path ending in a glob pattern | UseTreeGlob (Path a) a - -- | Path ending in a list of more paths + -- | Path ending in a list of more paths | UseTreeNested (Path a) [UseTree a] a deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) @@ -1149,14 +1230,14 @@ instance Located a => Located (UseTree a) where -- (@ast::syntax::Visibility@). [RFC about adding restricted -- visibility](https://github.com/rust-lang/rfcs/blob/master/text/1422-pub-restricted.md) data Visibility a - = PublicV -- ^ @pub@ is accessible from everywhere + = PublicV -- ^ @pub@ is accessible from everywhere | CrateV -- ^ @pub(crate)@ is accessible from within the crate | RestrictedV (Path a) -- ^ for some path @p@, @pub(p)@ is visible at that path | InheritedV -- ^ if no visbility is specified, this is the default deriving (Eq, Ord, Functor, Show, Typeable, Data, Generic, Generic1, NFData) -- | A @where@ clause in a definition, where one can apply a series of constraints to the types --- introduced and used by a 'Generic' clause (@syntax::ast::WhereClause@). In many cases, @where@ +-- introduced and used by a 'Generic' clause (@syntax::ast::WhereClause@). In many cases, @where@ -- is the /only/ way to express certain bounds (since those bounds may not be immediately on a type -- defined in the generic, but on a type derived from types defined in the generic). -- @@ -1183,7 +1264,7 @@ instance (Sem.Semigroup a, Monoid a) => Monoid (WhereClause a) where -- | An individual predicate in a 'WhereClause' (@syntax::ast::WherePredicate@). data WherePredicate a -- | type bound (@syntax::ast::WhereBoundPredicate@) (example: @for\<\'c\> Foo: Send+Clone+\'c@) - = BoundPredicate [LifetimeDef a] (Ty a) [TyParamBound a] a + = BoundPredicate [GenericParam a] (Ty a) [GenericBound a] a -- | lifetime predicate (@syntax::ast::WhereRegionPredicate@) (example: @\'a: \'b+\'c@) | RegionPredicate (Lifetime a) [Lifetime a] a -- | equality predicate (@syntax::ast::WhereEqPredicate@) (example: @T=int@). Note that this is diff --git a/src/Language/Rust/Syntax/Token.hs b/src/Language/Rust/Syntax/Token.hs index 64fb822..6f607b9 100644 --- a/src/Language/Rust/Syntax/Token.hs +++ b/src/Language/Rust/Syntax/Token.hs @@ -1,7 +1,7 @@ {-| Module : Language.Rust.Syntax.Token Description : Token definitions -Copyright : (c) Alec Theriault, 2017-2018 +Copyright : (c) Alec Theriault, 2017-2019 License : BSD-style Maintainer : alec.theriault@gmail.com Stability : experimental @@ -39,20 +39,20 @@ import Language.Rust.Syntax.AST ( Nonterminal, AttrStyle(..) ) -- and @syntax::parse::token::BinOpEqToken@ as regular tokens. data Token -- Single character expression-operator symbols. - = Equal -- ^ @=@ token - | Less -- ^ @<@ token - | Greater -- ^ @>@ token - | Ampersand -- ^ @&@ token - | Pipe -- ^ @|@ token - | Exclamation -- ^ @!@ token - | Tilde -- ^ @~@ token - | Plus -- ^ @+@ token - | Minus -- ^ @-@ token - | Star -- ^ @*@ token - | Slash -- ^ @/@ token - | Percent -- ^ @%@ token - | Caret -- ^ @^@ token - + = Equal -- ^ @=@ token + | Less -- ^ @<@ token + | Greater -- ^ @>@ token + | Ampersand -- ^ @&@ token + | Pipe -- ^ @|@ token + | Exclamation -- ^ @!@ token + | Tilde -- ^ @~@ token + | Plus -- ^ @+@ token + | Minus -- ^ @-@ token + | Star -- ^ @*@ token + | Slash -- ^ @/@ token + | Percent -- ^ @%@ token + | Caret -- ^ @^@ token + -- Multi character expression-operator symbols | GreaterEqual -- ^ @>=@ token | GreaterGreaterEqual -- ^ @>>=@ token @@ -72,8 +72,8 @@ data Token | SlashEqual -- ^ @/=@ token | CaretEqual -- ^ @^=@ token | PercentEqual -- ^ @%=@ token - - -- Structural symbols + + -- Structural symbols | At -- ^ @\@@ token | Dot -- ^ @.@ token | DotDot -- ^ @..@ token @@ -89,14 +89,14 @@ data Token | Pound -- ^ @#@ token | Dollar -- ^ @$@ token | Question -- ^ @?@ token - + -- Delimiters | OpenDelim !Delim -- ^ One of @(@, @[@, @{@ | CloseDelim !Delim -- ^ One of @)@, @]@, @}@ - + -- Literals | LiteralTok LitTok (Maybe Name) -- ^ a literal token with an optional suffix (something like @i32@) - + -- Name components | IdentTok Ident -- ^ an arbitrary identifier (something like @x@ or @foo@ or @and_then@) | LifetimeTok Ident -- ^ a lifetime (something like @\'a@ or @\'static@) @@ -105,7 +105,7 @@ data Token -- ^ doc comment with its contents, whether it is outer/inner, and whether it is inline or not | Shebang -- ^ @#!@ shebang token | Eof -- ^ end of file token - + -- NOT PRODUCED IN TOKENIZATION!! | Interpolated (Nonterminal Span) -- ^ can be expanded into several tokens in macro-expansion deriving (Eq, Ord, Data, Typeable, Generic, NFData) @@ -149,7 +149,7 @@ spaceNeeded Greater FatArrow = True -- conflicts with 'GreaterGreaterEqual' spaceNeeded Greater GreaterEqual = True spaceNeeded GreaterGreater Equal = True -spaceNeeded GreaterGreater EqualEqual = True +spaceNeeded GreaterGreater EqualEqual = True spaceNeeded GreaterGreater FatArrow = True -- conflicts with 'AmpersandAmpersand' @@ -271,7 +271,7 @@ spaceNeeded Equal GreaterEqual = True spaceNeeded Equal GreaterGreaterEqual = True -- conflicts with 'LiteralTok' -spaceNeeded LiteralTok{} IdentTok{} = True +spaceNeeded LiteralTok{} IdentTok{} = True -- conflicts with 'IdentTok' spaceNeeded IdentTok{} IdentTok{} = True @@ -364,6 +364,6 @@ instance Show Token where show (Doc d Outer False) = "///" ++ d show Shebang = "#!" show Eof = "" - -- Macro related + -- Macro related show Interpolated{} = "" diff --git a/src/Language/Rust/Syntax/Token.hs-boot b/src/Language/Rust/Syntax/Token.hs-boot index ca14ffe..2059440 100644 --- a/src/Language/Rust/Syntax/Token.hs-boot +++ b/src/Language/Rust/Syntax/Token.hs-boot @@ -1,8 +1,5 @@ -- .hs-boot files play badly with associated type families like 'Rep' -{-# LANGUAGE CPP #-} -#if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -Wno-missing-methods #-} -#endif module Language.Rust.Syntax.Token where diff --git a/test/README.md b/test/README.md index 7ebc84a..779135c 100644 --- a/test/README.md +++ b/test/README.md @@ -9,7 +9,7 @@ $ stack test --test-arguments "--hide-successes" # show only fa $ stack test --test-arguments "--help" # learn about more options! ``` -## `unit-tests` +## `unit-tests` These are mostly regression/coverage style tests. They cover lexing, parsing, and pretty printing. The case for parsing is actually a bit more involved: on top of just checking that inputs parse diff --git a/test/rustc-tests/Diff.hs b/test/rustc-tests/Diff.hs index 4dea76d..2d1ee06 100644 --- a/test/rustc-tests/Diff.hs +++ b/test/rustc-tests/Diff.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE CPP, OverloadedStrings, OverloadedLists, InstanceSigs #-} +{-# LANGUAGE OverloadedStrings, OverloadedLists, InstanceSigs #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Diff where @@ -15,6 +15,7 @@ import Data.Maybe (fromMaybe, isNothing) import Data.Semigroup ((<>)) import qualified Data.Text as T import qualified Data.Vector as V +import qualified Data.List.NonEmpty as N import DiffUtils @@ -30,16 +31,14 @@ instance Show a => Diffable (Item a) where let n' = val ! "node" inheritedV = InheritedV :: Visibility () case (n' ! "variant", item) of - ("Fn", Fn as v i decl u c a gen bod _) -> do + ("Fn", Fn as v i decl hdr gen bod _) -> do as === (val ! "attrs") v === (val ! "vis") i === (val ! "ident") decl === (n' ! "fields" ! 0) - u === (n' ! "fields" ! 1) - c === (n' ! "fields" ! 2) - a === (n' ! "fields" ! 3) - gen === (n' ! "fields" ! 4) - bod === (n' ! "fields" ! 5) + hdr === (n' ! "fields" ! 1) + gen === (n' ! "fields" ! 2) + bod === (n' ! "fields" ! 3) ("ExternCrate", ExternCrate as v i i' _) -> do as === (val ! "attrs") v === (val ! "vis") @@ -76,17 +75,23 @@ instance Show a => Diffable (Item a) where mkIdent "" === (val ! "ident") a === (n' ! "fields" ! 0 ! "abi") is === (n' ! "fields" ! 0 ! "items") - ("Ty", TyAlias as v i t g _) -> do + ("TyAlias", TyAlias as v i t g _) -> do as === (val ! "attrs") v === (val ! "vis") i === (val ! "ident") t === (n' ! "fields" ! 0) g === (n' ! "fields" ! 1) + ("OpaqueTy", TyAlias as v i (ImplTrait b _) g _) -> do + as === (val ! "attrs") + v === (val ! "vis") + i === (val ! "ident") + b === (n' ! "fields" ! 0) + g === (n' ! "fields" ! 1) ("Enum", Enum as v i vs g _) -> do as === (val ! "attrs") v === (val ! "vis") i === (val ! "ident") - vs === (n' ! "fields" ! 0 ! "variants") + vs === (n' ! "fields" ! 0 ! "variants") g === (n' ! "fields" ! 1) ("Struct", StructItem as v i v' g _) -> do as === (val ! "attrs") @@ -126,18 +131,17 @@ instance Show a => Diffable (Item a) where mtr === (n' ! "fields" ! 4) t === (n' ! "fields" ! 5) is === (n' ! "fields" ! 6) - ("Mac", MacItem as i m _) -> do + ("Mac", MacItem as m _) -> do as === (val ! "attrs") inheritedV === (val ! "vis") - fromMaybe "" i === (val ! "ident") m === (n' ! "fields" ! 0) - ("MacroDef", MacroDef as i tt _) -> do + ("MacroDef", MacroDef as v i tt _) -> do as === (val ! "attrs") - inheritedV === (val ! "vis") + v === (val ! "vis") i === (val ! "ident") tt === (n' ! "fields" ! 0 ! "tokens") _ -> diff "different items" item val - + newtype IsAuto = IsAuto Bool deriving (Show, Eq) instance Diffable IsAuto where @@ -173,10 +177,10 @@ instance Show a => Diffable (TraitItem a) where ("Macro", MacroT as m _) -> do as === (val ! "attrs") m === (n' ! "fields" ! 0) - _ -> diff "different trait item" item val + _ -> diff "different trait item" item val instance Show a => Diffable (ImplItem a) where - item === val = do + item === val = do let n' = val ! "node" case (n' ! "variant", item) of ("Const", ConstI as v d i t e _) -> do @@ -194,24 +198,36 @@ instance Show a => Diffable (ImplItem a) where g === (val ! "generics") m === (n' ! "fields" ! 0) b === (n' ! "fields" ! 1) - ("Type", TypeI as v d i t _) -> do + ("TyAlias", TypeI as v d i t _) -> do as === (val ! "attrs") v === (val ! "vis") d === (val ! "defaultness") i === (val ! "ident") t === (n' ! "fields" ! 0) + ("OpaqueTy", TypeI as v d i (ImplTrait b _) _) -> do + as === (val ! "attrs") + v === (val ! "vis") + d === (val ! "defaultness") + i === (val ! "ident") + b === (n' ! "fields" ! 0) ("Macro", MacroI as d m _) -> do as === (val ! "attrs") d === (val ! "defaultness") m === (n' ! "fields" ! 0) _ -> diff "different impl item" item val - + instance Show a => Diffable (MethodSig a) where - MethodSig u c a decl === val = do + MethodSig header decl === val = do + header === (val ! "header") + decl === (val ! "decl") + +instance Show a => Diffable (FnHeader a) where + FnHeader u s c a _ === val = do u === (val ! "unsafety") + s === (val ! "asyncness" ! "node") a === (val ! "abi") c === (val ! "constness") - decl === (val ! "decl") + instance Diffable Defaultness where Final === "Final" = pure () @@ -220,15 +236,15 @@ instance Diffable Defaultness where instance Show a => Diffable (Variant a) where Variant i as d e _ === val = do - i === (val ! "node" ! "ident") - as === (val ! "node" ! "attrs") - d === (val ! "node" ! "data") - e === (val ! "node" ! "disr_expr") + i === (val ! "ident") + as === (val ! "attrs") + d === (val ! "data") + fmap AnonConst e === (val ! "disr_expr") instance Show a => Diffable (VariantData a) where d === val = case (val ! "variant", d) of - ("Tuple", TupleD sf _) -> sf === (val ! "fields" ! 0) + ("Tuple", TupleD sf _) -> sf === (val ! "fields" ! 0) ("Struct", StructD sf _) -> sf === (val ! "fields" ! 0) ("Unit", UnitD _) -> pure () _ -> diff "different variants" d val @@ -252,14 +268,17 @@ instance Show a => Diffable (ForeignItem a) where as === (val ! "attrs") v === (val ! "vis") i === (val ! "ident") - d === (n' ! "fields" ! 0) + d === (n' ! "fields" ! 0) g === (n' ! "fields" ! 1) ("Static", ForeignStatic as v i t m _) -> do as === (val ! "attrs") v === (val ! "vis") i === (val ! "ident") t === (n' ! "fields" ! 0) - (m == Mutable) === (n' ! "fields" ! 1) + m === (n' ! "fields" ! 1) + ("Macro", ForeignMac as m _) -> do + as === (val ! "attrs") + m === (n' ! "fields" ! 0) _ -> diff "different foreign item" f val instance Show a => Diffable (UseTree a) where @@ -282,31 +301,39 @@ instance Show (UseTreePair a) where instance Show a => Diffable (UseTreePair a) where UseTreePair ut === val = ut === (val ! 0) - + instance Show a => Diffable (FnDecl a) where - FnDecl as out v _ === val = do + FnDecl as out variadic _ === val = do -- Check inputs - as === (val ! "inputs") - + -- Rust tacks on an extra bogus argument representing the "...". We don't. + let adjustedIns = case val ! "inputs" of + Data.Aeson.Array arr | variadic -> Data.Aeson.Array (V.init arr) + other -> other + as === adjustedIns + -- Check output let outTy = val ! "output" ! "variant" case (outTy, out) of ("Default", Nothing) -> pure () ("Ty", Just t) -> t === (val ! "output" ! "fields" ! 0) _ -> diff "different output types" out outTy - + -- Check variadic - v === (val ! "variadic") + variadic === (val ! "c_variadic") instance Show a => Diffable (Arg a) where - SelfRegion _ _ x === val = + SelfRegion as _ _ x === val = do + NullList as === (val ! "attrs" ! "_field0") IdentP (ByValue Immutable) "self" Nothing x === (val ! "pat") - SelfValue m x === val = + SelfValue as m x === val = do + NullList as === (val ! "attrs" ! "_field0") IdentP (ByValue m) "self" Nothing x === (val ! "pat") - SelfExplicit t m x === val = do + SelfExplicit as t m x === val = do + NullList as === (val ! "attrs" ! "_field0") IdentP (ByValue m) "self" Nothing x === (val ! "pat") t === (val ! "ty") - Arg p t _ === val = do + Arg as p t _ === val = do + NullList as === (val ! "attrs" ! "_field0") let p' = fromMaybe (IdentP (ByValue Immutable) invalidIdent Nothing undefined) p p' === (val ! "pat") t === (val ! "ty") @@ -328,6 +355,7 @@ instance Diffable Abi where Cdecl === "Cdecl" = pure () Stdcall === "Stdcall" = pure () Fastcall === "Fastcall" = pure () + Thiscall === "Thiscall" = pure () Vectorcall === "Vectorcall" = pure () Aapcs === "Aapcs" = pure () Win64 === "Win64" = pure () @@ -335,6 +363,7 @@ instance Diffable Abi where PtxKernel === "PtxKernel" = pure () Msp430Interrupt === "Msp430Interrupt" = pure () X86Interrupt === "X86Interrupt" = pure () + AmdGpuKernel === "AmdGpuKernel" = pure () Rust === "Rust" = pure () C === "C" = pure () System === "System" = pure () @@ -345,31 +374,29 @@ instance Diffable Abi where a === val = diff "different ABI" a val instance Show a => Diffable (Generics a) where - Generics lts tys whr _ === val = do - (map LifetimeParam lts ++ map TypeParam tys) === (val ! "params") + Generics params whr _ === val = do + params === (val ! "params") whr === (val ! "where_clause") -data Param a = TypeParam (TyParam a) | LifetimeParam (LifetimeDef a) deriving (Show) - -instance Show a => Diffable (Param a) where - p === val = - case (val ! "variant", p) of - ("Lifetime", LifetimeParam ldef) -> ldef === (val ! "fields" ! 0) - ("Type", TypeParam typ) -> typ === (val ! "fields" ! 0) - _ -> diff "different generic param" p val - -instance Show a => Diffable (LifetimeDef a) where - LifetimeDef as l bd _ === val = do - NullList as === (val ! "attrs" ! "_field0") - l === (val ! "lifetime") - bd === (val ! "bounds") - -instance Show a => Diffable (TyParam a) where - TyParam as i bd d _ === val = do - NullList as === (val ! "attrs" ! "_field0") - i === (val ! "ident") - bd === (val ! "bounds") - d === (val ! "default") +instance Show a => Diffable (GenericParam a) where + param === val = + case (val ! "kind", param) of + ("Lifetime", LifetimeParam as l bd _) -> do + NullList as === (val ! "attrs" ! "_field0") + l === val + bd === (val ! "bounds") + (n, _) -> + case (n ! "variant", param) of + ("Type", TypeParam as i bd d _) -> do + NullList as === (val ! "attrs" ! "_field0") + i === (val ! "ident") + bd === (val ! "bounds") + d === (val ! "kind" ! "fields" ! 0) + ("Const", ConstParam as i t _) -> do + NullList as === (val ! "attrs" ! "_field0") + i === (val ! "ident") + t === (val ! "kind" ! "fields" ! 0) + _ -> diff "different generic parameter" param val instance Show a => Diffable (WhereClause a) where WhereClause preds _ === val = preds === (val ! "predicates") @@ -378,12 +405,12 @@ instance Show a => Diffable (WherePredicate a) where w === val = case (val ! "variant", w) of ("BoundPredicate", BoundPredicate ls t bds _) -> do - map LifetimeParam ls === (val ! "fields" ! 0 ! "bound_generic_params") + ls === (val ! "fields" ! 0 ! "bound_generic_params") t === (val ! "fields" ! 0 ! "bounded_ty") bds === (val ! "fields" ! 0 ! "bounds") ("RegionPredicate", RegionPredicate l bs _) -> do l === (val ! "fields" ! 0 ! "lifetime") - bs === (val ! "fields" ! 0 ! "bounds") + map (\b@(Lifetime _ x) -> OutlivesBound b x) bs === (val ! "fields" ! 0 ! "bounds") ("EqPredicate", EqPredicate l r _) -> do l === (val ! "fields" ! 0 ! "lhs_ty") r === (val ! "fields" ! 0 ! "rhs_ty") @@ -391,9 +418,19 @@ instance Show a => Diffable (WherePredicate a) where instance Show a => Diffable (Block a) where Block ss ru _ === val = do - ss === (val ! "stmts") + massageStandaloneSemis ss === (val ! "stmts") ru === (val ! "rules") +massageStandaloneSemis :: [Stmt a] -> [Stmt a] +massageStandaloneSemis [] = [] +massageStandaloneSemis (StandaloneSemi s : rest) = semiTup s : massageStandaloneSemis (dropWhile isStandalone rest) + where + isStandalone StandaloneSemi{} = True + isStandalone _ = False + semiTup x = Semi (TupExpr [] [] x) x +massageStandaloneSemis (s : rest) = s : massageStandaloneSemis rest + +-- TODO: Rust parses out extra semicolons instance Show a => Diffable (Stmt a) where stmt === val = do let n' = val ! "node" @@ -403,7 +440,7 @@ instance Show a => Diffable (Stmt a) where t === (n' ! "fields" ! 0 ! "ty") i === (n' ! "fields" ! 0 ! "init") NullList as === (n' ! "fields" ! 0 ! "attrs" ! "_field0") - ("Expr", NoSemi e _) -> e === (n' ! "fields" ! 0) + ("Expr", NoSemi e _) -> e === (n' ! "fields" ! 0) ("Semi", Semi e _) -> e === (n' ! "fields" ! 0) ("Item", ItemStmt i _) -> i === (n' ! "fields" ! 0) ("Mac", MacStmt m s as _) -> do @@ -425,7 +462,7 @@ instance Show a => Diffable (Visibility a) where (CrateV, "Crate") -> pure () (RestrictedV p, val') -> do mkIdent "Restricted" === (val' ! "variant") - p === (val' ! "fields" ! 0) + p === (val' ! "fields" ! 0) (InheritedV, "Inherited") -> pure () (_, val') -> diff "different visibilities" a val' @@ -441,9 +478,9 @@ instance Show a => Diffable (Attribute a) where let toks = val ! "tokens" Token mempty Equal === (toks ! 0) let str = toks ! 1 - mkIdent "Literal" === (str ! "fields" ! 1 ! "variant") - mkIdent "Str_" === (str ! "fields" ! 1 ! "fields" ! 0 ! "variant") - let Data.Aeson.String n' = str ! "fields" ! 1 ! "fields" ! 0 ! "fields" ! 0 + mkIdent "Literal" === (str ! "fields" ! 0 ! "kind" ! "variant") + mkIdent "Str" === (str ! "fields" ! 0 ! "kind" ! "fields" ! 0 ! "kind") + let Data.Aeson.String n' = str ! "fields" ! 0 ! "kind" ! "fields" ! 0 ! "symbol" Str n'' Cooked Unsuffixed () = translateLit (StrTok (T.unpack n')) Unsuffixed () -- Style case (val ! "style", sty, inl) of @@ -461,14 +498,26 @@ instance Show a => Diffable (Attribute a) where ts === (val ! "tokens") _ -> diff "attribute is not sugared doc" a val +-- Temporary hack until Rust gets their AST in order... +newtype OrPatHack a = OrPatHack (Pat a) deriving Show + +variants :: Pat a -> N.NonEmpty (Pat a) +variants (OrP ps _) = ps +variants notOrPat = [notOrPat] + +instance Show a => Diffable (OrPatHack a) where + OrPatHack p === val = variants p === val + instance Show a => Diffable (Pat a) where p' === val = do let val' = val ! "node" case (val', p') of ("Wild", WildP _) -> pure () + ("Rest", RestP _) -> pure () (Data.Aeson.Object{}, _) -> case (val' ! "variant", p') of ("Box", BoxP p _) -> p === (val' ! "fields" ! 0) + ("Paren", ParenP p _) -> p === (val' ! "fields" ! 0) ("Lit", LitP e _) -> e === (val' ! "fields" ! 0) ("Mac", MacP m _) -> m === (val' ! "fields" ! 0) ("Ident", IdentP bm i m _) -> do @@ -482,20 +531,19 @@ instance Show a => Diffable (Pat a) where p === (val' ! "fields" ! 0) fp === (val' ! "fields" ! 1) d === (val' ! "fields" ! 2) - ("TupleStruct", TupleStructP p fp mi _) -> do + ("TupleStruct", TupleStructP p fp _) -> do p === (val' ! "fields" ! 0) fp === (val' ! "fields" ! 1) - mi === (val' ! "fields" ! 2) - ("Tuple", TupleP fp mi _) -> do + ("Tuple", TupleP fp _) -> do fp === (val' ! "fields" ! 0) - mi === (val' ! "fields" ! 1) - ("Range", RangeP e1 e2 _) -> do + ("Or", OrP ps _) -> do + ps === (val' ! "fields" ! 0) + ("Range", RangeP e1 e2 rl _) -> do e1 === (val' ! "fields" ! 0) e2 === (val' ! "fields" ! 1) - ("Slice", SliceP b m a _) -> do - b === (val' ! "fields" ! 0) - m === (val' ! "fields" ! 1) - a === (val' ! "fields" ! 2) + rl === (val' ! "fields" ! 2) + ("Slice", SliceP a _) -> do + a === (val' ! "fields" ! 0) ("Path", PathP q p _) -> do q === (val' ! "fields" ! 0) p === (val' ! "fields" ! 1) @@ -504,21 +552,21 @@ instance Show a => Diffable (Pat a) where instance Show a => Diffable (Mac a) where Mac p tt _ === val = do - p === (val ! "node" ! "path") - tt === (val ! "node" ! "tts") + p === (val ! "path") + tt === (val ! "tts") instance Diffable TokenTree where - tt === val = + tt === val = case (val ! "variant", tt) of - ("Token", Token _ t) -> t === (val ! "fields" ! 1) + ("Token", Token _ t) -> t === (val ! "fields" ! 0 ! "kind") ("Delimited", Delimited _ d tt') -> do - d === (val ! "fields" ! 1 ! "delim") - tt' === (val ! "fields" ! 1 ! "tts") + d === (val ! "fields" ! 1) + tt' === (val ! "fields" ! 2) _ -> diff "different token trees" tt val instance Diffable TokenStream where - ts === val = flatten ts === val - where + ts === val = flatten ts === val + where flatten (Tree t) = [t] flatten (Stream s) = concatMap flatten s @@ -565,7 +613,7 @@ instance Diffable Token where ("DocComment", Doc s Outer True) -> ("/**" <> mkIdent s <> "*/") === (val ! "fields" ! 0) ("Literal", LiteralTok l s) -> do l === (val ! "fields" ! 0) - fmap mkIdent s === (val ! "fields" ! 1) + fmap mkIdent s === (val ! "fields" ! 0 ! "suffix") ("BinOp", _) -> case (val ! "fields" ! 0, t) of ("Star", Star) -> pure () @@ -599,15 +647,19 @@ instance Diffable Token where instance Diffable LitTok where l === val = - case (val ! "variant", l) of - ("Byte", ByteTok s) | fromString s == (val ! "fields" ! 0) -> pure () - ("Char", CharTok s) | fromString s == (val ! "fields" ! 0) -> pure () - ("Integer", IntegerTok s) | fromString s == (val ! "fields" ! 0) -> pure () - ("Float", FloatTok s) | fromString s == (val ! "fields" ! 0) -> pure () - ("Str_", StrTok s) | fromString s == clean (val ! "fields" ! 0) -> pure () - ("StrRaw", StrRawTok s i) | fromString s == clean (val ! "fields" ! 0) -> i === (val ! "fields" ! 1) - ("ByteStr", ByteStrTok s) | fromString s == clean (val ! "fields" ! 0) -> pure () - ("ByteStrRaw", ByteStrRawTok s i) | fromString s == clean (val ! "fields" ! 0) -> i === (val ! "fields" ! 1) + case (val ! "kind", l) of + ("Byte", ByteTok s) | fromString s == (val ! "symbol") -> pure () + ("Char", CharTok s) | fromString s == (val ! "symbol") -> pure () + ("Integer", IntegerTok s) | fromString s == (val ! "symbol") -> pure () + ("Float", FloatTok s) | fromString s == (val ! "symbol") -> pure () + ("Str", StrTok s) | fromString s == clean (val ! "symbol") -> pure () + ("ByteStr", ByteStrTok s) | fromString s == clean (val ! "symbol") -> pure () + (strRaw, StrRawTok s i) | strRaw !? "variant" == Just "StrRaw" + , fromString s == clean (val ! "symbol") + -> i === (strRaw ! "fields" ! 0) + (byteStrRaw, ByteStrRawTok s i) | byteStrRaw !? "variant" == Just "ByteStrRaw" + , fromString s == clean (val ! "symbol") + -> i === (byteStrRaw ! "fields" ! 0) _ -> diff "different literal token" l val clean :: Value -> Value @@ -617,26 +669,32 @@ clean x = _ -> x instance Show a => Diffable (FieldPat a) where - f@(FieldPat mi p _) === val = do + f@(FieldPat mi p as _) === val = do -- Extract the identifier and whether the pattern is shorthand (i, s) <- case (mi,p) of + (Nothing, BoxP (IdentP _ i' Nothing _) _) -> pure (i', True) (Nothing, IdentP _ i' Nothing _) -> pure (i', True) (Nothing, _) -> diff "shorthand field pattern needs to be identifier" f val (Just i', _) -> pure (i', False) - - i === (val ! "node" ! "ident") - s === (val ! "node" ! "is_shorthand") - p === (val ! "node" ! "pat") + + i === (val ! "ident") + s === (val ! "is_shorthand") + p === (val ! "pat") + NullList as === (val ! "attrs" ! "_field0") instance Show a => Diffable (Field a) where - Field i me _ === val = do + Field i me as _ === val = do isNothing me === (val ! "is_shorthand") i === (val ! "ident") unless (isNothing me) $ me === (val ! "expr") + NullList as === (val ! "attrs" ! "_field0") instance Diffable Ident where Ident i _ _ === String s | fromString i == s = pure () + Ident i _ _ === val | Just (String s) <- val !? "name" + , fromString i == s + = pure () ident' === val = diff "identifiers are different" ident' val -- | The empty identifier is invalid @@ -669,8 +727,8 @@ instance Show a => Diffable (Ty a) where ("Tup", TupTy t _) -> t === (n ! "fields" ! 0) ("Slice", Slice t _) -> t === (n ! "fields" ! 0) ("Array", Language.Rust.Syntax.Array t e _) -> do - t === (n ! "fields" ! 0) - e ===(n ! "fields" ! 1) + t === (n ! "fields" ! 0) + AnonConst e === (n ! "fields" ! 1) ("Ptr", Ptr m t _) -> do m === (n ! "fields" ! 0 ! "mutbl") t === (n ! "fields" ! 0 ! "ty") @@ -681,30 +739,30 @@ instance Show a => Diffable (Ty a) where ("BareFn", BareFn u a lts decl _) -> do u === (n ! "fields" ! 0 ! "unsafety") a === (n ! "fields" ! 0 ! "abi") - map LifetimeParam lts === (n ! "fields" ! 0 ! "generic_params") + lts === (n ! "fields" ! 0 ! "generic_params") decl === (n ! "fields" ! 0 ! "decl") ("TraitObject", TraitObject bds _) -> bds === (n ! "fields" ! 0) ("Paren", ParenTy t _) -> t === (n ! "fields" ! 0) - ("Typeof", Typeof e _) -> e ===(n ! "fields" ! 0) + ("Typeof", Typeof e _) -> AnonConst e === (n ! "fields" ! 0) ("Mac", MacTy m _) -> m === (n ! "fields" ! 0) - ("ImplTrait", ImplTrait bds _) -> bds === (n ! "fields" ! 0) + ("ImplTrait", ImplTrait bds _) -> bds === (n ! "fields" ! 1) _ -> diff "differing types" t' val _ -> diff "differing types" t' val -instance Show a => Diffable (TyParamBound a) where +instance Show a => Diffable (GenericBound a) where bd === val = case (val ! "variant", bd) of - ("TraitTyParamBound", TraitTyParamBound p m _) -> do + ("Trait", TraitBound p m _) -> do p === (val ! "fields" ! 0) m === (val ! "fields" ! 1) - ("RegionTyParamBound", RegionTyParamBound l _) -> + ("Outlives", OutlivesBound l _) -> l === (val ! "fields" ! 0) _ -> diff "different type parameter bounds" bd val instance Show a => Diffable (PolyTraitRef a) where PolyTraitRef lts tr _ === val = do - map LifetimeParam lts === (val ! "bound_generic_params") + lts === (val ! "bound_generic_params") tr === (val ! "trait_ref") instance Show a => Diffable (TraitRef a) where @@ -713,12 +771,12 @@ instance Show a => Diffable (TraitRef a) where instance Diffable TraitBoundModifier where None === "None" = pure () Maybe === "Maybe" = pure () - m === val = diff "different trait boudn modifier" m val + m === val = diff "different trait bound modifier" m val instance Show a => Diffable (Lifetime a) where l@(Lifetime n _) === val - | fromString ("'" ++ n) /= val ! "ident" = diff "lifetime is different" l val - | otherwise = pure () + | fromString ("'" ++ n) == val ! "ident" ! "name" = pure () + | otherwise = diff "lifetime is different" l val instance Show a => Diffable (QSelf a) where QSelf t p === val = do @@ -729,33 +787,53 @@ instance Show a => Diffable (QSelf a) where instance Show a => Diffable (Path a) where Path _ segs _ === val = do let val' = case val ! "segments" of - j@(Data.Aeson.Array v) | not (V.null v) && j ! 0 ! "ident" == "{{root}}" -> Data.Aeson.Array (V.drop 1 v) + j@(Data.Aeson.Array v) + | not (V.null v) + , j ! 0 ! "ident" ! "name" == "{{root}}" + -> Data.Aeson.Array (V.drop 1 v) j -> j - + segs === val' instance Show a => Diffable (PathSegment a) where PathSegment i pp _ === val = do i === (val ! "ident") - pp === (val ! "parameters") + pp === (val ! "args") -instance Show a => Diffable (PathParameters a) where +instance Show a => Diffable (GenericArgs a) where p === val = case (val ! "variant", p) of - ("AngleBracketed", AngleBracketed lts tys bds _) -> do - lts === (val ! "fields" ! 0 ! "lifetimes") - tys === (val ! "fields" ! 0 ! "types") - map Binding bds === (val ! "fields" ! 0 ! "bindings") + ("AngleBracketed", AngleBracketed args bds _) -> do + args === (val ! "fields" ! 0 ! "args") + bds === (val ! "fields" ! 0 ! "constraints") ("Parenthesized", Parenthesized is o _) -> do is === (val ! "fields" ! 0 ! "inputs") o === (val ! "fields" ! 0 ! "output") _ -> diff "different path parameters" p val -newtype Binding a = Binding (Ident, Ty a) deriving (Show) -instance Show a => Diffable (Binding a) where - Binding (i,t) === v = do - i === (v ! "ident") - t === (v ! "ty") +instance Show a => Diffable (GenericArg a) where + arg === val = + case (val ! "variant", arg) of + ("Lifetime", LifetimeArg l) -> l === (val ! "fields" ! 0) + ("Type", TypeArg t) -> t === (val ! "fields" ! 0) + ("Const", ConstArg e) -> AnonConst e === (val ! "fields" ! 0) + _ -> diff "different generic argument" arg val + +instance Show a => Diffable (AssocTyConstraint a) where + con === val = + case (val ! "kind" ! "variant", con) of + ("Equality", EqualityConstraint i t _) -> do + i === (val ! "ident") + t === (val ! "kind" ! "fields" ! 0) + ("Bound", BoundConstraint i b _) -> do + i === (val ! "ident") + b === (val ! "kind" ! "fields" ! 0) + _ -> diff "different associated constraints" con val + +newtype AnonConst a = AnonConst (Expr a) deriving (Show, Eq) + +instance Show a => Diffable (AnonConst a) where + AnonConst e === val = e === (val ! "value") instance Show a => Diffable (Expr a) where ex === val = @@ -773,34 +851,26 @@ instance Show a => Diffable (Expr a) where ("Box", Box as e _) -> do NullList as === (val ! "attrs" ! "_field0") e === (n ! "fields" ! 0) - ("InPlace", InPlace as e1 e2 _) -> do - NullList as === (val ! "attrs" ! "_field0") - e1 === (n ! "fields" ! 0) - e2 === (n ! "fields" ! 1) ("Path", PathExpr as q p _) -> do NullList as === (val ! "attrs" ! "_field0") q === (n ! "fields" ! 0) p === (n ! "fields" ! 1) - ("Array", Vec as es _) -> do + ("Array", Vec as es _) -> do NullList as === (val ! "attrs" ! "_field0") es === (n ! "fields" ! 0) ("Call", Call as f es _) -> do NullList as === (val ! "attrs" ! "_field0") f === (n ! "fields" ! 0) es === (n ! "fields" ! 1) - ("MethodCall", MethodCall as o i tys es _) -> do + ("MethodCall", MethodCall as o i es _) -> do NullList as === (val ! "attrs" ! "_field0") - i === (n ! "fields" ! 0 ! "ident") - let tys' = n ! "fields" ! 0 ! "parameters" - tys === if (tys' == Data.Aeson.Null) - then tys' - else tys' ! "fields" ! 0 ! "types" - (o : es) === (n ! "fields" ! 1) + i === (n ! "fields" ! 0) + (o : es) === (n ! "fields" ! 1) ("Binary", Binary as o e1 e2 _) -> do NullList as === (val ! "attrs" ! "_field0") o === (n ! "fields" ! 0) - e1 === (n ! "fields" ! 1) - e2 === (n ! "fields" ! 2) + e1 === (n ! "fields" ! 1) + e2 === (n ! "fields" ! 2) ("Unary", Unary as o e _) -> do NullList as === (val ! "attrs" ! "_field0") o === (n ! "fields" ! 0) @@ -813,31 +883,38 @@ instance Show a => Diffable (Expr a) where NullList as === (val ! "attrs" ! "_field0") e === (n ! "fields" ! 0) t === (n ! "fields" ! 1) - ("Block", BlockExpr as b _) -> do + ("Block", BlockExpr as b l _) -> do NullList as === (val ! "attrs" ! "_field0") b === (n ! "fields" ! 0) + l === (n ! "fields" ! 1) ("If", If as e tb ee _) -> do NullList as === (val ! "attrs" ! "_field0") e === (n ! "fields" ! 0) tb === (n ! "fields" ! 1) ee === (n ! "fields" ! 2) - ("IfLet", IfLet as p e tb ee _) -> do + ("If", IfLet as p e tb ee _) -> do NullList as === (val ! "attrs" ! "_field0") - p === (n ! "fields" ! 0) - e === (n ! "fields" ! 1) - tb === (n ! "fields" ! 2) - ee === (n ! "fields" ! 3) + case n ! "fields" ! 0 ! "node" ! "variant" of + "Let" -> pure () + _ -> diff "expected `Let` for condition of `IfLet`" ex val + OrPatHack p === (n ! "fields" ! 0 ! "node" ! "fields" ! 0) + e === (n ! "fields" ! 0 ! "node" ! "fields" ! 1) + tb === (n ! "fields" ! 1) + ee === (n ! "fields" ! 2) ("While", While as e b l _) -> do NullList as === (val ! "attrs" ! "_field0") e === (n ! "fields" ! 0) b === (n ! "fields" ! 1) l === (n ! "fields" ! 2) - ("WhileLet", WhileLet as p e b l _) -> do + ("While", WhileLet as p e b l _) -> do NullList as === (val ! "attrs" ! "_field0") - p === (n ! "fields" ! 0) - e === (n ! "fields" ! 1) - b === (n ! "fields" ! 2) - l === (n ! "fields" ! 3) + case n ! "fields" ! 0 ! "node" ! "variant" of + "Let" -> pure () + _ -> diff "expected `Let` for condition of `WhileLet`" ex val + OrPatHack p === (n ! "fields" ! 0 ! "node" ! "fields" ! 0) + e === (n ! "fields" ! 0 ! "node" ! "fields" ! 1) + b === (n ! "fields" ! 1) + l === (n ! "fields" ! 2) ("Continue", Continue as l _) -> do NullList as === (val ! "attrs" ! "_field0") l === (n ! "fields" ! 0) @@ -859,13 +936,14 @@ instance Show a => Diffable (Expr a) where NullList as === (val ! "attrs" ! "_field0") l === (n ! "fields" ! 0) h === (n ! "fields" ! 1) - rl === (n ! "fields" ! 2) - ("Closure", Closure as m c decl e _) -> do + rl === (n ! "fields" ! 2) + ("Closure", Closure as c a m decl e _) -> do NullList as === (val ! "attrs" ! "_field0") - m === (n ! "fields" ! 1) c === (n ! "fields" ! 0) - decl === (n ! "fields" ! 2) - e === (n ! "fields" ! 3) + a === (n ! "fields" ! 1) + m === (n ! "fields" ! 2) + decl === (n ! "fields" ! 3) + e === (n ! "fields" ! 4) ("Assign", Assign as l r _) -> do NullList as === (val ! "attrs" ! "_field0") l === (n ! "fields" ! 0) @@ -908,14 +986,21 @@ instance Show a => Diffable (Expr a) where ("Repeat", Repeat as e1 e2 _) -> do NullList as === (val ! "attrs" ! "_field0") e1 === (n ! "fields" ! 0) - e2 === (n ! "fields" ! 1) + AnonConst e2 === (n ! "fields" ! 1) ("Paren", ParenExpr as e' _) -> do NullList as === (val ! "attrs" ! "_field0") e' === (n ! "fields" ! 0) ("Try", Try as e _) -> do NullList as === (val ! "attrs" ! "_field0") e === (n ! "fields" ! 0) - ("Catch", Catch as e _) -> do + ("TryBlock", TryBlock as e _) -> do + NullList as === (val ! "attrs" ! "_field0") + e === (n ! "fields" ! 0) + ("Async", Async as c e _) -> do + NullList as === (val ! "attrs" ! "_field0") + c === (n ! "fields" ! 0) + e === (n ! "fields" ! 2) + ("Await", Await as e _) -> do NullList as === (val ! "attrs" ! "_field0") e === (n ! "fields" ! 0) _ -> diff "differing expressions:" ex val @@ -935,8 +1020,19 @@ instance Diffable Movability where Movable === "Movable" = pure () m === val = diff "different movability" m val +instance Diffable IsAsync where + IsAsync === val | val !? "node" == Just "Async" = pure () + NotAsync === val | val !? "node" == Just "NotAsync" = pure () + IsAsync === val | val !? "variant" == Just "Async" = pure () + NotAsync === val | val !? "variant" == Just "NotAsync" = pure () + IsAsync === "Async" = pure () + NotAsync === "NotAsync" = pure () + a === val = diff "different async-ness" a val instance Diffable RangeLimits where + HalfOpen === val | Just "Excluded" <- val !? "node" = pure () + Closed === val | Just v <- val !? "node" + , Just "Included" <- v !? "variant" = pure () HalfOpen === "HalfOpen" = pure () Closed === "Closed" = pure () rl === val = diff "different range limits" rl val @@ -944,24 +1040,24 @@ instance Diffable RangeLimits where instance Diffable BinOp where b === val = case (val ! "node", b) of - ("Add", AddOp ) -> pure () - ("Sub", SubOp ) -> pure () - ("Mul", MulOp ) -> pure () - ("Div", DivOp ) -> pure () - ("Rem", RemOp ) -> pure () - ("And", AndOp ) -> pure () - ("Or", OrOp ) -> pure () - ("BitXor", BitXorOp) -> pure () - ("BitAnd", BitAndOp) -> pure () - ("BitOr", BitOrOp ) -> pure () - ("Shl", ShlOp ) -> pure () - ("Shr", ShrOp ) -> pure () - ("Eq", EqOp ) -> pure () - ("Lt", LtOp ) -> pure () - ("Le", LeOp ) -> pure () - ("Ne", NeOp ) -> pure () - ("Ge", GeOp ) -> pure () - ("Gt", GtOp ) -> pure () + ("Add", AddOp ) -> pure () + ("Sub", SubOp ) -> pure () + ("Mul", MulOp ) -> pure () + ("Div", DivOp ) -> pure () + ("Rem", RemOp ) -> pure () + ("And", AndOp ) -> pure () + ("Or", OrOp ) -> pure () + ("BitXor", BitXorOp) -> pure () + ("BitAnd", BitAndOp) -> pure () + ("BitOr", BitOrOp ) -> pure () + ("Shl", ShlOp ) -> pure () + ("Shr", ShrOp ) -> pure () + ("Eq", EqOp ) -> pure () + ("Lt", LtOp ) -> pure () + ("Le", LeOp ) -> pure () + ("Ne", NeOp ) -> pure () + ("Ge", GeOp ) -> pure () + ("Gt", GtOp ) -> pure () _ -> diff "different binary operation" b val instance Diffable UnOp where @@ -971,9 +1067,9 @@ instance Diffable UnOp where u === val = diff "different unary operator" u val instance Show a => Diffable (Arm a) where - Arm as ps g b _ === val = do + Arm as p g b _ === val = do as === (val ! "attrs") - ps === (val ! "pats") + OrPatHack p === (val ! "pats") g === (val ! "guard") b === (val ! "body") @@ -1026,17 +1122,17 @@ instance Diffable Suffix where Unsuffixed === "Unsuffixed" = pure () F32 === "F32" = pure () F64 === "F64" = pure () - Is === val | val ! "fields" == Data.Aeson.Array ["Isize"] = pure () - I8 === val | val ! "fields" == Data.Aeson.Array ["I8"] = pure () - I16 === val | val ! "fields" == Data.Aeson.Array ["I16"] = pure () - I32 === val | val ! "fields" == Data.Aeson.Array ["I32"] = pure () - I64 === val | val ! "fields" == Data.Aeson.Array ["I64"] = pure () - I128 === val | val ! "fields" == Data.Aeson.Array ["I128"] = pure () - Us === val | val ! "fields" == Data.Aeson.Array ["Usize"] = pure () - U8 === val | val ! "fields" == Data.Aeson.Array ["U8"] = pure () - U16 === val | val ! "fields" == Data.Aeson.Array ["U16"] = pure () - U32 === val | val ! "fields" == Data.Aeson.Array ["U32"] = pure () - U64 === val | val ! "fields" == Data.Aeson.Array ["U64"] = pure () - U128 === val | val ! "fields" == Data.Aeson.Array ["U128"] = pure () + Is === val | val ! "fields" == Data.Aeson.Array ["Isize"] = pure () + I8 === val | val ! "fields" == Data.Aeson.Array ["I8"] = pure () + I16 === val | val ! "fields" == Data.Aeson.Array ["I16"] = pure () + I32 === val | val ! "fields" == Data.Aeson.Array ["I32"] = pure () + I64 === val | val ! "fields" == Data.Aeson.Array ["I64"] = pure () + I128 === val | val ! "fields" == Data.Aeson.Array ["I128"] = pure () + Us === val | val ! "fields" == Data.Aeson.Array ["Usize"] = pure () + U8 === val | val ! "fields" == Data.Aeson.Array ["U8"] = pure () + U16 === val | val ! "fields" == Data.Aeson.Array ["U16"] = pure () + U32 === val | val ! "fields" == Data.Aeson.Array ["U32"] = pure () + U64 === val | val ! "fields" == Data.Aeson.Array ["U64"] = pure () + U128 === val | val ! "fields" == Data.Aeson.Array ["U128"] = pure () u === val = diff "different suffix" u val diff --git a/test/rustc-tests/DiffUtils.hs b/test/rustc-tests/DiffUtils.hs index 5e5f843..509bb8f 100644 --- a/test/rustc-tests/DiffUtils.hs +++ b/test/rustc-tests/DiffUtils.hs @@ -1,7 +1,4 @@ -{-# LANGUAGE CPP #-} -#if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -Wno-missing-methods #-} -#endif module DiffUtils where import qualified Data.Aeson as Aeson @@ -11,10 +8,9 @@ import qualified Data.List.NonEmpty as N import Control.Monad import Data.String import Data.ByteString.Lazy.Char8 (unpack) -import Control.Exception -import Data.Typeable import Data.Foldable import Data.Word (Word8) +import GHC.Stack -- | This type is a straightforward hack to let me index by both 'String' and 'Int' in '(!)' below. @@ -23,15 +19,20 @@ instance Num AesonKey where fromInteger = Index . fromIntegral instance IsString AesonKey where fromString = Key -- | Accessor method for JSON with helpful error messages. -(!) :: Aeson.Value -> AesonKey -> Aeson.Value +(!) :: HasCallStack => Aeson.Value -> AesonKey -> Aeson.Value val@(Aeson.Object hashmap) ! Key key = case HM.lookup (fromString key) hashmap of - Nothing -> error $ "No key `" ++ key ++ "' on JSON object `" ++ showAeson val ++ "'" + Nothing -> + let ks = unwords . map show $ HM.keys hashmap + suggestion + | HM.size hashmap < 8 = "\n(Possible keys: " ++ ks ++ ")" + | otherwise = "" + in error $ "No key `" ++ key ++ "' on JSON object `" ++ showAeson val ++ "'" ++ suggestion Just v -> v val ! Key key = error $ "Cannot lookup key `" ++ key ++ "' on non-object JSON `" ++ showAeson val ++ "'" val@(Aeson.Array vect) ! Index key = case vect V.!? key of - Nothing -> error $ "Index `" ++ show key ++ "' is OOB on JSON array `" ++ showAeson val ++ "'" + Nothing -> error $ "Index `" ++ show key ++ "' is OOB on JSON array `" ++ showAeson val ++ "' of size " ++ show (V.length vect) Just v -> v val ! Index key = error $ "Cannot lookup index `" ++ show key ++ "' on non-array JSON `" ++ showAeson val ++ "'" @@ -48,14 +49,9 @@ _ !? _ = Nothing -- | This lets us do whatever we want while comparing @rustc@ with our parser type Diff = IO () --- | This data type exists only as an easy way to throw a new type of error -data DiffError = DiffError String deriving (Typeable) -instance Exception DiffError -instance Show DiffError where show (DiffError msg) = msg - -- | Class of things that can be diff-ed against their JSON debug output class Show a => Diffable a where - (===) :: a -> Aeson.Value -> Diff + (===) :: HasCallStack => a -> Aeson.Value -> Diff instance Diffable a => Diffable (N.NonEmpty a) where xs === json = toList xs === json @@ -89,13 +85,13 @@ instance Diffable Int where (===) = diffIntegral instance Diffable Integer where (===) = diffIntegral -- | Diff something that is a number and can be shown -diffIntegral :: (Show i, Integral i) => i -> Aeson.Value -> Diff +diffIntegral :: (HasCallStack, Show i, Integral i) => i -> Aeson.Value -> Diff diffIntegral i (Aeson.Number s) | fromIntegral i == s = pure () diffIntegral i val = diff "different integral values" i val -- | Report a difference -diff :: Show a => String -> a -> Aeson.Value -> IO b -diff explanation v j = throw (DiffError msg) +diff :: (HasCallStack, Show a) => String -> a -> Aeson.Value -> IO b +diff explanation v j = error msg where msg = unlines [ explanation ++ " in" , " * parsed AST" , cropped (show v) @@ -105,5 +101,5 @@ diff explanation v j = throw (DiffError msg) cropped msg' | length msg' > 500 = take 500 msg' ++ "..." | otherwise = msg' - + diff --git a/test/rustc-tests/Main.hs b/test/rustc-tests/Main.hs index ae77f1d..52338b5 100644 --- a/test/rustc-tests/Main.hs +++ b/test/rustc-tests/Main.hs @@ -1,26 +1,28 @@ -{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE MultiParamTypeClasses, BangPatterns #-} module Main where import Diff () import DiffUtils +import Options import Control.Monad (filterM, when) import Control.Exception (catch, SomeException, evaluate) +import Data.Maybe (fromJust) import Data.Typeable (Typeable) import Data.ByteString.Lazy (hGetContents) import Data.ByteString.Lazy.Char8 (unpack) import Data.Aeson (decode', Value) - +import System.Directory import Language.Rust.Parser (readSourceFile) import Language.Rust.Pretty (prettyUnresolved, Resolve(..), Issue(..), Severity(Clean)) import Language.Rust.Syntax (SourceFile) import System.Directory (getCurrentDirectory, getTemporaryDirectory, listDirectory, doesFileExist, findExecutable) -import System.Process (withCreateProcess, proc, CreateProcess(..), StdStream(..), callProcess, readProcess) +import System.Process (createProcess, proc, CreateProcess(..), StdStream(..), callProcess, readProcess, waitForProcess) import System.FilePath ((), takeFileName) import System.IO (withFile, IOMode(WriteMode,ReadMode)) -import System.Exit (exitSuccess) +import System.Exit (exitSuccess, ExitCode(..)) import Data.Time.Clock (utctDay, getCurrentTime) import Data.Time.Calendar (fromGregorian, showGregorian, diffDays) @@ -28,20 +30,24 @@ import Data.Time.Calendar (fromGregorian, showGregorian, diffDays) import qualified Data.Text.Prettyprint.Doc as PP import Data.Text.Prettyprint.Doc.Render.Text (renderIO) -import Test.Framework (defaultMain) +import Test.Framework (defaultMainWithOpts) import Test.Framework.Providers.API + main :: IO () main = do + -- Parse out command line options + (opts, runnerOpts) <- getOptions + -- Check last time `rustc` version was bumped - let lastDay = fromGregorian 2018 4 19 + let lastDay = fromGregorian 2019 09 6 today <- utctDay <$> getCurrentTime when (diffDays today lastDay > 32) $ putStrLn $ "\x1b[33m" ++ "\nThe version of `rustc' the tests will try to use is older than 1 month" ++ "\x1b[0m" -- Don't bother running the tests if you don't have `rustup` or `rustc` installed. missingProgs <- any null <$> traverse findExecutable ["rustup","rustc"] - when missingProgs $ do + when missingProgs $ do putStrLn $ "Could not find `rustup`/`rustc`, so skipping these tests" exitSuccess @@ -52,25 +58,37 @@ main = do -- Run the tests workingDirectory <- getCurrentDirectory - let folder = workingDirectory "sample-sources" + let folder = workingDirectory sourceFolder opts entries <- map (folder ) <$> listDirectory folder files <- filterM doesFileExist (filter (/= folder ".benchignore") entries) - defaultMain (map (\f -> Test (takeFileName f) (DiffTest f)) files) + let tests = [ Test (takeFileName f) (DiffTest (pruneTests opts) f) | f <- files ] + defaultMainWithOpts tests runnerOpts -- | Given a path pointing to a rust source file, read that file and parse it into JSON -getJsonAST :: FilePath -> IO Value -getJsonAST fileName = do +getJsonAST + :: Bool -- ^ delete the test case if it can't be parsed and return 'Nothing' + -> FilePath -- ^ test case path + -> IO (Maybe Value) -- ^ the JSON AST (this will error instead of returning 'Nothing' unless the + -- first argument is 'True') +getJsonAST deleteOnFailure fileName = do let cp = (proc "rustc" [ "-Z", "ast-json-noexpand" , "-Z", "no-analysis" + , "--edition", "2018" , fileName ]){ std_out = CreatePipe , std_err = NoStream , std_in = NoStream } - withCreateProcess cp $ \_ (Just hOut) _ _ -> do - jsonContents <- hGetContents hOut - case decode' jsonContents of - Just value -> pure value - Nothing -> error ("Failed to get `rustc' JSON\n" ++ unpack jsonContents) + (_, Just hOut, _, ph) <- createProcess cp + !jsonContents <- hGetContents hOut + let !jsonAstOpt = decode' jsonContents + exitCode <- waitForProcess ph + case jsonAstOpt of + _ | exitCode /= ExitSuccess + -> if deleteOnFailure + then removeFile fileName *> pure Nothing + else error "`rustc' exitted with non-zero code" + Just jsonAst -> pure (Just jsonAst) + Nothing -> error ("Failed to get `rustc' JSON\n" ++ unpack jsonContents) -- | Given an AST and a file name, print it into a temporary file (without resolving) and return -- that path @@ -91,8 +109,9 @@ resolveDiff ast = when (sev /= Clean) $ -- * Difference tests --- | A 'DiffTest' only needs to know the name of the file it is diffing -data DiffTest = DiffTest String +-- | A 'DiffTest' only needs to know the name of the file it is diffing and whether failed tests +-- should be skipped +data DiffTest = DiffTest Bool String -- | These are the possible pending statuses of a 'DiffTest' data DiffRunning = ParsingReference @@ -116,29 +135,35 @@ instance Show DiffRunning where -- | These are the possible final states of a 'DiffTest' data DiffResult = Error DiffRunning String | Done + | Skipped String instance Show DiffResult where show (Error improvement message) = "ERROR (" ++ show improvement ++ "): " ++ message show Done = "OK" + show (Skipped reason) = "SKIPPED: " ++ reason -- | A test is successful if it finishes and has no diffs instance TestResultlike DiffRunning DiffResult where testSucceeded Done = True + testSucceeded (Skipped _) = True testSucceeded (Error _ _) = False -- | With timeouts and catching errors instance Testlike DiffRunning DiffResult DiffTest where testTypeName _ = "Difference tests" - runTest TestOptions{ topt_timeout = K timeout } (DiffTest file) = runImprovingIO $ - step timeout ParsingReference (getJsonAST file) $ \parsedRustc -> - step timeout ParsingImplementation (evaluate =<< withFile file ReadMode readSourceFile) $ \parsedOurs -> - step timeout ParsingDiffing (parsedOurs === parsedRustc) $ \_ -> - step timeout PrintingParsed (prettySourceFile file parsedOurs) $ \tmpFile -> - step timeout ReparsingReference (getJsonAST tmpFile) $ \reparsedRustc -> - step timeout ReparsingDiffing (parsedOurs === reparsedRustc) $ \_ -> - step timeout ResolveInvariant (resolveDiff parsedOurs) $ \_ -> - pure Done + runTest TestOptions{ topt_timeout = K timeout } (DiffTest pruneFail file) = runImprovingIO $ + step timeout ParsingReference (getJsonAST pruneFail file) $ \parsedRustcOpt -> + case parsedRustcOpt of + Nothing -> pure (Skipped "`rustc` can't parse") + Just parsedRustc -> + step timeout ParsingImplementation (evaluate =<< withFile file ReadMode readSourceFile) $ \parsedOurs -> + step timeout ParsingDiffing (parsedOurs === parsedRustc) $ \_ -> + step timeout PrintingParsed (prettySourceFile file parsedOurs) $ \tmpFile -> + step timeout ReparsingReference (getJsonAST False tmpFile) $ \reparsedRustcOpt -> + step timeout ReparsingDiffing (parsedOurs === fromJust reparsedRustcOpt) $ \_ -> + step timeout ResolveInvariant (resolveDiff parsedOurs) $ \_ -> + pure Done step :: Maybe Int -- ^ timeout for the step @@ -153,9 +178,8 @@ step timeout improvement action continuation = do Nothing -> pure (Error improvement "Timed out") Just (Left e) -> pure (Error improvement e) Just (Right val) -> continuation val - - + -- | Variant of 'try' which separates the error case by just returning 'Left msg' when there is an -- exception. diff --git a/test/rustc-tests/Options.hs b/test/rustc-tests/Options.hs new file mode 100644 index 0000000..8d3847b --- /dev/null +++ b/test/rustc-tests/Options.hs @@ -0,0 +1,54 @@ +module Options ( getOptions, RustcTestsConfig(..) ) where + +import Prelude hiding ( fail ) + +import System.Console.GetOpt +import System.Environment ( getArgs, getProgName ) +import Control.Monad.Fail ( fail ) +import Data.Either ( partitionEithers ) + +import Test.Framework.Runners.Console +import Test.Framework.Runners.Options + +-- | Configuration settings for `rustc-tests` +data RustcTestsConfig = RTS + { sourceFolder :: FilePath + , pruneTests :: Bool + } + +-- | Base configuration +defaultConfig :: RustcTestsConfig +defaultConfig = RTS + { sourceFolder = "sample-sources" + , pruneTests = False + } + +type RustcTestsOptions = RustcTestsConfig -> RustcTestsConfig + +-- | Command-line options for modifying the config +options :: [OptDescr RustcTestsOptions] +options = [ Option [] ["rust-sources"] + (ReqArg (\f r -> r { sourceFolder = f }) "FOLDER") + "Folder containing rust file test cases" + , Option [] ["prune-failing-rustc"] + (NoArg (\r -> r { pruneTests = True })) + "Remove test cases which `rustc` can't initially parse" + ] + +fullOptions :: [OptDescr (Either RustcTestsOptions SuppliedRunnerOptions)] +fullOptions = map (fmap Left) options ++ map (fmap Right) optionsDescription + +-- | Parse out options from the command line arguments +getOptions :: IO (RustcTestsConfig, RunnerOptions) +getOptions = do + args <- getArgs + prog <- getProgName + let header = "Usage: " ++ prog ++ " [OPTION...]" + case getOpt Permute fullOptions args of + (o, [], []) -> let (ourOpts, optTestFrameworkOpts) = partitionEithers o + testFrameworkOpts = sequence optTestFrameworkOpts + in case testFrameworkOpts of + Nothing -> fail (usageInfo header fullOptions) + Just theirOpts -> pure ( foldl (flip id) defaultConfig ourOpts + , mconcat theirOpts ) + (_, _, errs) -> fail (concat errs ++ usageInfo header fullOptions) diff --git a/test/unit-tests/CompleteTest.hs b/test/unit-tests/CompleteTest.hs index 553159f..8ce8787 100644 --- a/test/unit-tests/CompleteTest.hs +++ b/test/unit-tests/CompleteTest.hs @@ -15,7 +15,7 @@ import Data.Text.Prettyprint.Doc.Render.String (renderShowS) -- The following tests render with width 50 and ribbon length 50 too. -- | | -completeSuite :: Test +completeSuite :: Test completeSuite = testGroup "complete suite" [ testComplete "short mod" "mod foo { }" @@ -37,7 +37,7 @@ completeSuite = testGroup "complete suite" , structs , enums , matchExpressions - ] + ] functionArgs :: Test functionArgs = testGroup "function args" @@ -139,7 +139,7 @@ methodCalls = testGroup "method calls" \ .foo\n\ \ .bar[0]\n\ \ .baz?\n\ - \}" + \}" ] lets :: Test @@ -291,6 +291,23 @@ typeAliases = testGroup "type aliases" \where\n\ \ T: Copy,\n\ \= Vec;" + , testComplete "long type" + "type F =\n\ + \ (\n\ + \ Box<\n\ + \ dyn\n\ + \ FnOnce(\n\ + \ &BuildDeps,\n\ + \ Option<\n\ + \ &dyn Fn() -> CargoResult,\n\ + \ >,\n\ + \ ) -> CargoResult<\n\ + \ Option>,\n\ + \ > +\n\ + \ Send +,\n\ + \ >,\n\ + \ bool,\n\ + \ );" ] traits :: Test @@ -432,6 +449,6 @@ testComplete name inp = testCase name $ do -- Pretty print it let opts = LayoutOptions (AvailablePerLine 50 1.0) inp' = renderShowS (layoutPretty opts (pretty' x)) "" - + -- Assert that the input and output are the same inp @=? inp' diff --git a/test/unit-tests/LexerTest.hs b/test/unit-tests/LexerTest.hs index 12e7768..445d197 100644 --- a/test/unit-tests/LexerTest.hs +++ b/test/unit-tests/LexerTest.hs @@ -15,11 +15,11 @@ import Language.Rust.Data.InputStream lexerSuite :: Test lexerSuite = testGroup "lexer suite" [ commonCode, literals ] --- | This contains some random real-life code fragments. The purpose here is +-- | This contains some random real-life code fragments. The purpose here is -- primarily black-box testing. commonCode :: Test commonCode = testGroup "lexing common code fragments" - [ testCode "let span = $p.span;" + [ testCode "let span = $p.span;" [ IdentTok (mkIdent "let") , Space Whitespace " " , IdentTok (mkIdent "span") @@ -32,7 +32,7 @@ commonCode = testGroup "lexing common code fragments" , IdentTok (mkIdent "span") , Semicolon ] - , testCode "$(p.span),+" + , testCode "$(p.span),+" [ Dollar , OpenDelim Paren , IdentTok (mkIdent "p") @@ -94,7 +94,7 @@ commonCode = testGroup "lexing common code fragments" [ IdentTok (mkIdent "fn") , Space Whitespace " " , IdentTok (mkIdent "ܐ_ܐ") - , OpenDelim Paren + , OpenDelim Paren , CloseDelim Paren , Space Whitespace " " , OpenDelim Brace diff --git a/test/unit-tests/ParserTest.hs b/test/unit-tests/ParserTest.hs index 5570849..c0322ec 100644 --- a/test/unit-tests/ParserTest.hs +++ b/test/unit-tests/ParserTest.hs @@ -36,21 +36,30 @@ parserSuite = testGroup "parser suite" ] -- | Create a test for a code fragment that should parse to a type. -testP :: forall f. +testP :: forall f. (Parse (f Span), Pretty (f ()), Resolve (f ()), Functor f, Show (f ()), Eq (f ()), Data (f Span)) => TestName -> f () -> Test testP inp y = testCase inp $ do -- parse test - Right y @=? parseNoSpans parser inps - + assertEqual + "Incorrect parsing output:" + (Right y) + (parseNoSpans parser inps) + -- resolve test - Right y @=? either (\(ResolveFail _ msg) -> Left msg) Right (resolve y) - + assertEqual + "Resolving the parsed output was not idempotent:" + (Right y) + (either (\(ResolveFail _ msg) -> Left msg) Right (resolve y)) + -- re-parse the result of printing resolve - Right y @=? case pretty y of - Left (ResolveFail _ msg) -> Left msg - Right inp' -> parseNoSpans parser (inputStreamFromString (show inp')) - + assertEqual + "Re-parsing pretty-printed output is not idempotent:" + (Right y) + (case pretty y of + Left (ResolveFail _ msg) -> Left msg + Right inp' -> parseNoSpans parser (inputStreamFromString (show inp'))) + -- check that the sub-spans re-parse correctly let Right y' = parse inps checkSubterms inps (y' :: f Span) @@ -72,13 +81,12 @@ checkTerm inp y = sequence_ $ catMaybes tests , checkTerm' (Proxy :: Proxy Ty) inp <$> cast y , checkTerm' (Proxy :: Proxy Pat) inp <$> cast y , checkTerm' (Proxy :: Proxy Expr) inp <$> cast y - -- , checkTerm' (Proxy :: Proxy Stmt) inp <$> cast y + -- , checkTerm' (Proxy :: Proxy Stmt) inp <$> cast y , checkTerm' (Proxy :: Proxy Item) inp <$> cast y - -- , checkTerm' (Proxy :: Proxy TyParamBound) inp <$> cast y - , checkTerm' (Proxy :: Proxy TyParam) inp <$> cast y + -- , checkTerm' (Proxy :: Proxy GenericBound) inp <$> cast y + , checkTerm' (Proxy :: Proxy GenericParam) inp <$> cast y , checkTerm' (Proxy :: Proxy TraitItem) inp <$> cast y , checkTerm' (Proxy :: Proxy ImplItem) inp <$> cast y - , checkTerm' (Proxy :: Proxy LifetimeDef) inp <$> cast y , checkTerm' (Proxy :: Proxy Block) inp <$> cast y ] @@ -96,10 +104,10 @@ checkTerm inp y = sequence_ $ catMaybes tests slice (Span (Position s _ _) (Position e _ _)) str = Just . take (e - s) . drop s $ str slice _ _ = Nothing - + checkSubterms :: Data a => InputStream -> a -> IO () checkSubterms inp y = checkTerm inp y *> gmapQl (*>) (pure ()) (checkSubterms inp) y - + -- | Turn an InputStream into either an error or a parse. parseNoSpans :: Functor f => P (f Span) -> InputStream -> Either String (f ()) @@ -119,7 +127,7 @@ parserLiterals = testGroup "parsing literals" , testP "b'\\n'" (Byte 10 Unsuffixed ()) -- char's , testP "'a'" (Char 'a' Unsuffixed ()) - , testP "'\\n'" (Char '\n' Unsuffixed ()) + , testP "'\\n'" (Char '\n' Unsuffixed ()) -- integers , testP "123" (Int Dec 123 Unsuffixed ()) , testP "123i32" (Int Dec 123 I32 ()) @@ -137,7 +145,7 @@ parserLiterals = testGroup "parsing literals" , testP "123e-9f32" (Float 123e-9 F32 ()) -- string's , testP "\"hello \\n world!\"" (Str "hello \n world!" Cooked Unsuffixed ()) - , testP "r\"hello \n world!\"" (Str "hello \n world!" (Raw 0) Unsuffixed ()) + , testP "r\"hello \n world!\"" (Str "hello \n world!" (Raw 0) Unsuffixed ()) , testP "r##\"hello \"#\n world!\"##" (Str "hello \"#\n world!" (Raw 2) Unsuffixed ()) -- bytestring's , testP "b\"hello \\n world!\"" (byteStr "hello \n world!" Cooked Unsuffixed ()) @@ -166,7 +174,7 @@ t = Path False [PathSegment "T" Nothing ()] () -- | Test parsing of (inner and outer) attributes. parserAttributes :: Test -parserAttributes = testGroup "parsing attributes" +parserAttributes = testGroup "parsing attributes" [ testP "#![cfgi]" (Attribute Inner cfgi (Stream []) ()) , testP "#[cfgo]" (Attribute Outer cfgo (Stream []) ()) , testP "#[derive(Eq, Ord, 1)]" (Attribute Outer derive (Tree (Delimited (Span (Position 8 1 8) (Position 20 1 20)) Paren (Stream @@ -219,19 +227,19 @@ parserTypes = testGroup "parsing types" , testP "!" (Never ()) , testP "i32" i32 , testP "Self" (PathTy Nothing (Path False [PathSegment "Self" Nothing ()] ()) ()) - , testP "?Debug" (TraitObject [TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) Maybe ()] ()) - , testP "Debug + ?Send + 'a" (TraitObject [ TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) None () - , TraitTyParamBound (PolyTraitRef [] (TraitRef send) ()) Maybe () - , RegionTyParamBound (Lifetime "a" ()) () + , testP "?Debug" (TraitObject [TraitBound (PolyTraitRef [] (TraitRef debug) ()) Maybe ()] ()) + , testP "Debug + ?Send + 'a" (TraitObject [ TraitBound (PolyTraitRef [] (TraitRef debug) ()) None () + , TraitBound (PolyTraitRef [] (TraitRef send) ()) Maybe () + , OutlivesBound (Lifetime "a" ()) () ] ()) - , testP "?for<'a> Debug" (TraitObject [TraitTyParamBound (PolyTraitRef [LifetimeDef [] (Lifetime "a" ()) [] ()] (TraitRef debug) ()) Maybe ()] ()) - , testP "?for<'a> Debug + 'a" (TraitObject [ TraitTyParamBound (PolyTraitRef [LifetimeDef [] (Lifetime "a" ()) [] ()] (TraitRef debug) ()) Maybe () - , RegionTyParamBound (Lifetime "a" ()) () + , testP "?for<'a> Debug" (TraitObject [TraitBound (PolyTraitRef [LifetimeParam [] (Lifetime "a" ()) [] ()] (TraitRef debug) ()) Maybe ()] ()) + , testP "?for<'a> Debug + 'a" (TraitObject [ TraitBound (PolyTraitRef [LifetimeParam [] (Lifetime "a" ()) [] ()] (TraitRef debug) ()) Maybe () + , OutlivesBound (Lifetime "a" ()) () ] ()) , testP "Send + ?for<'a> Debug + 'a" (TraitObject - [ TraitTyParamBound (PolyTraitRef [] (TraitRef send) ()) None () - , TraitTyParamBound (PolyTraitRef [LifetimeDef [] (Lifetime "a" ()) [] ()] (TraitRef debug) ()) Maybe () - , RegionTyParamBound (Lifetime "a" ()) () + [ TraitBound (PolyTraitRef [] (TraitRef send) ()) None () + , TraitBound (PolyTraitRef [LifetimeParam [] (Lifetime "a" ()) [] ()] (TraitRef debug) ()) Maybe () + , OutlivesBound (Lifetime "a" ()) () ] ()) , testP "(i32,)" (TupTy [i32] ()) , testP "(i32,())" (TupTy [i32, TupTy [] ()] ()) @@ -252,31 +260,41 @@ parserTypes = testGroup "parsing types" , testP "&i32" (Rptr Nothing Immutable i32 ()) , testP "&'lt mut i32" (Rptr (Just (Lifetime "lt" ())) Mutable i32 ()) , testP "typeof(123)" (Typeof (Lit [] (Int Dec 123 Unsuffixed ()) ()) ()) - , testP "Vec" (PathTy Nothing (Path False [PathSegment "Vec" (Just (AngleBracketed [] [i32] [] ())) ()] ()) ()) - , testP "Vec" (PathTy Nothing (Path False [PathSegment "Vec" (Just (AngleBracketed [] [i32] [] ())) ()] ()) ()) - , testP "Vec<::b,i32>" (PathTy Nothing (Path False [PathSegment "Vec" (Just (AngleBracketed [] [ PathTy (Just (QSelf i32 1)) + , testP "Vec" (PathTy Nothing (Path False [PathSegment "Vec" (Just (AngleBracketed [TypeArg i32] [] ())) ()] ()) ()) + , testP "Vec::" (PathTy Nothing (Path False [PathSegment "Vec" (Just (AngleBracketed [TypeArg i32] [] ())) ()] ()) ()) + , testP "Vec<{x}>" (PathTy Nothing (Path False [PathSegment "Vec" (Just (AngleBracketed [ConstArg (BlockExpr [] (Block [NoSemi (PathExpr [] Nothing x ()) ()] Normal ()) Nothing ())] [] ())) ()] ()) ()) + , testP "Vec<29, {x+1}>" (PathTy Nothing (Path False [PathSegment "Vec" (Just (AngleBracketed [ConstArg (Lit [] (Int Dec 29 Unsuffixed ()) ()), ConstArg (BlockExpr [] (Block [NoSemi (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) ()] Normal ()) Nothing ())] [] ())) ()] ()) ()) + , testP "Vec<::b,i32>" (PathTy Nothing (Path False [PathSegment "Vec" (Just (AngleBracketed [ TypeArg (PathTy (Just (QSelf i32 1)) (Path False [ PathSegment "a" Nothing () , PathSegment "b" Nothing () - ] ()) () - , i32] [] ())) ()] ()) ()) - , testP "Vec< ::b,i32>" (PathTy Nothing (Path False [PathSegment "Vec" (Just (AngleBracketed [] [ PathTy (Just (QSelf i32 1)) + ] ()) ()) + , TypeArg i32 ] [] ())) ()] ()) ()) + , testP "Vec< ::b,i32>" (PathTy Nothing (Path False [PathSegment "Vec" (Just (AngleBracketed [ TypeArg (PathTy (Just (QSelf i32 1)) (Path False [ PathSegment "a" Nothing () , PathSegment "b" Nothing () - ] ()) () - , i32] [] ())) ()] ()) ()) - , testP "std::vec::Vec" (PathTy Nothing (Path False [ PathSegment "std" Nothing () - , PathSegment "vec" Nothing () - , PathSegment "Vec" (Just (AngleBracketed [] [PathTy Nothing t ()] [] ())) () + ] ()) ()) + , TypeArg i32 ] [] ())) ()] ()) ()) + , testP "std::vec::Vec" (PathTy Nothing (Path False [ PathSegment "std" Nothing () + , PathSegment "vec" Nothing () + , PathSegment "Vec" (Just (AngleBracketed [TypeArg (PathTy Nothing t ())] [] ())) () ] ()) ()) + , testP "std::vec::Vec::" (PathTy Nothing (Path False [ PathSegment "std" Nothing () + , PathSegment "vec" Nothing () + , PathSegment "Vec" (Just (AngleBracketed [TypeArg (PathTy Nothing t ())] [] ())) () + ] ()) ()) , testP "foo::baz<'a,T,B=!>" (PathTy Nothing (Path False [ PathSegment "foo" Nothing () - , PathSegment "baz" (Just (AngleBracketed [Lifetime "a" ()] - [PathTy Nothing t () ] - [(mkIdent "B", Never ())] ())) () + , PathSegment "baz" (Just (AngleBracketed [LifetimeArg (Lifetime "a" ()), TypeArg (PathTy Nothing t ())] + [EqualityConstraint (mkIdent "B") (Never ()) ()] ())) () ] ()) ()) , testP "Foo(!,!)" (PathTy Nothing (Path False [ PathSegment "Foo" (Just (Parenthesized [Never (), Never ()] Nothing ())) () ] ()) ()) , testP "Foo(!,!,)" (PathTy Nothing (Path False [ PathSegment "Foo" (Just (Parenthesized [Never (), Never ()] Nothing ())) () ] ()) ()) , testP "Foo(!,!) -> !" (PathTy Nothing (Path False [ PathSegment "Foo" (Just (Parenthesized [Never (), Never ()] (Just (Never ())) ())) () ] ()) ()) , testP "Foo(!,!,) -> !" (PathTy Nothing (Path False [ PathSegment "Foo" (Just (Parenthesized [Never (), Never ()] (Just (Never ())) ())) () ] ()) ()) + , testP "<'a + Trait>::AssocTy" + (PathTy (Just (QSelf (TraitObject [ OutlivesBound (Lifetime "a" ()) () + , TraitBound (PolyTraitRef [] (TraitRef (Path False [PathSegment "Trait" Nothing ()] ())) ()) None () + ] ()) 0)) + (Path False [PathSegment "AssocTy" Nothing ()] ()) ()) , testP "::b" (PathTy (Just (QSelf i32 1)) (Path False [ PathSegment "a" Nothing () , PathSegment "b" Nothing () @@ -309,9 +327,9 @@ parserTypes = testGroup "parsing types" ()) , testP "< ::AssociatedItem as x>::Another" (PathTy (Just (QSelf (PathTy (Just (QSelf - (TraitObject [ TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) None () - , RegionTyParamBound (Lifetime "static" ()) () - ] ()) 3)) + (TraitObject [ TraitBound (PolyTraitRef [] (TraitRef debug) ()) None () + , OutlivesBound (Lifetime "static" ()) () + ] ()) 3)) (Path False [ PathSegment "a" Nothing () , PathSegment "b" Nothing () , PathSegment "Trait" Nothing () @@ -323,9 +341,9 @@ parserTypes = testGroup "parsing types" ()) , testP "<::AssociatedItem as x>::Another" (PathTy (Just (QSelf (PathTy (Just (QSelf - (TraitObject [ TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) None () - , RegionTyParamBound (Lifetime "static" ()) () - ] ()) 3)) + (TraitObject [ TraitBound (PolyTraitRef [] (TraitRef debug) ()) None () + , OutlivesBound (Lifetime "static" ()) () + ] ()) 3)) (Path False [ PathSegment "a" Nothing () , PathSegment "b" Nothing () , PathSegment "Trait" Nothing () @@ -337,78 +355,87 @@ parserTypes = testGroup "parsing types" ()) , testP "::Trait(i32) -> i32>::AssociatedItem" (PathTy (Just (QSelf i32 3)) (Path False [ PathSegment "a" (Just (Parenthesized [i32, i32] Nothing ())) () - , PathSegment "b" (Just (AngleBracketed [Lifetime "lt" ()] [] [] ())) () + , PathSegment "b" (Just (AngleBracketed [LifetimeArg (Lifetime "lt" ())] [] ())) () + , PathSegment "Trait" (Just (Parenthesized [i32] (Just i32) ())) () + , PathSegment "AssociatedItem" Nothing () + ] ()) ()) + , testP "::Trait::(i32) -> i32>::AssociatedItem" + (PathTy (Just (QSelf i32 3)) (Path False [ PathSegment "a" (Just (Parenthesized [i32, i32] Nothing ())) () + , PathSegment "b" (Just (AngleBracketed [LifetimeArg (Lifetime "lt" ())] [] ())) () , PathSegment "Trait" (Just (Parenthesized [i32] (Just i32) ())) () , PathSegment "AssociatedItem" Nothing () ] ()) ()) , testP "extern fn(i32,...)" - (BareFn Normal C [] (FnDecl [Arg Nothing i32 ()] Nothing True ()) ()) + (BareFn Normal C [] (FnDecl [Arg [] Nothing i32 ()] Nothing True ()) ()) , testP "fn(i32) -> i32" - (BareFn Normal Rust [] (FnDecl [Arg Nothing i32 ()] (Just i32) False ()) ()) + (BareFn Normal Rust [] (FnDecl [Arg [] Nothing i32 ()] (Just i32) False ()) ()) , testP "fn(i32,) -> i32" - (BareFn Normal Rust [] (FnDecl [Arg Nothing i32 ()] (Just i32) False ()) ()) + (BareFn Normal Rust [] (FnDecl [Arg [] Nothing i32 ()] (Just i32) False ()) ()) , testP "fn(_: i32) -> i32" - (BareFn Normal Rust [] (FnDecl [Arg (Just (WildP ())) i32 ()] (Just i32) False ()) ()) + (BareFn Normal Rust [] (FnDecl [Arg [] (Just (WildP ())) i32 ()] (Just i32) False ()) ()) , testP "unsafe extern \"C\" fn(_: i32)" - (BareFn Unsafe C [] (FnDecl [Arg (Just (WildP ())) i32 ()] Nothing False ()) ()) + (BareFn Unsafe C [] (FnDecl [Arg [] (Just (WildP ())) i32 ()] Nothing False ()) ()) , testP "fn(i32) -> impl Debug + Clone" - (BareFn Normal Rust [] (FnDecl [Arg Nothing i32 ()] (Just (ImplTrait - [ TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) None () - , TraitTyParamBound (PolyTraitRef [] (TraitRef clone) ()) None () + (BareFn Normal Rust [] (FnDecl [Arg [] Nothing i32 ()] (Just (ImplTrait + [ TraitBound (PolyTraitRef [] (TraitRef debug) ()) None () + , TraitBound (PolyTraitRef [] (TraitRef clone) ()) None () ] ())) False ()) ()) , testP "PResult<'a, P>" - (PathTy Nothing (Path False [PathSegment "PResult" (Just (AngleBracketed [ Lifetime "a" () ] - [ PathTy Nothing (Path False [PathSegment "P" (Just (AngleBracketed [] [ i32 ] [] ())) ()] ()) () ] + (PathTy Nothing (Path False [PathSegment "PResult" (Just (AngleBracketed [ LifetimeArg (Lifetime "a" ()) + , TypeArg (PathTy Nothing (Path False [PathSegment "P" (Just (AngleBracketed [ TypeArg i32 ] [] ())) ()] ()) ()) ] [] ())) ()] ()) ()) , testP "for<'l1: 'l2 + 'l3, 'l4: 'l5 +,> fn(_: Trait + 'l1 +) -> i32" (BareFn Normal Rust - [ LifetimeDef [] (Lifetime "l1" ()) [Lifetime "l2" (), Lifetime "l3" ()] () - , LifetimeDef [] (Lifetime "l4" ()) [Lifetime "l5" ()] () ] - (FnDecl [Arg (Just (WildP ())) (TraitObject [TraitTyParamBound (PolyTraitRef [] (TraitRef (Path False [PathSegment "Trait" Nothing ()] ())) ()) None (), RegionTyParamBound (Lifetime "l1" ()) ()] ()) ()] + [ LifetimeParam [] (Lifetime "l1" ()) [OutlivesBound (Lifetime "l2" ()) (), OutlivesBound (Lifetime "l3" ()) ()] () + , LifetimeParam [] (Lifetime "l4" ()) [OutlivesBound (Lifetime "l5" ()) ()] () ] + (FnDecl [Arg [] (Just (WildP ())) (TraitObject [TraitBound (PolyTraitRef [] (TraitRef (Path False [PathSegment "Trait" Nothing ()] ())) ()) None (), OutlivesBound (Lifetime "l1" ()) ()] ()) ()] (Just i32) False ()) ()) , testP "for <'a> Foo<&'a T>" (TraitObject - [TraitTyParamBound - (PolyTraitRef [LifetimeDef [] (Lifetime "a" ()) [] ()] - (TraitRef (Path False [PathSegment "Foo" (Just (AngleBracketed [] [Rptr (Just (Lifetime "a" ())) + [TraitBound + (PolyTraitRef [LifetimeParam [] (Lifetime "a" ()) [] ()] + (TraitRef (Path False [PathSegment "Foo" (Just (AngleBracketed [ TypeArg (Rptr (Just (Lifetime "a" ())) Immutable (PathTy Nothing t ()) - ()] + ()) ] [] ())) ()] ())) ()) None ()] ()) , testP "for <'a,> Debug + for <'b> Send + for <'c> Sync" (TraitObject - [ TraitTyParamBound (PolyTraitRef [LifetimeDef [] (Lifetime "a" ()) [] ()] + [ TraitBound (PolyTraitRef [LifetimeParam [] (Lifetime "a" ()) [] ()] (TraitRef debug) ()) None () - , TraitTyParamBound (PolyTraitRef [LifetimeDef [] (Lifetime "b" ()) [] ()] + , TraitBound (PolyTraitRef [LifetimeParam [] (Lifetime "b" ()) [] ()] (TraitRef send) ()) None () - , TraitTyParamBound (PolyTraitRef [LifetimeDef [] (Lifetime "c" ()) [] ()] + , TraitBound (PolyTraitRef [LifetimeParam [] (Lifetime "c" ()) [] ()] (TraitRef (Path False [PathSegment "Sync" Nothing ()] ())) ()) None () ] ()) , testP "&(Debug + Send)" (Rptr Nothing Immutable (ParenTy - (TraitObject [ TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) None () - , TraitTyParamBound (PolyTraitRef [] (TraitRef send) ()) None () + (TraitObject [ TraitBound (PolyTraitRef [] (TraitRef debug) ()) None () + , TraitBound (PolyTraitRef [] (TraitRef send) ()) None () ] ()) ()) ()) , testP "&(for<'a> Tr<'a> + Send)" (Rptr Nothing Immutable (ParenTy - (TraitObject [ TraitTyParamBound (PolyTraitRef [LifetimeDef [] (Lifetime "a" ()) [] ()] (TraitRef (Path False [PathSegment "Tr" (Just (AngleBracketed [Lifetime "a" ()] [] [] ())) ()] ())) ()) None () - , TraitTyParamBound (PolyTraitRef [] (TraitRef send) ()) None () + (TraitObject [ TraitBound (PolyTraitRef [LifetimeParam [] (Lifetime "a" ()) [] ()] (TraitRef (Path False [PathSegment "Tr" (Just (AngleBracketed [LifetimeArg (Lifetime "a" ())] [] ())) ()] ())) ()) None () + , TraitBound (PolyTraitRef [] (TraitRef send) ()) None () ] ()) ()) ()) , testP "Fn() -> &(Object+Send)" - (PathTy Nothing (Path False [PathSegment "Fn" (Just (Parenthesized [] (Just (Rptr Nothing Immutable (ParenTy (TraitObject [ TraitTyParamBound (PolyTraitRef [] (TraitRef (Path False [PathSegment "Object" Nothing ()] ())) ()) None () - , TraitTyParamBound (PolyTraitRef [] (TraitRef send) ()) None ()] ()) ()) ())) ())) ()] ()) ()) + (PathTy Nothing (Path False [PathSegment "Fn" (Just (Parenthesized [] (Just (Rptr Nothing Immutable (ParenTy (TraitObject [ TraitBound (PolyTraitRef [] (TraitRef (Path False [PathSegment "Object" Nothing ()] ())) ()) None () + , TraitBound (PolyTraitRef [] (TraitRef send) ()) None ()] ()) ()) ())) ())) ()] ()) ()) + , testP "Fn::() -> &(Object+Send)" + (PathTy Nothing (Path False [PathSegment "Fn" (Just (Parenthesized [] (Just (Rptr Nothing Immutable (ParenTy (TraitObject [ TraitBound (PolyTraitRef [] (TraitRef (Path False [PathSegment "Object" Nothing ()] ())) ()) None () + , TraitBound (PolyTraitRef [] (TraitRef send) ()) None ()] ()) ()) ())) ())) ()] ()) ()) , testP "foo![ x ]" (MacTy (Mac (Path False [PathSegment "foo" Nothing ()] ()) (Tree (Token (Span (Position 6 1 6) (Position 7 1 7)) (IdentTok "x"))) ()) ()) , testP "impl Debug + Clone" (ImplTrait - [ TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) None () - , TraitTyParamBound (PolyTraitRef [] (TraitRef clone) ()) None () + [ TraitBound (PolyTraitRef [] (TraitRef debug) ()) None () + , TraitBound (PolyTraitRef [] (TraitRef clone) ()) None () ] ()) , testP "dyn Debug + Clone" (TraitObject - [ TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) None () - , TraitTyParamBound (PolyTraitRef [] (TraitRef clone) ()) None () - ] ()) + [ TraitBound (PolyTraitRef [] (TraitRef debug) ()) None () + , TraitBound (PolyTraitRef [] (TraitRef clone) ()) None () + ] ()) ] @@ -420,108 +447,136 @@ parserPatterns = testGroup "parsing patterns" , testP "ref mut x" (IdentP (ByRef Mutable) "x" Nothing ()) , testP "&x" (RefP x' Immutable ()) , testP "&mut x" (RefP x' Mutable ()) - , testP "(x,)" (TupleP [ x' ] Nothing ()) - , testP "(..)" (TupleP [] (Just 0) ()) - , testP "(x, x)" (TupleP [ x', x' ] Nothing ()) - , testP "(x,.., x)" (TupleP [ x', x' ] (Just 1) ()) - , testP "(..,x)" (TupleP [ x' ] (Just 0) ()) - , testP "(..,x,)" (TupleP [ x' ] (Just 0) ()) - , testP "(x,..)" (TupleP [ x' ] (Just 1) ()) - , testP "(x,x,)" (TupleP [ x', x' ] Nothing ()) + , testP "(x,)" (TupleP [ x' ] ()) + , testP "(x)" (ParenP x' ()) + , testP "(..)" (TupleP [RestP ()] ()) + , testP "(x, x)" (TupleP [ x', x' ] ()) + , testP "(x, .., x)" (TupleP [ x', RestP (), x' ] ()) + , testP "(..,x)" (TupleP [ RestP (), x' ] ()) + , testP "(..,x,)" (TupleP [ RestP (), x' ] ()) + , testP "(x,..)" (TupleP [ x', RestP () ] ()) + , testP "(x,x,)" (TupleP [ x', x' ] ()) , testP "(x, ref mut y, box z)" (TupleP [ x' , IdentP (ByRef Mutable) "y" Nothing () , BoxP (IdentP (ByValue Immutable) "z" Nothing ()) () - ] - Nothing ()) + ] + ()) , testP "true" (LitP (Lit [] (Bool True Unsuffixed ()) ()) ()) , testP "-123" (LitP (Unary [] Neg (Lit [] (Int Dec 123 Unsuffixed ()) ()) ()) ()) , testP "Point { .. }" (StructP point [] True ()) , testP "Point { x, y: y1 }" (StructP point - [ FieldPat Nothing (IdentP (ByValue Immutable) "x" Nothing ()) () - , FieldPat (Just "y") (IdentP (ByValue Immutable) "y1" Nothing ()) () ] - False ()) + [ FieldPat Nothing (IdentP (ByValue Immutable) "x" Nothing ()) [] () + , FieldPat (Just "y") (IdentP (ByValue Immutable) "y1" Nothing ()) [] () ] + False ()) + , testP "Point { y: y1 | y2, x }" (StructP point + [ FieldPat (Just "y") (OrP [ IdentP (ByValue Immutable) "y1" Nothing () + , IdentP (ByValue Immutable) "y2" Nothing () ] ()) [] () + , FieldPat Nothing (IdentP (ByValue Immutable) "x" Nothing ()) [] () ] + False ()) , testP "Point { x, .. }" (StructP point - [ FieldPat Nothing (IdentP (ByValue Immutable) "x" Nothing ()) () ] + [ FieldPat Nothing (IdentP (ByValue Immutable) "x" Nothing ()) [] () ] True ()) , testP "math" (IdentP (ByValue Immutable) "math" Nothing ()) , testP "math::PI" (PathP Nothing (Path False [ PathSegment "math" Nothing () , PathSegment "PI" Nothing () ] ()) ()) - , testP "math::" (PathP Nothing (Path False [ PathSegment "math" (Just (AngleBracketed [] [i32] [] ())) () ] ()) ()) - , testP "math::::PI" (PathP Nothing (Path False [ PathSegment "math" (Just (AngleBracketed [] [i32] [] ())) () + , testP "math::" (PathP Nothing (Path False [ PathSegment "math" (Just (AngleBracketed [TypeArg i32] [] ())) () ] ()) ()) + , testP "math::::PI" (PathP Nothing (Path False [ PathSegment "math" (Just (AngleBracketed [TypeArg i32] [] ())) () , PathSegment "PI" Nothing () ] ()) ()) - , testP "1...2" (RangeP (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()) - , testP "1..=2" (RangeP (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()) - , testP "ref mut y@(x,x)" (IdentP (ByRef Mutable) "y" (Just (TupleP [ x', x' ] Nothing ())) ()) + , testP "1...2" (RangeP (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 2 Unsuffixed ()) ()) Closed ()) + , testP "1..=2" (RangeP (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 2 Unsuffixed ()) ()) Closed ()) + , testP "1..2" (RangeP (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 2 Unsuffixed ()) ()) HalfOpen ()) + , testP "ref mut y@(x,x)" (IdentP (ByRef Mutable) "y" (Just (TupleP [ x', x' ] ())) ()) , testP "ref mut y@_" (IdentP (ByRef Mutable) "y" (Just (WildP ())) ()) , testP "(1,2,..,3)" (TupleP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () - , LitP (Lit [] (Int Dec 2 Unsuffixed ()) ()) () - , LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] - (Just 2) ()) - , testP "Point(x)" (TupleStructP point - [ x' ] Nothing ()) - , testP "Point(x,)" (TupleStructP point - [ x' ] Nothing ()) + , LitP (Lit [] (Int Dec 2 Unsuffixed ()) ()) () + , RestP () + , LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] + ()) + , testP "Point(x)" (TupleStructP point [ x' ] ()) + , testP "Point(x | _)" (TupleStructP point [ OrP [ x', WildP () ] () ] ()) + , testP "Point(x | _,)" (TupleStructP point [ OrP [ x', WildP () ] () ] ()) + , testP "Point(x,)" (TupleStructP point [ x' ] ()) , testP "::b::<'lt>::AssociatedItem" (PathP (Just (QSelf i32 1)) (Path False [ PathSegment "a" (Just (Parenthesized [i32, i32] Nothing ())) () - , PathSegment "b" (Just (AngleBracketed [Lifetime "lt" ()] [] [] ())) () + , PathSegment "b" (Just (AngleBracketed [LifetimeArg (Lifetime "lt" ())] [] ())) () , PathSegment "AssociatedItem" Nothing () ] ()) ()) , testP "[1,2]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () - , LitP (Lit [] (Int Dec 2 Unsuffixed ()) ()) () ] - Nothing [] ()) + , LitP (Lit [] (Int Dec 2 Unsuffixed ()) ()) () ] + ()) , testP "[1,2,]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () - , LitP (Lit [] (Int Dec 2 Unsuffixed ()) ()) () ] - Nothing [] ()) - , testP "[1,..,3]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () ] - (Just (WildP ())) - [ LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] ()) - , testP "[1,..,3,]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () ] - (Just (WildP ())) - [ LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] ()) - , testP "[1,x..,3]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () ] - (Just x') - [ LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] ()) - , testP "[1,..]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () ] (Just (WildP ())) [] ()) - , testP "[1,x..]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () ] (Just x') [] ()) - , testP "[x]" (SliceP [ x' ] Nothing [] ()) - , testP "[x,]" (SliceP [ x' ] Nothing [] ()) - , testP "[x..]" (SliceP [] (Just x') [] ()) - , testP "[..]" (SliceP [] (Just (WildP ())) [] ()) + , LitP (Lit [] (Int Dec 2 Unsuffixed ()) ()) () ] + ()) + , testP "[1,..,3]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () + , RestP () + , LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] ()) + , testP "[1,..,3,]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () + , RestP () + , LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] ()) + , testP "[1,x@..,3]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () + , IdentP (ByValue Immutable) "x" (Just (RestP ())) () + , LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] ()) + , testP "[1 | _, .. | ..]" (SliceP [ OrP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () + , WildP () ] () + , OrP [RestP (), RestP ()] () ] ()) + , testP "[1,..]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), RestP () ] ()) + , testP "[1,x@..]" (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () + , IdentP (ByValue Immutable) "x" (Just (RestP ())) () ] ()) + , testP "[x]" (SliceP [ x' ] ()) + , testP "[x,]" (SliceP [ x' ] ()) + , testP "[x@..]" (SliceP [ IdentP (ByValue Immutable) "x" (Just (RestP ())) () ] ()) + , testP "[..]" (SliceP [RestP ()] ()) , testP "foo!(x)" (MacP (Mac (Path False [PathSegment "foo" Nothing ()] ()) (Tree (Token (Span (Position 5 1 5) (Position 6 1 6)) (IdentTok "x"))) ()) ()) ] - + -- | Test parsing of expressions. parserExpressions :: Test parserExpressions = testGroup "parsing expressions" [ testP "123" (Lit [] (Int Dec 123 Unsuffixed ()) ()) - , testP "()" (TupExpr [] [] ()) + , testP "()" (TupExpr [] [] ()) , testP "(1,)" (TupExpr [] [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) , testP "(1,2)" (TupExpr [] [Lit [] (Int Dec 1 Unsuffixed ()) (), Lit [] (Int Dec 2 Unsuffixed ()) ()] ()) - , testP "|| 1" (Closure [] Movable Ref (FnDecl [] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) - , testP "|_: ()| 1" (Closure [] Movable Ref (FnDecl [Arg (Just (WildP ())) (TupTy [] ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) - , testP "|_| 1" (Closure [] Movable Ref (FnDecl [Arg (Just (WildP ())) (Infer ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) - , testP "static |_| 1" (Closure [] Immovable Ref (FnDecl [Arg (Just (WildP ())) (Infer ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) - , testP "|_: ()| -> () { (); }" (Closure [] Movable Ref (FnDecl [Arg (Just (WildP ())) (TupTy [] ()) ()] (Just (TupTy [] ())) False ()) (BlockExpr [] (Block [Semi (TupExpr [] [] ()) ()] Normal ()) ()) ()) - , testP "move || 1" (Closure [] Movable Value (FnDecl [] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) - , testP "static move || 1" (Closure [] Immovable Value (FnDecl [] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) - , testP "move |_: ()| 1" (Closure [] Movable Value (FnDecl [Arg (Just (WildP ())) (TupTy [] ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) - , testP "move |_| 1" (Closure [] Movable Value (FnDecl [Arg (Just (WildP ())) (Infer ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) - , testP "move |_: ()| -> () { (); }" (Closure [] Movable Value (FnDecl [Arg (Just (WildP ())) (TupTy [] ()) ()] (Just (TupTy [] ())) False ()) (BlockExpr [] (Block [Semi (TupExpr [] [] ()) ()] Normal ()) ()) ()) - , testP "|_: ()| -> () { () }" (Closure [] Movable Ref (FnDecl [Arg (Just (WildP ())) (TupTy [] ()) ()] (Just (TupTy [] ())) False ()) (BlockExpr [] (Block [NoSemi (TupExpr [] [] ()) ()] Normal ()) ()) ()) - , testP "move |_: ()| -> () { () }" (Closure [] Movable Value (FnDecl [Arg (Just (WildP ())) (TupTy [] ()) ()] (Just (TupTy [] ())) False ()) (BlockExpr [] (Block [NoSemi (TupExpr [] [] ()) ()] Normal ()) ()) ()) + , testP "|| 1" (Closure [] Ref NotAsync Movable (FnDecl [] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) + , testP "async || 1" (Closure [] Ref IsAsync Movable (FnDecl [] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) + , testP "|_: ()| 1" (Closure [] Ref NotAsync Movable (FnDecl [Arg [] (Just (WildP ())) (TupTy [] ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) + , testP "|(A | B): u8| ()" (Closure [] Ref NotAsync Movable (FnDecl [ Arg [] (Just (ParenP (OrP [ IdentP (ByValue Immutable) "A" Nothing () + , IdentP (ByValue Immutable) "B" Nothing () ] ()) ())) + (PathTy Nothing (Path False [PathSegment "u8" Nothing ()] ()) ()) + () ] + Nothing + False + ()) + (TupExpr [] [] ()) + ()) + , testP "|_| 1" (Closure [] Ref NotAsync Movable (FnDecl [Arg [] (Just (WildP ())) (Infer ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) + , testP "static |_| 1" (Closure [] Ref NotAsync Immovable (FnDecl [Arg [] (Just (WildP ())) (Infer ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) + , testP "static async |_| 1" (Closure [] Ref IsAsync Immovable (FnDecl [Arg [] (Just (WildP ())) (Infer ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) + , testP "|_: ()| -> () { (); }" (Closure [] Ref NotAsync Movable (FnDecl [Arg [] (Just (WildP ())) (TupTy [] ()) ()] (Just (TupTy [] ())) False ()) (BlockExpr [] (Block [Semi (TupExpr [] [] ()) ()] Normal ()) Nothing ()) ()) + , testP "move || 1" (Closure [] Value NotAsync Movable (FnDecl [] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) + , testP "static move || 1" (Closure [] Value NotAsync Immovable (FnDecl [] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) + , testP "move |_: ()| 1" (Closure [] Value NotAsync Movable (FnDecl [Arg [] (Just (WildP ())) (TupTy [] ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) + , testP "move |_| 1" (Closure [] Value NotAsync Movable (FnDecl [Arg [] (Just (WildP ())) (Infer ()) ()] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) + , testP "move |_: ()| -> () { (); }" (Closure [] Value NotAsync Movable (FnDecl [Arg [] (Just (WildP ())) (TupTy [] ()) ()] (Just (TupTy [] ())) False ()) (BlockExpr [] (Block [Semi (TupExpr [] [] ()) ()] Normal ()) Nothing ()) ()) + , testP "|_: ()| -> () { () }" (Closure [] Ref NotAsync Movable (FnDecl [Arg [] (Just (WildP ())) (TupTy [] ()) ()] (Just (TupTy [] ())) False ()) (BlockExpr [] (Block [NoSemi (TupExpr [] [] ()) ()] Normal ()) Nothing ()) ()) + , testP "move |_: ()| -> () { () }" (Closure [] Value NotAsync Movable (FnDecl [Arg [] (Just (WildP ())) (TupTy [] ()) ()] (Just (TupTy [] ())) False ()) (BlockExpr [] (Block [NoSemi (TupExpr [] [] ()) ()] Normal ()) Nothing ()) ()) + , testP "async move |_: ()| -> () { () }" (Closure [] Value IsAsync Movable (FnDecl [Arg [] (Just (WildP ())) (TupTy [] ()) ()] (Just (TupTy [] ())) False ()) (BlockExpr [] (Block [NoSemi (TupExpr [] [] ()) ()] Normal ()) Nothing ()) ()) , testP "[(); 512]" (Repeat [] (TupExpr [] [] ()) (Lit [] (Int Dec 512 Unsuffixed ()) ()) ()) , testP "[]" (Vec [] [] ()) , testP "[1]" (Vec [] [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) , testP "[1,]" (Vec [] [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) , testP "[1,2]" (Vec [] [Lit [] (Int Dec 1 Unsuffixed ()) (), Lit [] (Int Dec 2 Unsuffixed ()) ()] ()) - , testP "{ 1; 2 }" (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), NoSemi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) ()) - , testP "unsafe { 1; 2 }" (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), NoSemi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Unsafe ()) ()) - , testP "{ 1; 2; }" (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) ()) - , testP "{ }" (BlockExpr [] (Block [] Normal ()) ()) - , testP "unsafe { 1; 2; }" (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Unsafe ()) ()) - , testP "{ ;;; }" (BlockExpr [] (Block [] Normal ()) ()) - , testP "{ 1;; 2;; }" (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) ()) + , testP "{ 1; 2 }" (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), NoSemi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) + , testP "unsafe { 1; 2 }" (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), NoSemi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Unsafe ()) Nothing ()) + , testP "{ 1; 2; }" (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) + , testP "{ }" (BlockExpr [] (Block [] Normal ()) Nothing ()) + , testP "unsafe { 1; 2; }" (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Unsafe ()) Nothing ()) + , testP "{ ;;; }" (BlockExpr [] (Block [StandaloneSemi (), StandaloneSemi (), StandaloneSemi () ] Normal ()) Nothing ()) + , testP "{ 1;; 2;; }" (BlockExpr [] (Block [ Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) () + , StandaloneSemi () + , Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) () + , StandaloneSemi () ] + Normal ()) Nothing ()) , testP "return" (Ret [] Nothing ()) , testP "return 1" (Ret [] (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) ()) , testP "continue" (Continue [] Nothing ()) @@ -533,63 +588,74 @@ parserExpressions = testGroup "parsing expressions" , testP "math" (PathExpr [] Nothing (Path False [ PathSegment "math" Nothing () ] ()) ()) , testP "math::PI" (PathExpr [] Nothing (Path False [ PathSegment "math" Nothing () , PathSegment "PI" Nothing () ] ()) ()) - , testP "math::" (PathExpr [] Nothing (Path False [ PathSegment "math" (Just (AngleBracketed [] [i32] [] ())) () ] ()) ()) - , testP "math::::PI" (PathExpr [] Nothing (Path False [ PathSegment "math" (Just (AngleBracketed [] [i32] [] ())) () + , testP "math::" (PathExpr [] Nothing (Path False [ PathSegment "math" (Just (AngleBracketed [TypeArg i32] [] ())) () ] ()) ()) + , testP "math::::PI" (PathExpr [] Nothing (Path False [ PathSegment "math" (Just (AngleBracketed [TypeArg i32] [] ())) () , PathSegment "PI" Nothing () ] ()) ()) , testP "::b::<'lt>::AssociatedItem" (PathExpr [] (Just (QSelf i32 1)) (Path False [ PathSegment "a" (Just (Parenthesized [i32, i32] Nothing ())) () - , PathSegment "b" (Just (AngleBracketed [Lifetime "lt" ()] [] [] ())) () + , PathSegment "b" (Just (AngleBracketed [LifetimeArg (Lifetime "lt" ())] [] ())) () , PathSegment "AssociatedItem" Nothing () ] ()) ()) - , testP "Point { x: 1, y: 2 }" (Struct [] point [Field "x" (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) (), Field "y" (Just (Lit [] (Int Dec 2 Unsuffixed ()) ())) ()] Nothing ()) - , testP "Point { x, y }" (Struct [] point [Field "x" Nothing (), Field "y" Nothing ()] Nothing ()) - , testP "Point { x: 1, y: 2, }" (Struct [] point [Field "x" (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) (), Field "y" (Just (Lit [] (Int Dec 2 Unsuffixed ()) ())) ()] Nothing ()) - , testP "Point { x: 1, ..p }" (Struct [] point [Field "x" (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) ()] (Just (PathExpr [] Nothing (Path False [ PathSegment "p" Nothing () ] ()) ())) ()) + , testP "Point { x: 1, y: 2 }" (Struct [] point [Field "x" (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) [] (), Field "y" (Just (Lit [] (Int Dec 2 Unsuffixed ()) ())) [] ()] Nothing ()) + , testP "Point { x, y }" (Struct [] point [Field "x" Nothing [] (), Field "y" Nothing [] ()] Nothing ()) + , testP "Point { x: 1, y: 2, }" (Struct [] point [Field "x" (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) [] (), Field "y" (Just (Lit [] (Int Dec 2 Unsuffixed ()) ())) [] ()] Nothing ()) + , testP "Point { x: 1, ..p }" (Struct [] point [Field "x" (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) [] ()] (Just (PathExpr [] Nothing (Path False [ PathSegment "p" Nothing () ] ()) ())) ()) , testP "Point { ..p }" (Struct [] point [] (Just (PathExpr [] Nothing (Path False [ PathSegment "p" Nothing () ] ()) ())) ()) , testP "Point { }" (Struct [] point [] Nothing ()) , testP "if true { 1; }" - (If [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) + (If [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) , testP "if true { 1; } else { 2; }" - (If [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) - (Just (BlockExpr [] (Block [Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) ())) ()) + (If [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) + (Just (BlockExpr [] (Block [Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) Nothing ())) ()) , testP "if true { 1; } else if false { 2; }" - (If [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) + (If [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) (Just (If [] (Lit [] (Bool False Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) Nothing ())) ()) , testP "if true { 1; } else if false { 2; } else { 3; }" - (If [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) + (If [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) (Just (If [] (Lit [] (Bool False Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) - (Just (BlockExpr [] (Block [Semi (Lit [] (Int Dec 3 Unsuffixed ()) ()) ()] Normal ()) ())) ())) ()) + (Just (BlockExpr [] (Block [Semi (Lit [] (Int Dec 3 Unsuffixed ()) ()) ()] Normal ()) Nothing ())) ())) ()) , testP "if let x = true { 1; }" - (IfLet [] [x'] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) + (IfLet [] x' (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) + , testP "if let x | _ = true { }" + (IfLet [] (OrP [x', WildP ()] ()) (Lit [] (Bool True Unsuffixed ()) ()) (Block [] Normal ()) Nothing ()) + , testP "if let | x | _ = true { }" + (IfLet [] (OrP [x', WildP ()] ()) (Lit [] (Bool True Unsuffixed ()) ()) (Block [] Normal ()) Nothing ()) + , testP "if let (x | _) = true { }" + (IfLet [] (ParenP (OrP [x', WildP ()] ()) ()) (Lit [] (Bool True Unsuffixed ()) ()) (Block [] Normal ()) Nothing ()) + , testP "if let (x | _,) = true { }" + (IfLet [] (TupleP [OrP [x', WildP ()] ()] ()) (Lit [] (Bool True Unsuffixed ()) ()) (Block [] Normal ()) Nothing ()) , testP "if let x = true { 1; } else { 2; }" - (IfLet [] [x'] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) - (Just (BlockExpr [] (Block [Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) ())) ()) + (IfLet [] x' (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) + (Just (BlockExpr [] (Block [Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) Nothing ())) ()) , testP "if true { 1; } else if let x = false { 2; }" - (If [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) - (Just (IfLet [] [x'] (Lit [] (Bool False Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) + (If [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) + (Just (IfLet [] x' (Lit [] (Bool False Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] Normal ()) Nothing ())) ()) - , testP "do catch { 1; }" (Catch [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) + , testP "try { 1; }" (TryBlock [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) , testP "loop { 1; }" (Loop [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) , testP "'lbl: loop { 1; }" (Loop [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) (Just (Label "lbl" ())) ()) - , testP "for x in [1,2,3] { 1; }" (ForLoop [] x' (Vec [] [Lit [] (Int Dec 1 Unsuffixed ()) (), Lit [] (Int Dec 2 Unsuffixed ()) (), Lit [] (Int Dec 3 Unsuffixed ()) ()] ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) - , testP "'lbl: for x in [1,2,3] { 1; }" (ForLoop [] x' (Vec [] [Lit [] (Int Dec 1 Unsuffixed ()) (), Lit [] (Int Dec 2 Unsuffixed ()) (), Lit [] (Int Dec 3 Unsuffixed ()) ()] ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) (Just (Label "lbl" ())) ()) + , testP "for x in [1,2,3] { 1; }" (ForLoop [] x' (Vec [] [Lit [] (Int Dec 1 Unsuffixed ()) (), Lit [] (Int Dec 2 Unsuffixed ()) (), Lit [] (Int Dec 3 Unsuffixed ()) ()] ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) + , testP "for | x | _ in [] { }" (ForLoop [] (OrP [x',WildP ()] ()) (Vec [] [] ()) (Block [] Normal ()) Nothing ()) + , testP "for x | _ in [] { }" (ForLoop [] (OrP [x',WildP ()] ()) (Vec [] [] ()) (Block [] Normal ()) Nothing ()) + , testP "'lbl: for x in [1,2,3] { 1; }" (ForLoop [] x' (Vec [] [Lit [] (Int Dec 1 Unsuffixed ()) (), Lit [] (Int Dec 2 Unsuffixed ()) (), Lit [] (Int Dec 3 Unsuffixed ()) ()] ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) (Just (Label "lbl" ())) ()) , testP "while true { 1; }" (While [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) , testP "'lbl: while true { 1; }" (While [] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) (Just (Label "lbl" ())) ()) - , testP "while let x = true { 1; }" (WhileLet [] [x'] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) - , testP "'lbl: while let x = true { 1; }" (WhileLet [] [x'] (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) (Just (Label "lbl" ())) ()) + , testP "while let x = true { 1; }" (WhileLet [] x' (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) + , testP "'lbl: while let x | x = true { 1; }" (WhileLet [] (OrP [x',x'] ()) (Lit [] (Bool True Unsuffixed ()) ()) (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) (Just (Label "lbl" ())) ()) + , testP "'lbl: while let | x | _ = true { }" (WhileLet [] (OrP [x',WildP ()] ()) (Lit [] (Bool True Unsuffixed ()) ()) (Block [] Normal ()) (Just (Label "lbl" ())) ()) , testP "match true { }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [] ()) - , testP "match true { _ => 2 }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] [WildP ()] Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] ()) - , testP "match true { _ if true => 2 }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] [WildP ()] (Just (Lit [] (Bool True Unsuffixed ()) ())) (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] ()) - , testP "match true { _ => 2, }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] [WildP ()] Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] ()) - , testP "match true { _ => 2, x | x => 1 }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] [WildP ()] Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) (), Arm [] [x',x'] Nothing (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] ()) - , testP "match true { _ => 2, x | x => { 1; } }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] [WildP ()] Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) (), Arm [] [x',x'] Nothing (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) ()] ()) - , testP "match true { _ => 2, x | x => { 1; }, }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] [WildP ()] Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) (), Arm [] [x',x'] Nothing (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) ()] ()) - , testP "match true { _ => 2, x | x => { 1; }, _ => 1 }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] [WildP ()] Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) (), Arm [] [x',x'] Nothing (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) (), Arm [] [WildP ()] Nothing (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] ()) - , testP "match true { _ => 2, x | x => { 1; } _ => 1 }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] [WildP ()] Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) (), Arm [] [x',x'] Nothing (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) (), Arm [] [WildP ()] Nothing (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] ()) - , testP "println!()" (MacExpr [] (Mac (Path False [PathSegment "println" Nothing ()] ()) (Stream []) ()) ()) + , testP "match true { _ => 2 }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] (WildP ()) Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] ()) + , testP "match true { _ if true => 2 }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] (WildP ()) (Just (Lit [] (Bool True Unsuffixed ()) ())) (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] ()) + , testP "match true { _ => 2, }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] (WildP ()) Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) ()] ()) + , testP "match true { _ => 2, x | x => 1 }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] (WildP ()) Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) (), Arm [] (OrP [x',x'] ()) Nothing (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] ()) + , testP "match true { _ => 2, x | x => { 1; } }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] (WildP ()) Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) (), Arm [] (OrP [x',x'] ()) Nothing (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) ()] ()) + , testP "match true { _ => 2, x | x => { 1; }, }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] (WildP ()) Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) (), Arm [] (OrP [x',x'] ()) Nothing (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) ()] ()) + , testP "match true { _ => 2, | x | x => { 1; }, _ => 1 }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] (WildP ()) Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) (), Arm [] (OrP [x',x'] ()) Nothing (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) (), Arm [] (WildP ()) Nothing (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] ()) + , testP "match true { _ => 2, x | x => { 1; } _ => 1 }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] (WildP ()) Nothing (Lit [] (Int Dec 2 Unsuffixed ()) ()) (), Arm [] (OrP [x',x'] ()) Nothing (BlockExpr [] (Block [Semi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) (), Arm [] (WildP ()) Nothing (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] ()) + , testP "println!()" (MacExpr [] (Mac (Path False [PathSegment "println" Nothing ()] ()) (Stream []) ()) ()) , testP "1..2" (Range [] (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) (Just (Lit [] (Int Dec 2 Unsuffixed ()) ())) HalfOpen ()) , testP "1...2" (Range [] (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) (Just (Lit [] (Int Dec 2 Unsuffixed ()) ())) Closed ()) , testP "1..=2" (Range [] (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) (Just (Lit [] (Int Dec 2 Unsuffixed ()) ())) Closed ()) @@ -600,14 +666,15 @@ parserExpressions = testGroup "parsing expressions" , testP ".." (Range [] Nothing Nothing HalfOpen ()) , testP "x?" (Try [] (PathExpr [] Nothing x ()) ()) , testP "x.0" (TupField [] (PathExpr [] Nothing x ()) 0 ()) + , testP "x.await" (Await [] (PathExpr [] Nothing x ()) ()) , testP "x.foo" (FieldAccess [] (PathExpr [] Nothing x ()) "foo" ()) - , testP "x.foo()" (MethodCall [] (PathExpr [] Nothing x ()) "foo" Nothing [] ()) - , testP "x.foo(1)" (MethodCall [] (PathExpr [] Nothing x ()) "foo" Nothing [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) - , testP "x.foo(1,)" (MethodCall [] (PathExpr [] Nothing x ()) "foo" Nothing [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) - , testP "x.foo::<>(1,)" (MethodCall [] (PathExpr [] Nothing x ()) "foo" (Just []) [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) - , testP "x.foo::()" (MethodCall [] (PathExpr [] Nothing x ()) "foo" (Just [i32]) [] ()) - , testP "x.foo::(1)" (MethodCall [] (PathExpr [] Nothing x ()) "foo" (Just [i32]) [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) - , testP "x.foo::(1,)" (MethodCall [] (PathExpr [] Nothing x ()) "foo" (Just [i32]) [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) + , testP "x.foo()" (MethodCall [] (PathExpr [] Nothing x ()) (PathSegment "foo" Nothing ()) [] ()) + , testP "x.foo(1)" (MethodCall [] (PathExpr [] Nothing x ()) (PathSegment "foo" Nothing ()) [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) + , testP "x.foo(1,)" (MethodCall [] (PathExpr [] Nothing x ()) (PathSegment "foo" Nothing ()) [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) + , testP "x.foo::<>(1,)" (MethodCall [] (PathExpr [] Nothing x ()) (PathSegment "foo" (Just (AngleBracketed [] [] ())) ()) [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) + , testP "x.foo::()" (MethodCall [] (PathExpr [] Nothing x ()) (PathSegment "foo" (Just (AngleBracketed [TypeArg i32] [] ())) ()) [] ()) + , testP "x.foo::(1)" (MethodCall [] (PathExpr [] Nothing x ()) (PathSegment "foo" (Just (AngleBracketed [TypeArg i32] [] ())) ()) [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) + , testP "x.foo::(1,)" (MethodCall [] (PathExpr [] Nothing x ()) (PathSegment "foo" (Just (AngleBracketed [TypeArg i32] [] ())) ()) [Lit [] (Int Dec 1 Unsuffixed ()) ()] ()) , testP "self" (PathExpr [] Nothing (Path False [PathSegment "self" Nothing ()] ()) ()) , testP "x[1]" (Index [] (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) , testP "x()" (Call [] (PathExpr [] Nothing x ()) [] ()) @@ -664,34 +731,55 @@ parserExpressions = testGroup "parsing expressions" , testP "x << 1" (Binary [] ShlOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) , testP "x >> 1" (Binary [] ShrOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) , testP "&&&x&&&x" (Binary [] AndOp (AddrOf [] Immutable (AddrOf [] Immutable (AddrOf [] Immutable (PathExpr [] Nothing x ()) ()) ()) ()) (AddrOf [] Immutable (PathExpr [] Nothing x ()) ()) ()) - , testP "&[]" (AddrOf [] Immutable (Vec [] [] ()) ()) + , testP "&[]" (AddrOf [] Immutable (Vec [] [] ()) ()) , testP "for _ in 1..2 { }" (ForLoop [] (WildP ()) (Range [] (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) (Just (Lit [] (Int Dec 2 Unsuffixed ()) ())) HalfOpen ()) (Block [] Normal ()) Nothing ()) , testP "for _ in 1..x { }" (ForLoop [] (WildP ()) (Range [] (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) (Just (PathExpr [] Nothing x ())) HalfOpen ()) (Block [] Normal ()) Nothing ()) , testP "for _ in 1.. { }" (ForLoop [] (WildP ()) (Range [] (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) Nothing HalfOpen ()) (Block [] Normal ()) Nothing ()) , testP "1 * 1 + 1 * 1" (Binary [] AddOp (Binary [] MulOp (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) (Binary [] MulOp (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) ()) , testP "1 * - 1 + 1 * 1" (Binary [] AddOp (Binary [] MulOp (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Unary [] Neg (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) ()) (Binary [] MulOp (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) ()) , testP "match true { _ => match true { _ => true }, _ => match true { _ => true } }" (Match [] (Lit [] (Bool True Unsuffixed ()) ()) - [ Arm [] [WildP ()] Nothing (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] [WildP ()] Nothing (Lit [] (Bool True Unsuffixed ()) ()) ()] ()) () - , Arm [] [WildP ()] Nothing (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] [WildP ()] Nothing (Lit [] (Bool True Unsuffixed ()) ()) ()] ()) () ] ()) + [ Arm [] (WildP ()) Nothing (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] (WildP ()) Nothing (Lit [] (Bool True Unsuffixed ()) ()) ()] ()) () + , Arm [] (WildP ()) Nothing (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [Arm [] (WildP ()) Nothing (Lit [] (Bool True Unsuffixed ()) ()) ()] ()) () ] ()) ] -- | Test parsing of statements. parserStatements :: Test parserStatements = testGroup "parsing statements" - [ testP "let x: i32 = 1;" (Local x' (Just i32) (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) [] ()) + [ testP "let x: i32 = 1;" (Local x' (Just i32) (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) [] ()) , testP "let x: i32;" (Local x' (Just i32) Nothing [] ()) , testP "let x = 1;" (Local x' Nothing (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) [] ()) , testP "let x;" (Local x' Nothing Nothing [] ()) + , testP "let | x | _;" (Local (OrP [x',WildP ()] ()) Nothing Nothing [] ()) + , testP "let x | _;" (Local (OrP [x',WildP ()] ()) Nothing Nothing [] ()) + , testP "let x | _ = 1;" (Local (OrP [x',WildP ()] ()) Nothing (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) [] ()) + , testP "let box x | _;" (Local (OrP [BoxP x' (),WildP ()] ()) Nothing Nothing [] ()) + , testP "let &mut x | _;" (Local (OrP [RefP x' Mutable (),WildP ()] ()) Nothing Nothing [] ()) + , testP "let x @ _ | _;" (Local (OrP [IdentP (ByValue Immutable) "x" (Just (WildP ())) (),WildP ()] ()) Nothing Nothing [] ()) + , testP "let ref mut x @ _ | _;" (Local (OrP [IdentP (ByRef Mutable) "x" (Just (WildP ())) (),WildP ()] ()) Nothing Nothing [] ()) , testP "x + 1;" (Semi (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) ()) - , testP "x + { 1 };" (Semi (Binary [] AddOp (PathExpr [] Nothing x ()) (BlockExpr [] (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) ()) ()) + , testP "x + { 1 };" (Semi (Binary [] AddOp (PathExpr [] Nothing x ()) (BlockExpr [] (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) ()) ()) , testP "match true { };" (Semi (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [] ()) ()) , testP "match true { }" (NoSemi (Match [] (Lit [] (Bool True Unsuffixed ()) ()) [] ()) ()) , testP "static foo: i32 = 1;" (ItemStmt (Static [] InheritedV "foo" i32 Immutable (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) ()) - , testP "unsafe { 1 };" (Semi (BlockExpr [] (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Unsafe ()) ()) ()) - , testP "unsafe { 1 }" (NoSemi (BlockExpr [] (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Unsafe ()) ()) ()) - , testP "{ 1 };" (Semi (BlockExpr [] (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) ()) - , testP "{ 1 }" (NoSemi (BlockExpr [] (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) ()) + , testP "static || 1;" (Semi (Closure [] Ref NotAsync Immovable (FnDecl [] Nothing False ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) ()) + , testP "unsafe { 1 };" (Semi (BlockExpr [] (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Unsafe ()) Nothing ()) ()) + , testP "unsafe { 1 }" (NoSemi (BlockExpr [] (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Unsafe ()) Nothing ()) ()) + , testP "unsafe fn foo() { }" (ItemStmt (Fn [] InheritedV "foo" (FnDecl [] Nothing False ()) (FnHeader Unsafe NotAsync NotConst Rust ()) (Generics [] (WhereClause [] ()) ()) (Block [] Normal ()) ()) ()) + , testP "async { 1 };" (Semi (Async [] Ref (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) ()) + , testP "async { 1 }" (NoSemi (Async [] Ref (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) ()) + , testP "async move { 1 };" (Semi (Async [] Value (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) ()) + , testP "async move { 1 }" (NoSemi (Async [] Value (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) ()) ()) + , testP "async fn foo() { }" (ItemStmt (Fn [] InheritedV "foo" (FnDecl [] Nothing False ()) (FnHeader Normal IsAsync NotConst Rust ()) (Generics [] (WhereClause [] ()) ()) (Block [] Normal ()) ()) ()) + , testP "{ 1 };" (Semi (BlockExpr [] (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) ()) + , testP "{ 1 }" (NoSemi (BlockExpr [] (Block [NoSemi (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] Normal ()) Nothing ()) ()) + , testP "|| ();" (Semi (Closure [] Ref NotAsync Movable (FnDecl [] Nothing False ()) (TupExpr [] [] ()) ()) ()) + , testP "auto trait Foo { }" (ItemStmt (Trait [] InheritedV "Foo" True Normal (Generics [] (WhereClause [] ()) ()) [] [] ()) ()) + , testP "auto.field + 1;" (Semi (Binary [] AddOp (FieldAccess [] (PathExpr [] Nothing (Path False [PathSegment "auto" Nothing ()] ()) ()) "field" ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()) ()) + , testP "default impl Foo for Bar { }" (ItemStmt (Impl [] InheritedV Default Normal Positive (Generics [] (WhereClause [] ()) ()) (Just (TraitRef (Path False [PathSegment "Foo" Nothing ()] ()))) (PathTy Nothing (Path False [PathSegment "Bar" Nothing ()] ()) ()) [] ()) ()) + , testP "default { x: 1 };" (Semi (Struct [] (Path False [PathSegment "default" Nothing ()] ()) [Field "x" (Just (Lit [] (Int Dec 1 Unsuffixed ()) ())) [] ()] Nothing ()) ()) + , testP "union::foo::a;" (Semi (PathExpr [] Nothing (Path False [PathSegment "union" Nothing (),PathSegment "foo" Nothing (),PathSegment "a" Nothing ()] ()) ()) ()) + , testP "union Foo { }" (ItemStmt (Union [] InheritedV "Foo" (StructD [] ()) (Generics [] (WhereClause [] ()) ()) ()) ()) ] @@ -701,20 +789,22 @@ parserItems = testGroup "parsing items" [ testP "static mut foo: i32 = 1;" (Static [] InheritedV (mkIdent "foo") i32 Mutable _1 ()) , testP "static foo: i32 = 1;" (Static [] InheritedV (mkIdent "foo") i32 Immutable _1 ()) , testP "const foo: i32 = 1;" (ConstItem [] InheritedV (mkIdent "foo") i32 _1 ()) - , testP "type Foo = i32;" (TyAlias [] InheritedV "Foo" i32 (Generics [] [] (WhereClause [] ()) ()) ()) - , testP "type Foo where i32 = i32 = i32;" (TyAlias [] InheritedV "Foo" i32 (Generics [] [] (WhereClause [EqPredicate i32 i32 ()] ()) ()) ()) - , testP "type Foo<> = i32;" (TyAlias [] InheritedV "Foo" i32 (Generics [] [] (WhereClause [] ()) ()) ()) + , testP "type Foo = i32;" (TyAlias [] InheritedV "Foo" i32 (Generics [] (WhereClause [] ()) ()) ()) + , testP "type Foo where i32 = i32 = i32;" (TyAlias [] InheritedV "Foo" i32 (Generics [] (WhereClause [EqPredicate i32 i32 ()] ()) ()) ()) + , testP "type Foo<> = i32;" (TyAlias [] InheritedV "Foo" i32 (Generics [] (WhereClause [] ()) ()) ()) , testP "extern crate foo;" (ExternCrate [] InheritedV (mkIdent "foo") Nothing ()) , testP "extern crate foo as bar;" (ExternCrate [] InheritedV (mkIdent "bar") (Just "foo") ()) + , testP "extern crate self as bar;" (ExternCrate [] InheritedV (mkIdent "bar") (Just "self") ()) , testP "mod foo;" (Mod [] InheritedV "foo" Nothing ()) - , testP "struct Point;" (StructItem [] InheritedV "Point" (UnitD ()) (Generics [] [] (WhereClause [] ()) ()) ()) - , testP "struct Point { }" (StructItem [] InheritedV "Point" (StructD [] ()) (Generics [] [] (WhereClause [] ()) ()) ()) - , testP "struct Point { x: i32, y: i32 }" (StructItem [] InheritedV "Point" (StructD [StructField (Just "x") InheritedV i32 [] (), StructField (Just "y") InheritedV i32 [] ()] ()) (Generics [] [] (WhereClause [] ()) ()) ()) - , testP "struct Point { x: i32, y: i32, }" (StructItem [] InheritedV "Point" (StructD [StructField (Just "x") InheritedV i32 [] (), StructField (Just "y") InheritedV i32 [] ()] ()) (Generics [] [] (WhereClause [] ()) ()) ()) - , testP "union Either;" (Union [] InheritedV "Either" (UnitD ()) (Generics [] [] (WhereClause [] ()) ()) ()) - , testP "union Either{ }" (Union [] InheritedV "Either" (StructD [] ()) (Generics [] [] (WhereClause [] ()) ()) ()) - , testP "union Either { x: i32, y: i32 }" (Union [] InheritedV "Either" (StructD [StructField (Just "x") InheritedV i32 [] (), StructField (Just "y") InheritedV i32 [] ()] ()) (Generics [] [] (WhereClause [] ()) ()) ()) - , testP "union Either { x: i32, y: i32, }" (Union [] InheritedV "Either" (StructD [StructField (Just "x") InheritedV i32 [] (), StructField (Just "y") InheritedV i32 [] ()] ()) (Generics [] [] (WhereClause [] ()) ()) ()) + , testP "pub struct S(pub i32);" (StructItem [] PublicV "S" (TupleD [StructField Nothing PublicV i32 [] ()] ()) (Generics [] (WhereClause [] ()) ()) ()) + , testP "struct Point;" (StructItem [] InheritedV "Point" (UnitD ()) (Generics [] (WhereClause [] ()) ()) ()) + , testP "struct Point { }" (StructItem [] InheritedV "Point" (StructD [] ()) (Generics [] (WhereClause [] ()) ()) ()) + , testP "struct Point { x: i32, y: i32 }" (StructItem [] InheritedV "Point" (StructD [StructField (Just "x") InheritedV i32 [] (), StructField (Just "y") InheritedV i32 [] ()] ()) (Generics [] (WhereClause [] ()) ()) ()) + , testP "struct Point { x: i32, y: i32, }" (StructItem [] InheritedV "Point" (StructD [StructField (Just "x") InheritedV i32 [] (), StructField (Just "y") InheritedV i32 [] ()] ()) (Generics [] (WhereClause [] ()) ()) ()) + , testP "union Either;" (Union [] InheritedV "Either" (UnitD ()) (Generics [] (WhereClause [] ()) ()) ()) + , testP "union Either{ }" (Union [] InheritedV "Either" (StructD [] ()) (Generics [] (WhereClause [] ()) ()) ()) + , testP "union Either { x: i32, y: i32 }" (Union [] InheritedV "Either" (StructD [StructField (Just "x") InheritedV i32 [] (), StructField (Just "y") InheritedV i32 [] ()] ()) (Generics [] (WhereClause [] ()) ()) ()) + , testP "union Either { x: i32, y: i32, }" (Union [] InheritedV "Either" (StructD [StructField (Just "x") InheritedV i32 [] (), StructField (Just "y") InheritedV i32 [] ()] ()) (Generics [] (WhereClause [] ()) ()) ()) , testP "use std::math;" (Use [] InheritedV (UseTreeSimple (Path False [ PathSegment "std" Nothing (), PathSegment "math" Nothing () ] ()) Nothing ()) ()) , testP "use std::math as m;" (Use [] InheritedV (UseTreeSimple (Path False [ PathSegment "std" Nothing (), PathSegment "math" Nothing () ] ()) (Just "m") ()) ()) , testP "use std::math::*;" (Use [] InheritedV (UseTreeGlob (Path False [ PathSegment "std" Nothing (), PathSegment "math" Nothing () ] ()) ()) ()) @@ -724,88 +814,102 @@ parserItems = testGroup "parsing items" , testP "use std::math::{sqrt, pi as p};" (Use [] InheritedV (UseTreeNested (Path False [ PathSegment "std" Nothing (), PathSegment "math" Nothing () ] ()) [ UseTreeSimple (Path False [ PathSegment "sqrt" Nothing () ] ()) Nothing (), UseTreeSimple (Path False [ PathSegment "pi" Nothing () ] ()) (Just "p") () ] ()) ()) , testP "use std::math::{sqrt};" (Use [] InheritedV (UseTreeNested (Path False [ PathSegment "std" Nothing (), PathSegment "math" Nothing () ] ()) [ UseTreeSimple (Path False [ PathSegment "sqrt" Nothing () ] ()) Nothing () ] ()) ()) , testP "use std::math::{sqrt, pi,};" (Use [] InheritedV (UseTreeNested (Path False [ PathSegment "std" Nothing (), PathSegment "math" Nothing () ] ()) [ UseTreeSimple (Path False [ PathSegment "sqrt" Nothing () ] ()) Nothing (), UseTreeSimple (Path False [ PathSegment "pi" Nothing () ] ()) Nothing () ] ()) ()) - , testP "const unsafe fn foo(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg (Just x') i32 ()] (Just i32) False ()) Unsafe Const Rust (Generics [] [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) - , testP "fn bar(x: T, y: K) where T: Clone, K: Clone + Debug { return x + 1 }" (Fn [] InheritedV "bar" (FnDecl [ Arg (Just (IdentP (ByValue Immutable) "x" Nothing ())) (PathTy Nothing t ()) () - , Arg (Just (IdentP (ByValue Immutable) "y" Nothing ())) (PathTy Nothing (Path False [PathSegment "K" Nothing ()] ()) ()) () + , testP "const unsafe fn foo(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg [] (Just x') i32 ()] (Just i32) False ()) (FnHeader Unsafe NotAsync Const Rust ()) (Generics [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) + , testP "async fn bar(x: T, y: K) where T: Clone, K: Clone + Debug { return x + 1 }" (Fn [] InheritedV "bar" (FnDecl [ Arg [] (Just (IdentP (ByValue Immutable) "x" Nothing ())) (PathTy Nothing t ()) () + , Arg [] (Just (IdentP (ByValue Immutable) "y" Nothing ())) (PathTy Nothing (Path False [PathSegment "K" Nothing ()] ()) ()) () ] Nothing False ()) - Normal NotConst Rust - (Generics [] [TyParam [] "T" [] Nothing (), TyParam [] "K" [] Nothing ()] - (WhereClause [ BoundPredicate [] (PathTy Nothing t ()) [TraitTyParamBound (PolyTraitRef [] (TraitRef clone) ()) None ()] () - , BoundPredicate [] (PathTy Nothing (Path False [PathSegment "K" Nothing ()] ()) ()) [TraitTyParamBound (PolyTraitRef [] (TraitRef clone) ()) None (), TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) None ()] () + (FnHeader Normal IsAsync NotConst Rust ()) + (Generics [TypeParam [] "T" [] Nothing (), TypeParam [] "K" [] Nothing (), ConstParam [] "N" i32 ()] + (WhereClause [ BoundPredicate [] (PathTy Nothing t ()) [TraitBound (PolyTraitRef [] (TraitRef clone) ()) None ()] () + , BoundPredicate [] (PathTy Nothing (Path False [PathSegment "K" Nothing ()] ()) ()) [TraitBound (PolyTraitRef [] (TraitRef clone) ()) None (), TraitBound (PolyTraitRef [] (TraitRef debug) ()) None ()] () ] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) - , testP "fn inverse(x: i32) -> T where i32: ConvertTo, { return x + 1 }" (Fn [] InheritedV "inverse" (FnDecl [ Arg (Just (IdentP (ByValue Immutable) "x" Nothing ())) (PathTy Nothing (Path False [PathSegment "i32" Nothing ()] ()) ()) () + , testP "fn inverse(x: i32) -> T where i32: ConvertTo, { return x + 1 }" (Fn [] InheritedV "inverse" (FnDecl [ Arg [] (Just (IdentP (ByValue Immutable) "x" Nothing ())) (PathTy Nothing (Path False [PathSegment "i32" Nothing ()] ()) ()) () ] - (Just (PathTy Nothing t ())) + (Just (PathTy Nothing t ())) False ()) - Normal NotConst Rust - (Generics [] [TyParam [] "T" [] Nothing ()] - (WhereClause [ BoundPredicate [] (PathTy Nothing (Path False [ PathSegment "i32" Nothing () ] ()) ()) [TraitTyParamBound (PolyTraitRef [] (TraitRef (Path False [ PathSegment "ConvertTo" (Just (AngleBracketed [] [PathTy Nothing t ()] [] ())) () ] ())) ()) None ()] () + (FnHeader Normal NotAsync NotConst Rust ()) + (Generics [TypeParam [] "T" [] Nothing ()] + (WhereClause [ BoundPredicate [] (PathTy Nothing (Path False [ PathSegment "i32" Nothing () ] ()) ()) [TraitBound (PolyTraitRef [] (TraitRef (Path False [ PathSegment "ConvertTo" (Just (AngleBracketed [TypeArg (PathTy Nothing t ())] [] ())) () ] ())) ()) None ()] () ] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) - , testP "const fn foo<>(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg (Just x') i32 ()] (Just i32) False ()) Normal Const Rust (Generics [] [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) - , testP "unsafe extern fn foo(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg (Just x') i32 ()] (Just i32) False ()) Unsafe NotConst C (Generics [] [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) - , testP "unsafe extern \"win64\" fn foo(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg (Just x') i32 ()] (Just i32) False ()) Unsafe NotConst Win64 (Generics [] [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) - , testP "extern \"win64\" fn foo(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg (Just x') i32 ()] (Just i32) False ()) Normal NotConst Win64 (Generics [] [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) - , testP "fn foo(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg (Just x') i32 ()] (Just i32) False ()) Normal NotConst Rust (Generics [] [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) - , testP "fn foo(x: i32) -> i32 where { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg (Just x') i32 ()] (Just i32) False ()) Normal NotConst Rust (Generics [] [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) - , testP "mod foo;" (Mod [] InheritedV "foo" Nothing ()) - , testP "mod foo { }" (Mod [] InheritedV "foo" (Just []) ()) - , testP "mod foo { pub fn foo(x: i32) -> i32 { return x + 1 } }" (Mod [] InheritedV "foo" (Just [Fn [] PublicV "foo" (FnDecl [Arg (Just x') i32 ()] (Just i32) False ()) Normal NotConst Rust (Generics [] [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()]) ()) + , testP "const fn foo<>(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg [] (Just x') i32 ()] (Just i32) False ()) (FnHeader Normal NotAsync Const Rust ()) (Generics [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) + , testP "unsafe extern fn foo(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg [] (Just x') i32 ()] (Just i32) False ()) (FnHeader Unsafe NotAsync NotConst C ()) (Generics [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) + , testP "unsafe extern \"win64\" fn foo(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg [] (Just x') i32 ()] (Just i32) False ()) (FnHeader Unsafe NotAsync NotConst Win64 ()) (Generics [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) + , testP "extern \"win64\" fn foo(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg [] (Just x') i32 ()] (Just i32) False ()) (FnHeader Normal NotAsync NotConst Win64 ()) (Generics [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) + , testP "fn foo(x: i32) -> i32 { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg [] (Just x') i32 ()] (Just i32) False ()) (FnHeader Normal NotAsync NotConst Rust ()) (Generics [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) + , testP "fn foo(x: i32) -> i32 where { return x + 1 }" (Fn [] InheritedV "foo" (FnDecl [Arg [] (Just x') i32 ()] (Just i32) False ()) (FnHeader Normal NotAsync NotConst Rust ()) (Generics [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()) + , testP "mod foo;" (Mod [] InheritedV "foo" Nothing ()) + , testP "mod foo { }" (Mod [] InheritedV "foo" (Just []) ()) + , testP "mod foo { pub fn foo(x: i32) -> i32 { return x + 1 } }" (Mod [] InheritedV "foo" (Just [Fn [] PublicV "foo" (FnDecl [Arg [] (Just x') i32 ()] (Just i32) False ()) (FnHeader Normal NotAsync NotConst Rust ()) (Generics [] (WhereClause [] ()) ()) (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()]) ()) , testP "pub extern { }" (ForeignMod [] PublicV C [] ()) , testP "extern { }" (ForeignMod [] InheritedV C [] ()) , testP "extern \"win64\" { pub static x: i32; static mut y: i32; }" (ForeignMod [] InheritedV Win64 [ForeignStatic [] PublicV "x" i32 Immutable (), ForeignStatic [] InheritedV "y" i32 Mutable ()] ()) - , testP "extern { pub fn foo(x: i32, ...); }" (ForeignMod [] InheritedV C [ForeignFn [] PublicV "foo" (FnDecl [Arg (Just x') i32 ()] Nothing True ()) (Generics [] [] (WhereClause [] ()) ()) ()] ()) - + , testP "pub extern { crate fn foo(x: i32, ...); }" (ForeignMod [] PublicV C [ForeignFn [] CrateV "foo" (FnDecl [Arg [] (Just x') i32 ()] Nothing True ()) (Generics [] (WhereClause [] ()) ()) ()] ()) + , testP "enum Option { None, Some(T) }" (Enum [] InheritedV "Option" [ Variant "None" [] (UnitD ()) Nothing () , Variant "Some" [] (TupleD [ StructField Nothing InheritedV (PathTy Nothing t ()) [] ()] ()) Nothing () ] - (Generics [] [TyParam [] "T" [] Nothing ()] (WhereClause [] ()) ()) ()) - , testP "impl [i32] { }" (Impl [] InheritedV Final Normal Positive (Generics [] [] (WhereClause [] ()) ()) Nothing (Slice i32 ()) [] ()) - , testP "unsafe impl i32 { }" (Impl [] InheritedV Final Unsafe Positive (Generics [] [] (WhereClause [] ()) ()) Nothing i32 [] ()) - , testP "impl (::b) { }" (Impl [] InheritedV Final Normal Positive (Generics [] [] (WhereClause [] ()) ()) Nothing (ParenTy (PathTy (Just (QSelf i32 1)) (Path False [PathSegment "a" Nothing (), PathSegment "b" Nothing () ] ()) ()) ()) [] ()) - , testP "impl (::b) { }" (Impl [] InheritedV Final Normal Positive (Generics [] [] (WhereClause [] ()) ()) Nothing (ParenTy (PathTy (Just (QSelf i32 1)) (Path False [PathSegment "a" Nothing (), PathSegment "b" Nothing () ] ()) ()) ()) [] ()) - , testP "impl !Debug for i32 { }" (Impl [] InheritedV Final Normal Negative (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [] ()) - , testP "default impl Debug for i32 { }" (Impl [] InheritedV Default Normal Positive (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [] ()) - , testP "impl Debug for i32 { }" (Impl [] InheritedV Final Normal Positive (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [] ()) - , testP "pub impl Debug for i32 { type T = i32; }" (Impl [] PublicV Final Normal Positive (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [TypeI [] InheritedV Final "T" i32 ()] ()) - , testP "impl Debug for i32 { pub default type T = i32; }" (Impl [] InheritedV Final Normal Positive (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [TypeI [] PublicV Default "T" i32 ()] ()) - , testP "impl Debug for i32 { const x: i32 = 1; }" (Impl [] InheritedV Final Normal Positive (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [ConstI [] InheritedV Final "x" i32 (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] ()) - - , testP "pub impl Debug for i32 { const unsafe fn foo(x: i32) -> i32 { return x + 1 } }" + (Generics [TypeParam [] "T" [] Nothing ()] (WhereClause [] ()) ()) ()) + , testP "impl [i32] { }" (Impl [] InheritedV Final Normal Positive (Generics [] (WhereClause [] ()) ()) Nothing (Slice i32 ()) [] ()) + , testP "unsafe impl i32 { }" (Impl [] InheritedV Final Unsafe Positive (Generics [] (WhereClause [] ()) ()) Nothing i32 [] ()) + , testP "impl (::b) { }" (Impl [] InheritedV Final Normal Positive (Generics [] (WhereClause [] ()) ()) Nothing (ParenTy (PathTy (Just (QSelf i32 1)) (Path False [PathSegment "a" Nothing (), PathSegment "b" Nothing () ] ()) ()) ()) [] ()) + , testP "impl (::b) { }" (Impl [] InheritedV Final Normal Positive (Generics [] (WhereClause [] ()) ()) Nothing (ParenTy (PathTy (Just (QSelf i32 1)) (Path False [PathSegment "a" Nothing (), PathSegment "b" Nothing () ] ()) ()) ()) [] ()) + , testP "impl !Debug for i32 { }" (Impl [] InheritedV Final Normal Negative (Generics [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [] ()) + , testP "default impl Debug for i32 { }" (Impl [] InheritedV Default Normal Positive (Generics [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [] ()) + , testP "impl Debug for i32 { }" (Impl [] InheritedV Final Normal Positive (Generics [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [] ()) + , testP "pub impl Debug for i32 { type T = i32; }" (Impl [] PublicV Final Normal Positive (Generics [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [TypeI [] InheritedV Final "T" i32 ()] ()) + , testP "impl Debug for i32 { pub default type T = i32; }" (Impl [] InheritedV Final Normal Positive (Generics [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [TypeI [] PublicV Default "T" i32 ()] ()) + , testP "impl Debug for i32 { const x: i32 = 1; }" (Impl [] InheritedV Final Normal Positive (Generics [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [ConstI [] InheritedV Final "x" i32 (Lit [] (Int Dec 1 Unsuffixed ()) ()) ()] ()) + + , testP "pub impl Debug for i32 { const unsafe fn foo(x: i32) -> i32 { return x + 1 } }" (Impl [] PublicV Final Normal Positive - (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 + (Generics [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [MethodI [] InheritedV Final "foo" - (Generics [] [] (WhereClause [] ()) ()) - (MethodSig Unsafe Const Rust (FnDecl [Arg (Just x') i32 ()] (Just i32) False ())) - (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()] ()) - , testP "impl Debug for i32 { pub default extern \"C\" fn foo(x: i32) -> i32 { return x + 1 } }" + (Generics [] (WhereClause [] ()) ()) + (MethodSig (FnHeader Unsafe NotAsync Const Rust ()) (FnDecl [Arg [] (Just x') i32 ()] (Just i32) False ())) + (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()] ()) + , testP "impl Debug for i32 { pub default extern \"C\" fn foo(x: i32) -> i32 { return x + 1 } }" (Impl [] InheritedV Final Normal Positive - (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 + (Generics [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [MethodI [] PublicV Default "foo" - (Generics [] [] (WhereClause [] ()) ()) - (MethodSig Normal NotConst C (FnDecl [Arg (Just x') i32 ()] (Just i32) False ()) ) - (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()] ()) - , testP "impl Debug for i32 { fn foo(&self) -> i32 { return x + 1 } }" + (Generics [] (WhereClause [] ()) ()) + (MethodSig (FnHeader Normal NotAsync NotConst C ()) (FnDecl [Arg [] (Just x') i32 ()] (Just i32) False ()) ) + (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()] ()) + , testP "impl Debug for i32 { fn foo(&self) -> i32 { return x + 1 } }" + (Impl [] InheritedV Final Normal Positive + (Generics [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 + [MethodI [] InheritedV Final "foo" + (Generics [] (WhereClause [] ()) ()) + (MethodSig (FnHeader Normal NotAsync NotConst Rust ()) (FnDecl [SelfRegion [] Nothing Immutable ()] (Just i32) False ()) ) + (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()] ()) + , testP "impl Debug for i32 { async fn foo() { } }" (Impl [] InheritedV Final Normal Positive - (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 + (Generics [] (WhereClause [] ()) ()) (Just (TraitRef debug)) i32 [MethodI [] InheritedV Final "foo" - (Generics [] [] (WhereClause [] ()) ()) - (MethodSig Normal NotConst Rust (FnDecl [SelfRegion Nothing Immutable ()] (Just i32) False ()) ) - (Block [NoSemi (Ret [] (Just (Binary [] AddOp (PathExpr [] Nothing x ()) (Lit [] (Int Dec 1 Unsuffixed ()) ()) ())) ()) ()] Normal ()) ()] ()) - , testP "trait Trace { }" (Trait [] InheritedV "Trace" False Normal (Generics [] [] (WhereClause [] ()) ()) [] [] ()) - , testP "unsafe trait Trace { }" (Trait [] InheritedV "Trace" False Unsafe (Generics [] [] (WhereClause [] ()) ()) [] [] ()) - , testP "unsafe auto trait Trace { }" (Trait [] InheritedV "Trace" True Unsafe (Generics [] [] (WhereClause [] ()) ()) [] [] ()) - , testP "trait Trace: Debug { }" (Trait [] InheritedV "Trace" False Normal (Generics [] [] (WhereClause [] ()) ()) [TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) None ()] [] ()) - , testP "unsafe trait Trace: Debug { }" (Trait [] InheritedV "Trace" False Unsafe (Generics [] [] (WhereClause [] ()) ()) [TraitTyParamBound (PolyTraitRef [] (TraitRef debug) ()) None ()] [] ()) - ] + (Generics [] (WhereClause [] ()) ()) + (MethodSig (FnHeader Normal IsAsync NotConst Rust ()) (FnDecl [] Nothing False ()) ) + (Block [] Normal ()) ()] ()) + , testP "trait Trace { }" (Trait [] InheritedV "Trace" False Normal (Generics [] (WhereClause [] ()) ()) [] [] ()) + , testP "unsafe trait Trace { }" (Trait [] InheritedV "Trace" False Unsafe (Generics [] (WhereClause [] ()) ()) [] [] ()) + , testP "unsafe auto trait Trace { }" (Trait [] InheritedV "Trace" True Unsafe (Generics [] (WhereClause [] ()) ()) [] [] ()) + , testP "trait Trace: Debug { }" (Trait [] InheritedV "Trace" False Normal (Generics [] (WhereClause [] ()) ()) [TraitBound (PolyTraitRef [] (TraitRef debug) ()) None ()] [] ()) + , testP "unsafe trait Trace: Debug { }" (Trait [] InheritedV "Trace" False Unsafe (Generics [] (WhereClause [] ()) ()) [TraitBound (PolyTraitRef [] (TraitRef debug) ()) None ()] [] ()) + , testP "default!{ SizeBounds, 0..100 }" (MacItem [] (Mac (Path False [PathSegment "default" Nothing ()] ()) + (Stream [ Tree (Token (Span (Position 10 1 10) (Position 20 1 20)) (IdentTok "SizeBounds")) + , Tree (Token (Span (Position 20 1 20) (Position 21 1 21)) Comma) + , Tree (Token (Span (Position 22 1 22) (Position 23 1 23)) (LiteralTok (IntegerTok "0") Nothing)) + , Tree (Token (Span (Position 23 1 23) (Position 25 1 25)) DotDot) + , Tree (Token (Span (Position 25 1 25) (Position 28 1 28)) (LiteralTok (IntegerTok "100") Nothing)) + ]) ()) ()) + ] -- Just a common expression to make the tests above more straightforward _1 :: Expr () diff --git a/test/unit-tests/PrettyTest.hs b/test/unit-tests/PrettyTest.hs index 1403cf5..70d09b6 100644 --- a/test/unit-tests/PrettyTest.hs +++ b/test/unit-tests/PrettyTest.hs @@ -34,7 +34,7 @@ usize = PathTy Nothing (Path False [PathSegment "usize" Nothing ()] ()) () std, vec, veci32, debug, println :: PathSegment () std = PathSegment "std" Nothing () vec = PathSegment "vec" Nothing () -veci32 = PathSegment "Vec" (Just (AngleBracketed [] [i32] [] ())) () +veci32 = PathSegment "Vec" (Just (AngleBracketed [TypeArg i32] [] ())) () debug = PathSegment "Debug" Nothing () println = PathSegment "println" Nothing () @@ -43,10 +43,10 @@ point :: Path () point = Path False [PathSegment "Point" Nothing ()] () -- | Type parameter bounds to make tests more straightforward -debug', lt, iterator :: TyParamBound () -debug' = TraitTyParamBound (PolyTraitRef [] (TraitRef (Path False [debug] ())) ()) None () -lt = RegionTyParamBound (Lifetime "lt" ()) () -iterator = TraitTyParamBound (PolyTraitRef [] (TraitRef (Path False [PathSegment "Iterator" (Just (AngleBracketed [] [] [(mkIdent "Item",i32)] ())) ()] ())) ()) None () +debug', lt, iterator :: GenericBound () +debug' = TraitBound (PolyTraitRef [] (TraitRef (Path False [debug] ())) ()) None () +lt = OutlivesBound (Lifetime "lt" ()) () +iterator = TraitBound (PolyTraitRef [] (TraitRef (Path False [PathSegment "Iterator" (Just (AngleBracketed [] [EqualityConstraint (mkIdent "Item") i32 ()] ())) ()] ())) ()) None () -- | Short expressions to make tests more straightforward _1, _2, foo, bar :: Expr () @@ -103,72 +103,72 @@ prettyLiterals = testGroup "printing literals" prettyPatterns :: Test prettyPatterns = testGroup "printing patterns" [ testFlatten "_" (printPat (WildP ())) + , testFlatten ".." (printPat (RestP ())) , testFlatten "x" (printPat x) + , testFlatten "x | .." (printPat (OrP [x, RestP ()] ())) , testFlatten "x @ _" (printPat (IdentP (ByValue Immutable) (mkIdent "x") (Just (WildP ())) ())) , testFlatten "ref x" (printPat (IdentP (ByRef Immutable) (mkIdent "x") Nothing ())) , testFlatten "mut x" (printPat (IdentP (ByValue Mutable) (mkIdent "x") Nothing ())) , testFlatten "ref mut x" (printPat (IdentP (ByRef Mutable) (mkIdent "x") Nothing ())) , testFlatten "Point { .. }" (printPat (StructP point [] True ())) , testFlatten "Point { x, y: y1 }" (printPat (StructP point - [ FieldPat Nothing x () - , FieldPat (Just "y") (IdentP (ByValue Immutable) "y1" Nothing ()) () ] + [ FieldPat Nothing x [] () + , FieldPat (Just "y") (IdentP (ByValue Immutable) "y1" Nothing ()) [] () ] False ())) , testFlatten "Point { x, .. }" (printPat (StructP point - [ FieldPat Nothing x () ] - True ())) - , testFlatten "Point(x)" (printPat (TupleStructP point - [ x ] Nothing ())) - , testFlatten "Point()" (printPat (TupleStructP point - [] Nothing ())) - , testFlatten "Point(..)" (printPat (TupleStructP point - [] (Just 0) ())) - , testFlatten "Point(x, ..)" (printPat (TupleStructP point - [ x ] (Just 1) ())) - , testFlatten "Point(.., x)" (printPat (TupleStructP point - [ x ] (Just 0) ())) - , testFlatten "Point(x, _, .., _, x)" (printPat (TupleStructP point - [ x, WildP (), WildP (), x ] (Just 2) ())) + [ FieldPat Nothing x [] () ] + True ())) + , testFlatten "Point(x)" (printPat (TupleStructP point [ x ] ())) + , testFlatten "Point()" (printPat (TupleStructP point [] ())) + , testFlatten "Point(..)" (printPat (TupleStructP point [RestP ()] ())) + , testFlatten "Point(x, ..)" (printPat (TupleStructP point [ x, RestP () ] ())) + , testFlatten "Point(.., x)" (printPat (TupleStructP point [ RestP (), x ] ())) + , testFlatten "Point(x, _, .., _, x)" (printPat (TupleStructP point [ x, WildP (), RestP (), WildP (), x ] ())) , testFlatten "math::PI" (printPat (PathP Nothing (Path False [ PathSegment "math" Nothing () , PathSegment "PI" Nothing () ] ()) ())) , testFlatten "::b::<'lt>::AssociatedItem" (printPat (PathP (Just (QSelf i32 1)) (Path False [ PathSegment "a" (Just (Parenthesized [i32, i32] Nothing ())) () - , PathSegment "b" (Just (AngleBracketed [Lifetime "lt" ()] [] [] ())) () + , PathSegment "b" (Just (AngleBracketed [LifetimeArg (Lifetime "lt" ())] [] ())) () , PathSegment "AssociatedItem" Nothing () ] ()) ())) , testFlatten "(x, ref mut y, box z)" (printPat (TupleP [ x , IdentP (ByRef Mutable) "y" Nothing () , BoxP (IdentP (ByValue Immutable) "z" Nothing ()) () - ] - Nothing ())) - , testFlatten "ref mut y @ (x, x)" (printPat (IdentP (ByRef Mutable) "y" (Just (TupleP [ x, x ] Nothing ())) ())) + ] + ())) + , testFlatten "ref mut y @ (x, x)" (printPat (IdentP (ByRef Mutable) "y" (Just (TupleP [ x, x ] ())) ())) , testFlatten "(1, 2, .., 3)" (printPat (TupleP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () - , LitP (Lit [] (Int Dec 2 Unsuffixed ()) ()) () - , LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] - (Just 2) ())) + , LitP (Lit [] (Int Dec 2 Unsuffixed ()) ()) () + , RestP () + , LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] + ())) + , testFlatten "(..)" (printPat (TupleP [ RestP () ] ())) , testFlatten "box x" (printPat (BoxP x ())) - , testFlatten "1 ..= 2" (printPat (RangeP (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 2 Unsuffixed ()) ()) ())) + , testFlatten "1 ..= 2" (printPat (RangeP (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 2 Unsuffixed ()) ()) Closed ())) + , testFlatten "1 .. 2" (printPat (RangeP (Lit [] (Int Dec 1 Unsuffixed ()) ()) (Lit [] (Int Dec 2 Unsuffixed ()) ()) HalfOpen ())) , testFlatten "&x" (printPat (RefP x Immutable ())) , testFlatten "&mut x" (printPat (RefP x Mutable ())) , testFlatten "true" (printPat (LitP (Lit [] (Bool True Unsuffixed ()) ()) ())) , testFlatten "-123" (printPat (LitP (Unary [] Neg (Lit [] (Int Dec 123 Unsuffixed ()) ()) ()) ())) , testFlatten "[1, 2]" (printPat (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () - , LitP (Lit [] (Int Dec 2 Unsuffixed ()) ()) () ] - Nothing [] ())) - , testFlatten "[1, .., 3]" (printPat (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () ] - (Just (WildP ())) - [ LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] ())) - , testFlatten "[1, x.., 3]" (printPat (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () ] - (Just x) - [ LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] ())) - , testFlatten "[1, ..]" (printPat (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () ] (Just (WildP ())) [] ())) - , testFlatten "[1, x..]" (printPat (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () ] (Just x) [] ())) + , LitP (Lit [] (Int Dec 2 Unsuffixed ()) ()) () ] + ())) + , testFlatten "[1, .., 3]" (printPat (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () + , RestP () + , LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] ())) + , testFlatten "[1, x @ .., 3]" (printPat (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () + , IdentP (ByValue Immutable) "x" (Just (RestP ())) () + , LitP (Lit [] (Int Dec 3 Unsuffixed ()) ()) () ] ())) + , testFlatten "[1, _]" (printPat (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) (), WildP () ] ())) + , testFlatten "[1, x @ ..]" (printPat (SliceP [ LitP (Lit [] (Int Dec 1 Unsuffixed ()) ()) () + , IdentP (ByValue Immutable) "x" (Just (RestP ())) () ] ())) , testFlatten "vec!(foo)" (printPat (MacP (Mac (Path False [vec] ()) (Stream [ Tree (Token mempty (IdentTok (mkIdent "foo"))) ]) ()) ())) ] --- | Test pretty printing of types (flattened). +-- | Test pretty printing of types (flattened). prettyTypes :: Test prettyTypes = testGroup "printing types" [ testFlatten "i32" (printType i32) @@ -188,7 +188,8 @@ prettyTypes = testGroup "printing types" , testFlatten "(i32, f64, usize)" (printType (TupTy [i32,f64,usize] ())) , testFlatten "std::vec::Vec" (printType (PathTy Nothing (Path False [ std, vec, veci32 ] ()) ())) , testFlatten "::Vec" (printType (PathTy (Just (QSelf i32 2)) (Path False [ std, vec, veci32 ] ()) ())) - , testFlatten "Debug + 'lt" (printType (TraitObject [ debug', lt ] ())) + , testFlatten "::Vec" (printType (PathTy (Just (QSelf i32 3)) (Path True [ std, vec, veci32 ] ()) ())) + , testFlatten "dyn Debug + 'lt" (printType (TraitObject [ debug', lt ] ())) , testFlatten "impl Iterator + 'lt" (printType (ImplTrait [ iterator, lt ] ())) , testFlatten "(i32)" (printType (ParenTy i32 ())) , testFlatten "typeof(1i32)" (printType (Typeof (Lit [] (Int Dec 1 I32 ()) ()) ())) @@ -220,17 +221,17 @@ prettyTypes = testGroup "printing types" , Tree (Token (Span (Position 27 1 27) (Position 28 1 28)) Greater) ]) ()) - ())) + ())) , testFlatten "fn(i32) -> i32" - (printType (BareFn Normal Rust [] (FnDecl [Arg Nothing i32 ()] (Just i32) False ()) ())) + (printType (BareFn Normal Rust [] (FnDecl [Arg [] Nothing i32 ()] (Just i32) False ()) ())) , testFlatten "unsafe extern \"C\" fn(i32) -> i32" - (printType (BareFn Unsafe C [] (FnDecl [Arg Nothing i32 ()] (Just i32) False ()) ())) + (printType (BareFn Unsafe C [] (FnDecl [Arg [] Nothing i32 ()] (Just i32) False ()) ())) ] - + -- | Test pretty printing of attributes (flattened). prettyAttributes :: Test prettyAttributes = testGroup "printing attributes" - [ testFlatten "#![cfgi]" (printAttr cfgI True) + [ testFlatten "#![cfgi]" (printAttr cfgI True) , testFlatten "#[cfgo]" (printAttr cfgO True) , testFlatten "#[derive(Eq, Ord, 1)]" (printAttr (Attribute Outer (Path False [PathSegment "derive" Nothing ()] ()) (Tree (Delimited mempty Paren (Stream [ Tree (Token mempty (IdentTok "Eq")) @@ -245,23 +246,22 @@ prettyAttributes = testGroup "printing attributes" ]) ()) True) , testFlatten "/** some comment */" (printAttr (SugaredDoc Outer True " some comment " ()) True) ] - --- | Test pretty printing of expressions (flattened). + +-- | Test pretty printing of expressions (flattened). prettyExpressions :: Test prettyExpressions = testGroup "printing expressions" - [ testFlatten "foo" (printExpr foo) - , testFlatten "bar" (printExpr bar) - , testFlatten "1" (printExpr _1) - , testFlatten "#[cfgo] 2" (printExpr _2) + [ testFlatten "foo" (printExpr foo) + , testFlatten "bar" (printExpr bar) + , testFlatten "1" (printExpr _1) + , testFlatten "#[cfgo] 2" (printExpr _2) , testFlatten "box 1" (printExpr (Box [] _1 ())) , testFlatten "#[cfgo] box #[cfgo] 2" (printExpr (Box [cfgO] _2 ())) - , testFlatten "#[cfgo] 2 <- 1" (printExpr (InPlace [] _2 _1 ())) , testFlatten "[ 1, 1, 1 ]" (printExpr (Vec [] [_1,_1,_1] ())) , testFlatten "#[cfgo] [ #![cfgi] #[cfgo] 2, 1, #[cfgo] 2 ]" (printExpr (Vec [cfgO,cfgI] [_2,_1,_2] ())) , testFlatten "foo(1, bar)" (printExpr (Call [] foo [_1,bar] ())) - , testFlatten "foo.method::(1, bar)" (printExpr (MethodCall [] foo (mkIdent "method") (Just [i32,f64]) [_1,bar] ())) - , testFlatten "foo.method::<>(1, bar)" (printExpr (MethodCall [] foo (mkIdent "method") (Just []) [_1,bar] ())) - , testFlatten "foo.method(1, bar)" (printExpr (MethodCall [] foo (mkIdent "method") Nothing [_1,bar] ())) + , testFlatten "foo.method::(1, bar)" (printExpr (MethodCall [] foo (PathSegment "method" (Just (AngleBracketed [TypeArg i32,TypeArg f64] [] ())) ()) [_1,bar] ())) + , testFlatten "foo.method::<>(1, bar)" (printExpr (MethodCall [] foo (PathSegment "method" (Just (AngleBracketed [] [] ())) ()) [_1,bar] ())) + , testFlatten "foo.method(1, bar)" (printExpr (MethodCall [] foo (PathSegment "method" Nothing ()) [_1,bar] ())) , testFlatten "()" (printExpr (TupExpr [] [] ())) , testFlatten "#[cfgo] (#![cfgi])" (printExpr (TupExpr [cfgO,cfgI] [] ())) , testFlatten "(1,)" (printExpr (TupExpr [] [_1] ())) @@ -281,45 +281,62 @@ prettyExpressions = testGroup "printing expressions" , testFlatten "(foo + 1) as i32" (printExpr (Cast [] (ParenExpr [] (Binary [] AddOp foo _1 ()) ()) i32 ())) , testFlatten "foo: i32" (printExpr (TypeAscription [] foo i32 ())) , testFlatten "if foo { foo = 1 }" (printExpr (If [] foo assBlk Nothing ())) - , testFlatten "if foo { foo = 1 } else { return 1; }" (printExpr (If [] foo assBlk (Just (BlockExpr [] retBlk ())) ())) + , testFlatten "if foo { foo = 1 } else { return 1; }" (printExpr (If [] foo assBlk (Just (BlockExpr [] retBlk Nothing ())) ())) , testFlatten "if foo { foo = 1 } else if bar { return 1; }" (printExpr (If [] foo assBlk (Just (If [] bar retBlk Nothing ())) ())) - , testFlatten "if let foo = 1 { return 1; }" (printExpr (IfLet [] [IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()] _1 retBlk Nothing ())) - , testFlatten "if let foo = 1 { return 1; } else { return 1; }" (printExpr (IfLet [] [IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()] _1 retBlk (Just (BlockExpr [] retBlk ())) ())) + , testFlatten "if let foo = 1 { return 1; }" (printExpr (IfLet [] (IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()) _1 retBlk Nothing ())) + , testFlatten "if let foo = 1 { return 1; } else { return 1; }" (printExpr (IfLet [] (IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()) _1 retBlk (Just (BlockExpr [] retBlk Nothing ())) ())) , testFlatten "while foo { foo = 1 }" (printExpr (While [] foo assBlk Nothing ())) , testFlatten "'lbl: while foo { foo = 1 }" (printExpr (While [] foo assBlk (Just (Label "lbl" ())) ())) , testFlatten "#[cfgo] while foo { #![cfgi] foo = 1 }" (printExpr (While [cfgI,cfgO] foo assBlk Nothing ())) - , testFlatten "while let foo = 1 { foo = 1 }" (printExpr (WhileLet [] [IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()] _1 assBlk Nothing ())) - , testFlatten "'lbl: while let foo = 1 { foo = 1 }" (printExpr (WhileLet [] [IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()] _1 assBlk (Just (Label "lbl" ())) ())) - , testFlatten "#[cfgo] while let foo = 1 { #![cfgi] foo = 1 }" (printExpr (WhileLet [cfgO,cfgI] [IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()] _1 assBlk Nothing ())) + , testFlatten "while let foo = 1 { foo = 1 }" (printExpr (WhileLet [] (IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()) _1 assBlk Nothing ())) + , testFlatten "while let foo | _ = 1 { foo = 1 }" (printExpr (WhileLet [] (OrP [IdentP (ByValue Immutable) (mkIdent "foo") Nothing (), WildP ()] ()) _1 assBlk Nothing ())) + , testFlatten "'lbl: while let foo = 1 { foo = 1 }" (printExpr (WhileLet [] (IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()) _1 assBlk (Just (Label "lbl" ())) ())) + , testFlatten "#[cfgo] while let foo = 1 { #![cfgi] foo = 1 }" (printExpr (WhileLet [cfgO,cfgI] (IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()) _1 assBlk Nothing ())) , testFlatten "for foo in bar { foo = 1 }" (printExpr (ForLoop [] (IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()) bar assBlk Nothing ())) , testFlatten "'lbl: for foo in bar { foo = 1 }" (printExpr (ForLoop [] (IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()) bar assBlk (Just (Label "lbl" ())) ())) , testFlatten "#[cfgo] for foo in bar { #![cfgi] foo = 1 }" (printExpr (ForLoop [cfgO,cfgI] (IdentP (ByValue Immutable) (mkIdent "foo") Nothing ()) bar assBlk Nothing ())) , testFlatten "loop { foo = 1 }" (printExpr (Loop [] assBlk Nothing ())) , testFlatten "'lbl: loop { foo = 1 }" (printExpr (Loop [] assBlk (Just (Label "lbl" ())) ())) , testFlatten "#[cfgo] loop { #![cfgi] foo = 1 }" (printExpr (Loop [cfgO,cfgI] assBlk Nothing ())) - , testFlatten "match foo { }" (printExpr (Match [] foo [] ())) - , testFlatten "match foo { _ => 1 }" (printExpr (Match [] foo [Arm [] [WildP ()] Nothing _1 ()] ())) - , testFlatten "#[cfgo] match foo { #![cfgi] _ => 1 }" (printExpr (Match [cfgI,cfgO] foo [Arm [] [WildP ()] Nothing _1 ()] ())) - , testFlatten "match foo { _ => { return 1; } }" (printExpr (Match [] foo [Arm [] [WildP ()] Nothing (BlockExpr [] retBlk ()) ()] ())) - , testFlatten "match foo { _ => { return 1; }, _ | _ if foo => 1 }" (printExpr (Match [] foo [Arm [] [WildP ()] Nothing (BlockExpr [] retBlk ()) (), Arm [] [WildP (), WildP ()] (Just foo) _1 ()] ())) + , testFlatten "match foo { }" (printExpr (Match [] foo [] ())) + , testFlatten "match foo { _ => 1 }" (printExpr (Match [] foo [Arm [] (WildP ()) Nothing _1 ()] ())) + , testFlatten "#[cfgo] match foo { #![cfgi] _ => 1 }" (printExpr (Match [cfgI,cfgO] foo [Arm [] (WildP ()) Nothing _1 ()] ())) + , testFlatten "match foo { _ => { return 1; } }" (printExpr (Match [] foo [Arm [] (WildP ()) Nothing (BlockExpr [] retBlk Nothing ()) ()] ())) + , testFlatten "match foo { _ => { return 1; }, _ | _ if foo => 1 }" (printExpr (Match [] foo [Arm [] (WildP ()) Nothing (BlockExpr [] retBlk Nothing ()) (), Arm [] (OrP [WildP (), WildP ()] ()) (Just foo) _1 ()] ())) , testFlatten "move |x: i32| { return 1; }" - (printExpr (Closure [] Movable Value (FnDecl [Arg (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) - (BlockExpr [] retBlk ()) ())) + (printExpr (Closure [] Value NotAsync Movable (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) + (BlockExpr [] retBlk Nothing ()) ())) , testFlatten "static move |x: i32| { return 1; }" - (printExpr (Closure [] Immovable Value (FnDecl [Arg (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) - (BlockExpr [] retBlk ()) ())) + (printExpr (Closure [] Value NotAsync Immovable (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) + (BlockExpr [] retBlk Nothing ()) ())) , testFlatten "|x: i32| -> i32 { return 1; }" - (printExpr (Closure [] Movable Ref (FnDecl [Arg (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] (Just i32) False ()) - (BlockExpr [] retBlk ()) ())) + (printExpr (Closure [] Ref NotAsync Movable (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] (Just i32) False ()) + (BlockExpr [] retBlk Nothing ()) ())) , testFlatten "static |x: i32| -> i32 { return 1; }" - (printExpr (Closure [] Immovable Ref (FnDecl [Arg (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] (Just i32) False ()) - (BlockExpr [] retBlk ()) ())) - , testFlatten "#[cfgo] { #![cfgi] return 1; }" (printExpr (BlockExpr [cfgI,cfgO] retBlk ())) - , testFlatten "{ return 1; }" (printExpr (BlockExpr [] retBlk ())) - , testFlatten "do catch { return 1; }" (printExpr (Catch [] retBlk ())) + (printExpr (Closure [] Ref NotAsync Immovable (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] (Just i32) False ()) + (BlockExpr [] retBlk Nothing ()) ())) + , testFlatten "async move |x: i32| { return 1; }" + (printExpr (Closure [] Value IsAsync Movable (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) + (BlockExpr [] retBlk Nothing ()) ())) + , testFlatten "static async move |x: i32| { return 1; }" + (printExpr (Closure [] Value IsAsync Immovable (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) + (BlockExpr [] retBlk Nothing ()) ())) + , testFlatten "async |x: i32| -> i32 { return 1; }" + (printExpr (Closure [] Ref IsAsync Movable (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] (Just i32) False ()) + (BlockExpr [] retBlk Nothing ()) ())) + , testFlatten "static async |x: i32| -> i32 { return 1; }" + (printExpr (Closure [] Ref IsAsync Immovable (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] (Just i32) False ()) + (BlockExpr [] retBlk Nothing ()) ())) + , testFlatten "#[cfgo] { #![cfgi] return 1; }" (printExpr (BlockExpr [cfgI,cfgO] retBlk Nothing ())) + , testFlatten "{ return 1; }" (printExpr (BlockExpr [] retBlk Nothing ())) + , testFlatten "'lbl: { return 1; }" (printExpr (BlockExpr [] retBlk (Just (Label "lbl" ())) ())) + , testFlatten "try { return 1; }" (printExpr (TryBlock [] retBlk ())) + , testFlatten "async { return 1; }" (printExpr (Async [] Ref retBlk ())) + , testFlatten "async move { return 1; }" (printExpr (Async [] Value retBlk ())) , testFlatten "foo = 1" (printExpr (Assign [] foo _1 ())) , testFlatten "foo += 1" (printExpr (AssignOp [] AddOp foo _1 ())) , testFlatten "foo <<= 1" (printExpr (AssignOp [] ShlOp foo _1 ())) + , testFlatten "foo.await" (printExpr (Await [] foo ())) , testFlatten "foo.bar" (printExpr (FieldAccess [] foo (mkIdent "bar") ())) , testFlatten "foo.1" (printExpr (TupField [] foo 1 ())) , testFlatten "foo[1]" (printExpr (Index [] foo _1 ())) @@ -342,11 +359,11 @@ prettyExpressions = testGroup "printing expressions" , testFlatten "print!(foo)" (printExpr (MacExpr [] (Mac (Path False [PathSegment "print" Nothing ()] ()) (Stream [ Tree (Token mempty (IdentTok (mkIdent "foo"))) ]) ()) ())) , testFlatten "foo { }" (printExpr (Struct [] (Path False [PathSegment "foo" Nothing ()] ()) [] Nothing ())) - , testFlatten "foo { x: 1 }" (printExpr (Struct [] (Path False [PathSegment "foo" Nothing ()] ()) [Field (mkIdent "x") (Just _1) ()] Nothing ())) - , testFlatten "#[cfgo] foo { #![cfgi] x: 1 }" (printExpr (Struct [cfgO,cfgI] (Path False [PathSegment "foo" Nothing ()] ()) [Field (mkIdent "x") (Just _1) ()] Nothing ())) - , testFlatten "foo { x: 1, y: 1 }" (printExpr (Struct [] (Path False [PathSegment "foo" Nothing ()] ()) [Field (mkIdent "x") (Just _1) (), Field (mkIdent "y") (Just _1) ()] Nothing ())) - , testFlatten "foo { x: 1, y: 1, ..bar }" (printExpr (Struct [] (Path False [PathSegment "foo" Nothing ()] ()) [Field (mkIdent "x") (Just _1) (), Field (mkIdent "y") (Just _1) ()] (Just bar) ())) - , testFlatten "#[cfgo] foo { #![cfgi] x, y, ..bar }" (printExpr (Struct [cfgO,cfgI] (Path False [PathSegment "foo" Nothing ()] ()) [Field (mkIdent "x") Nothing (), Field (mkIdent "y") Nothing ()] (Just bar) ())) + , testFlatten "foo { x: 1 }" (printExpr (Struct [] (Path False [PathSegment "foo" Nothing ()] ()) [Field "x" (Just _1) [] ()] Nothing ())) + , testFlatten "#[cfgo] foo { #![cfgi] x: 1 }" (printExpr (Struct [cfgO,cfgI] (Path False [PathSegment "foo" Nothing ()] ()) [Field "x" (Just _1) [] ()] Nothing ())) + , testFlatten "foo { x: 1, y: 1 }" (printExpr (Struct [] (Path False [PathSegment "foo" Nothing ()] ()) [Field "x" (Just _1) [] (), Field "y" (Just _1) [] ()] Nothing ())) + , testFlatten "foo { x: 1, y: 1, ..bar }" (printExpr (Struct [] (Path False [PathSegment "foo" Nothing ()] ()) [Field "x" (Just _1) [] (), Field "y" (Just _1) [] ()] (Just bar) ())) + , testFlatten "#[cfgo] foo { #![cfgi] x, y, ..bar }" (printExpr (Struct [cfgO,cfgI] (Path False [PathSegment "foo" Nothing ()] ()) [Field "x" Nothing [] (), Field "y" Nothing [] ()] (Just bar) ())) , testFlatten "[foo; 1]" (printExpr (Repeat [] foo _1 ())) , testFlatten "#[cfgo] [#![cfgi] foo; 1]" (printExpr (Repeat [cfgI, cfgO] foo _1 ())) , testFlatten "(foo?)" (printExpr (ParenExpr [] (Try [] foo ()) ())) @@ -368,111 +385,113 @@ prettyItems = testGroup "printing items" , testFlatten "static mut foo: i32 = 1;" (printItem (Static [] InheritedV (mkIdent "foo") i32 Mutable _1 ())) , testFlatten "static foo: i32 = 1;" (printItem (Static [] InheritedV (mkIdent "foo") i32 Immutable _1 ())) , testFlatten "const foo: i32 = 1;" (printItem (ConstItem [] InheritedV (mkIdent "foo") i32 _1 ())) - , testFlatten "fn foo(x: i32) -> i32 { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [Arg (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] (Just i32) False ()) Normal NotConst Rust (Generics [] [] (WhereClause [] ()) ()) retBlk ())) - , testFlatten "unsafe fn foo(x: i32, ...) { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [Arg (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing True ()) Unsafe NotConst Rust (Generics [] [] (WhereClause [] ()) ()) retBlk ())) - , testFlatten "const unsafe extern \"C\" fn foo(x: i32) { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [Arg (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) Unsafe Const C (Generics [] [] (WhereClause [] ()) ()) retBlk ())) - , testFlatten "fn foo<'lt: 'foo + 'bar, T, U: Debug + 'lt = i32>(x: i32) { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [Arg (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) Normal NotConst Rust (Generics [LifetimeDef [] (Lifetime "lt" ()) [Lifetime "foo" (), Lifetime "bar" ()] ()] [TyParam [] (mkIdent "T") [] Nothing (), TyParam [] (mkIdent "U") [debug', lt] (Just i32) ()] (WhereClause [] ()) ()) retBlk ())) - , testFlatten "fn foo(x: i32) where for<'lt> i32: Debug, 'foo: 'bar, vec::std = i32 { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [Arg (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) Normal NotConst Rust (Generics [] [TyParam [] (mkIdent "T") [] Nothing (), TyParam [] (mkIdent "U") [debug', lt] (Just i32) ()] (WhereClause [BoundPredicate [LifetimeDef [] (Lifetime "lt" ()) [] ()] i32 [debug'] (), RegionPredicate (Lifetime "foo" ()) [Lifetime "bar" ()] (), EqPredicate (PathTy Nothing (Path False [vec,std] ()) ()) i32 ()] ()) ()) retBlk ())) + , testFlatten "fn foo(x: i32) -> i32 { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] (Just i32) False ()) (FnHeader Normal NotAsync NotConst Rust ()) (Generics [] (WhereClause [] ()) ()) retBlk ())) + , testFlatten "async fn foo() { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [] Nothing False ()) (FnHeader Normal IsAsync NotConst Rust ()) (Generics [] (WhereClause [] ()) ()) retBlk ())) + , testFlatten "unsafe fn foo(x: i32, ...) { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing True ()) (FnHeader Unsafe NotAsync NotConst Rust ()) (Generics [] (WhereClause [] ()) ()) retBlk ())) + , testFlatten "const unsafe extern \"C\" fn foo(x: i32) { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) (FnHeader Unsafe NotAsync Const C ()) (Generics [] (WhereClause [] ()) ()) retBlk ())) + , testFlatten "fn foo<'lt: 'foo + 'bar, T, U: Debug + 'lt = i32>(x: i32) { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) (FnHeader Normal NotAsync NotConst Rust ()) (Generics [LifetimeParam [] (Lifetime "lt" ()) [OutlivesBound (Lifetime "foo" ()) (), OutlivesBound (Lifetime "bar" ()) ()] (), TypeParam [] (mkIdent "T") [] Nothing (), TypeParam [] (mkIdent "U") [debug', lt] (Just i32) ()] (WhereClause [] ()) ()) retBlk ())) + , testFlatten "fn foo(x: i32) where for<'lt> i32: Debug, 'foo: 'bar, vec::std = i32 { return 1; }" (printItem (Fn [] InheritedV (mkIdent "foo") (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] Nothing False ()) (FnHeader Normal NotAsync NotConst Rust ()) (Generics [TypeParam [] (mkIdent "T") [] Nothing (), TypeParam [] (mkIdent "U") [debug', lt] (Just i32) ()] (WhereClause [BoundPredicate [LifetimeParam [] (Lifetime "lt" ()) [] ()] i32 [debug'] (), RegionPredicate (Lifetime "foo" ()) [Lifetime "bar" ()] (), EqPredicate (PathTy Nothing (Path False [vec,std] ()) ()) i32 ()] ()) ()) retBlk ())) , testFlatten "mod serialize;" (printItem (Mod [] InheritedV (mkIdent "serialize") Nothing ())) , testFlatten "mod serialize { }" (printItem (Mod [] InheritedV (mkIdent "serialize") (Just []) ())) , testFlatten "mod serialize { const foo: i32 = 1; }" (printItem (Mod [] InheritedV (mkIdent "serialize") (Just [ConstItem [] InheritedV (mkIdent "foo") i32 _1 ()]) ())) , testFlatten "#[cfgo] mod serialize { #![cfgi] const foo: i32 = 1; }" (printItem (Mod [cfgO,cfgI] InheritedV (mkIdent "serialize") (Just [ConstItem [] InheritedV (mkIdent "foo") i32 _1 ()]) ())) , testFlatten "extern \"C\" { }" (printItem (ForeignMod [] InheritedV C [] ())) , testFlatten "extern \"C\" { static mut foo: i32; }" (printItem (ForeignMod [] InheritedV C [ForeignStatic [] InheritedV (mkIdent "foo") i32 Mutable ()] ())) - , testFlatten "#[cfgo] extern \"C\" { #![cfgi] fn foo(x: i32) -> i32; }" (printItem (ForeignMod [cfgO,cfgI] InheritedV C [ForeignFn [] InheritedV (mkIdent "foo") (FnDecl [Arg (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] (Just i32) False ()) (Generics [] [] (WhereClause [] ()) ()) ()] ())) + , testFlatten "#[cfgo] extern \"C\" { #![cfgi] fn foo(x: i32) -> i32; }" (printItem (ForeignMod [cfgO,cfgI] InheritedV C [ForeignFn [] InheritedV (mkIdent "foo") (FnDecl [Arg [] (Just (IdentP (ByValue Immutable) (mkIdent "x") Nothing ())) i32 ()] (Just i32) False ()) (Generics [] (WhereClause [] ()) ()) ()] ())) , testFlatten "#[cfgo] extern \"C\" { #![cfgi] static foo: i32; }" (printItem (ForeignMod [cfgO,cfgI] InheritedV C [ForeignStatic [] InheritedV (mkIdent "foo") i32 Immutable ()] ())) - , testFlatten "type Vec = i32;" (printItem (TyAlias [] InheritedV (mkIdent "Vec") i32 (Generics [] [TyParam [] (mkIdent "T") [] Nothing ()] (WhereClause [] ()) ()) ())) - , testFlatten "enum foo { }" (printItem (Enum [] InheritedV (mkIdent "foo") [] (Generics [] [TyParam [] (mkIdent "T") [] Nothing ()] (WhereClause [] ()) ()) ())) + , testFlatten "type Vec = i32;" (printItem (TyAlias [] InheritedV (mkIdent "Vec") i32 (Generics [TypeParam [] (mkIdent "T") [] Nothing ()] (WhereClause [] ()) ()) ())) + , testFlatten "enum foo { }" (printItem (Enum [] InheritedV (mkIdent "foo") [] (Generics [TypeParam [] (mkIdent "T") [] Nothing ()] (WhereClause [] ()) ()) ())) , testFlatten "enum color { #[cfgo] red { i32 } = 1, blue(i32), green }" (printItem (Enum [] InheritedV (mkIdent "color") [ Variant (mkIdent "red") [cfgO] (StructD [StructField Nothing InheritedV i32 [] ()] ()) (Just _1) () , Variant (mkIdent "blue") [] (TupleD [StructField Nothing InheritedV i32 [] ()] ()) Nothing () , Variant (mkIdent "green") [] (UnitD ()) Nothing ()] - (Generics [] [] (WhereClause [] ()) ()) ())) - , testFlatten "struct red { x: i32 }" (printItem (StructItem [] InheritedV (mkIdent "red") (StructD [StructField (Just (mkIdent "x")) InheritedV i32 [] ()] ()) (Generics [] [] (WhereClause [] ()) ()) ())) - , testFlatten "union red { x: i32 }" (printItem (Union [] InheritedV (mkIdent "red") (StructD [StructField (Just (mkIdent "x")) InheritedV i32 [] ()] ()) (Generics [] [] (WhereClause [] ()) ()) ())) - , testFlatten "union red { x: i32 }" (printItem (Union [] InheritedV (mkIdent "red") (StructD [StructField (Just (mkIdent "x")) InheritedV i32 [] ()] ()) (Generics [] [] (WhereClause [] ()) ()) ())) - , testFlatten "impl Debug for i32 { }" (printItem (Impl [] InheritedV Final Normal Positive (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef (Path False [debug] ()))) i32 [] ())) - , testFlatten "default impl Debug for i32 { }" (printItem (Impl [] InheritedV Default Normal Positive (Generics [] [] (WhereClause [] ()) ()) (Just (TraitRef (Path False [debug] ()))) i32 [] ())) - , testFlatten "pub impl !Debug for i32 where 'lt: 'gt { }" (printItem (Impl [] PublicV Final Normal Negative (Generics [] [] (WhereClause [RegionPredicate (Lifetime "lt" ()) [Lifetime "gt" ()] ()] ()) ()) (Just (TraitRef (Path False [debug] ()))) i32 [] ())) - , testFlatten "impl GenVal { fn value(&mut self) -> &T { return 1; } }" + (Generics [] (WhereClause [] ()) ()) ())) + , testFlatten "struct red { x: i32 }" (printItem (StructItem [] InheritedV (mkIdent "red") (StructD [StructField (Just (mkIdent "x")) InheritedV i32 [] ()] ()) (Generics [] (WhereClause [] ()) ()) ())) + , testFlatten "union red { x: i32 }" (printItem (Union [] InheritedV (mkIdent "red") (StructD [StructField (Just (mkIdent "x")) InheritedV i32 [] ()] ()) (Generics [] (WhereClause [] ()) ()) ())) + , testFlatten "union red { x: i32 }" (printItem (Union [] InheritedV (mkIdent "red") (StructD [StructField (Just (mkIdent "x")) InheritedV i32 [] ()] ()) (Generics [] (WhereClause [] ()) ()) ())) + , testFlatten "impl Debug for i32 { }" (printItem (Impl [] InheritedV Final Normal Positive (Generics [] (WhereClause [] ()) ()) (Just (TraitRef (Path False [debug] ()))) i32 [] ())) + , testFlatten "default impl Debug for i32 { }" (printItem (Impl [] InheritedV Default Normal Positive (Generics [] (WhereClause [] ()) ()) (Just (TraitRef (Path False [debug] ()))) i32 [] ())) + , testFlatten "pub impl !Debug for i32 where 'lt: 'gt { }" (printItem (Impl [] PublicV Final Normal Negative (Generics [] (WhereClause [RegionPredicate (Lifetime "lt" ()) [Lifetime "gt" ()] ()] ()) ()) (Just (TraitRef (Path False [debug] ()))) i32 [] ())) + , testFlatten "impl GenVal { fn value(&mut self) -> &T { return 1; } }" (printItem (Impl [] InheritedV Final Normal Positive - (Generics [] [TyParam [] (mkIdent "T") [] Nothing ()] (WhereClause [] ()) ()) + (Generics [TypeParam [] (mkIdent "T") [] Nothing ()] (WhereClause [] ()) ()) Nothing - (PathTy Nothing (Path False [PathSegment "GenVal" (Just (AngleBracketed [] [PathTy Nothing (Path False [PathSegment "T" Nothing ()] ()) ()] [] ())) ()] ()) ()) + (PathTy Nothing (Path False [PathSegment "GenVal" (Just (AngleBracketed [TypeArg (PathTy Nothing (Path False [PathSegment "T" Nothing ()] ()) ())] [] ())) ()] ()) ()) [ MethodI [] InheritedV Final (mkIdent "value") - (Generics [] [] (WhereClause [] ()) ()) - (MethodSig Normal NotConst Rust - (FnDecl [SelfRegion Nothing Mutable ()] - (Just (Rptr Nothing Immutable (PathTy Nothing (Path False [PathSegment "T" Nothing ()] ()) ()) ())) - False ())) + (Generics [] (WhereClause [] ()) ()) + (MethodSig (FnHeader Normal NotAsync NotConst Rust ()) + (FnDecl [SelfRegion [] Nothing Mutable ()] + (Just (Rptr Nothing Immutable (PathTy Nothing (Path False [PathSegment "T" Nothing ()] ()) ()) ())) + False ())) retBlk () ] ())) - , testFlatten "#[cfgo] impl i32 { #![cfgi] fn value(&self) -> i32 { return 1; } pub const pi: i32 = 1; default type Size = i32; }" + , testFlatten "#[cfgo] impl i32 { #![cfgi] async fn value(&self) -> i32 { return 1; } pub const pi: i32 = 1; default type Size = i32; }" (printItem (Impl [cfgI,cfgO] InheritedV Final Normal Positive - (Generics [] [] (WhereClause [] ()) ()) + (Generics [] (WhereClause [] ()) ()) Nothing i32 [ MethodI [] InheritedV Final (mkIdent "value") - (Generics [] [] (WhereClause [] ()) ()) - (MethodSig Normal NotConst Rust - (FnDecl [SelfRegion Nothing Immutable ()] - (Just i32) - False ())) + (Generics [] (WhereClause [] ()) ()) + (MethodSig (FnHeader Normal IsAsync NotConst Rust ()) + (FnDecl [SelfRegion [] Nothing Immutable ()] + (Just i32) + False ())) retBlk () , ConstI [] PublicV Final (mkIdent "pi") i32 _1 () , TypeI [] InheritedV Default (mkIdent "Size") i32 () ] ())) - , testFlatten "unsafe trait Show { }" (printItem (Trait [] InheritedV (mkIdent "Show") False Unsafe (Generics [] [] (WhereClause [] ()) ()) [] [] ())) + , testFlatten "unsafe trait Show { }" (printItem (Trait [] InheritedV (mkIdent "Show") False Unsafe (Generics [] (WhereClause [] ()) ()) [] [] ())) , testFlatten "trait Show: 'l1 + for<'l3: 'l1 + 'l2> Debug + 'l2 { }" (printItem (Trait [] InheritedV (mkIdent "Show") False Normal - (Generics [] [TyParam [] (mkIdent "T") [] Nothing ()] (WhereClause [] ()) ()) - [ RegionTyParamBound (Lifetime "l1" ()) () - , TraitTyParamBound (PolyTraitRef [LifetimeDef [] (Lifetime "l3" ()) [Lifetime "l1" (), Lifetime "l2" ()] ()] (TraitRef (Path False [debug] ())) ()) None () - , RegionTyParamBound (Lifetime "l2" ()) ()] + (Generics [TypeParam [] (mkIdent "T") [] Nothing ()] (WhereClause [] ()) ()) + [ OutlivesBound (Lifetime "l1" ()) () + , TraitBound (PolyTraitRef [LifetimeParam [] (Lifetime "l3" ()) [OutlivesBound (Lifetime "l1" ()) (), OutlivesBound (Lifetime "l2" ()) ()] ()] (TraitRef (Path False [debug] ())) ()) None () + , OutlivesBound (Lifetime "l2" ()) ()] [] ())) , testFlatten "pub trait Show { fn value(&mut self) -> i32; const pi: i32 = 1; const e: i32; type Size = i32; type Length: 'l3; type SomeType: 'l1 = f64; }" - (printItem (Trait [] PublicV (mkIdent "Show") False Normal (Generics [] [] (WhereClause [] ()) ()) [] + (printItem (Trait [] PublicV (mkIdent "Show") False Normal (Generics [] (WhereClause [] ()) ()) [] [ MethodT [] (mkIdent "value") - (Generics [] [] (WhereClause [] ()) ()) - (MethodSig Normal NotConst Rust - (FnDecl [SelfRegion Nothing Mutable ()] - (Just i32) - False ())) + (Generics [] (WhereClause [] ()) ()) + (MethodSig (FnHeader Normal NotAsync NotConst Rust ()) + (FnDecl [SelfRegion [] Nothing Mutable ()] + (Just i32) + False ())) Nothing () , ConstT [] (mkIdent "pi") i32 (Just _1) () , ConstT [] (mkIdent "e") i32 Nothing () , TypeT [] (mkIdent "Size") [] (Just i32) () - , TypeT [] (mkIdent "Length") [RegionTyParamBound (Lifetime "l3" ()) ()] Nothing () - , TypeT [] (mkIdent "SomeType") [RegionTyParamBound (Lifetime "l1" ()) ()] (Just f64) () + , TypeT [] (mkIdent "Length") [OutlivesBound (Lifetime "l3" ()) ()] Nothing () + , TypeT [] (mkIdent "SomeType") [OutlivesBound (Lifetime "l1" ()) ()] (Just f64) () ] ())) ] --- | Test pretty printing of statements (flattened). +-- | Test pretty printing of statements (flattened). prettyStatements :: Test prettyStatements = testGroup "printing statements" [ testFlatten "#[cfgo] let _;" (printStmt (Local (WildP ()) Nothing Nothing [cfgO] ())) , testFlatten "let _: i32;" (printStmt (Local (WildP ()) (Just i32) Nothing [] ())) , testFlatten "let _: i32 = 1;" (printStmt (Local (WildP ()) (Just i32) (Just _1) [] ())) - , testFlatten "extern crate rustc_serialize;" (printStmt (ItemStmt (ExternCrate [] InheritedV (mkIdent "rustc_serialize") Nothing ()) ())) + , testFlatten "extern crate rustc_serialize;" (printStmt (ItemStmt (ExternCrate [] InheritedV (mkIdent "rustc_serialize") Nothing ()) ())) , testFlatten "if foo { foo = 1 }" (printStmt (NoSemi (If [] foo assBlk Nothing ()) ())) - , testFlatten "{ return 1; }" (printStmt (NoSemi (BlockExpr [] retBlk ()) ())) + , testFlatten "{ return 1; }" (printStmt (NoSemi (BlockExpr [] retBlk Nothing ()) ())) + , testFlatten "'lbl: { return 1; }" (printStmt (NoSemi (BlockExpr [] retBlk (Just (Label "lbl" ())) ()) ())) , testFlatten "foo;" (printStmt (NoSemi foo ())) , testFlatten "1;" (printStmt (NoSemi _1 ())) , testFlatten "if foo { foo = 1 };" (printStmt (Semi (If [] foo assBlk Nothing ()) ())) - , testFlatten "{ return 1; };" (printStmt (Semi (BlockExpr [] retBlk ()) ())) + , testFlatten "{ return 1; };" (printStmt (Semi (BlockExpr [] retBlk Nothing ()) ())) , testFlatten "foo;" (printStmt (Semi foo ())) , testFlatten "1;" (printStmt (Semi _1 ())) , testFlatten "#[cfgo] println!(foo);" (printStmt (MacStmt (Mac (Path False [println] ()) (Stream [ Tree (Token mempty (IdentTok (mkIdent "foo"))) ]) ()) SemicolonMac [cfgO] ())) , testFlatten "println!(foo);" (printStmt (MacStmt (Mac (Path False [println] ()) (Stream [ Tree (Token mempty (IdentTok (mkIdent "foo"))) ]) ()) SemicolonMac [] ())) , testFlatten "println!{ foo }" (printStmt (MacStmt (Mac (Path False [println] ()) (Stream [ Tree (Token mempty (IdentTok (mkIdent "foo"))) ]) ()) BracesMac [] ())) ] - + -- | This tries to make it so that the `Doc` gets rendered onto only one line. testFlatten :: String -> Doc a -> Test testFlatten str doc = testCase (escapeNewlines str) $ str @=? renderShowS (layoutPretty (LayoutOptions Unbounded) (flatten doc)) ""