[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/haskell-tng-mode a6bb27e 061/385: [ci skip] layout algorit
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/haskell-tng-mode a6bb27e 061/385: [ci skip] layout algorithm implemented and tested |
Date: |
Tue, 5 Oct 2021 23:59:02 -0400 (EDT) |
branch: elpa/haskell-tng-mode
commit a6bb27ec2bdefab5ca0b5c82c0e476b439765869
Author: Tseen She <ts33n.sh3@gmail.com>
Commit: Tseen She <ts33n.sh3@gmail.com>
[ci skip] layout algorithm implemented and tested
---
haskell-tng-layout.el | 38 +++++++++---
haskell-tng-smie.el | 25 +++-----
haskell-tng-util.el | 6 ++
test/haskell-tng-layout-test.el | 42 +++++++++++--
test/haskell-tng-smie-test.el | 8 +--
test/src/layout.hs.layout | 19 ++++++
test/src/medley.hs.layout | 133 ++++++++++++++++++++++++++++++++++++++++
7 files changed, 233 insertions(+), 38 deletions(-)
diff --git a/haskell-tng-layout.el b/haskell-tng-layout.el
index f3cf56e..121abd8 100644
--- a/haskell-tng-layout.el
+++ b/haskell-tng-layout.el
@@ -19,16 +19,18 @@
;; Notes on caching
;;
-;; The easiest cache is to parse the entire buffer, invalidated on any change.
+;; Small brain is to parse the entire buffer, invalidated on any change.
;;
-;; A more efficient cache would store a record of the region that has been
-;; edited and reparse only the layouts that have changed. The invalidation may
-;; be a simple case of dismissing everything (including CLOSE parts) after any
-;; point that has been edited or trying to track insertions.
+;; Big brain would store a record of the region that has been edited and
reparse
+;; only the layouts that have changed. The invalidation may be a simple case of
+;; dismissing everything (including CLOSE parts) after any point that has been
+;; edited or trying to track insertions.
;;
;; Galaxy brain caching would use properties and put dirty markers on inserted
;; or deleted regions. Also this could give lightning fast lookup at point on
;; cache hits.
+;;
+;; Anything more complicated that small brain needs improved testing.
(require 'haskell-tng-util)
@@ -37,7 +39,9 @@
;; TODO invalidate the cache on change
-(defun haskell-tng-layout:virtuals-at-point (&optional pos)
+;; TODO a visual debugging option would be great, showing virtuals as overlays
+
+(defun haskell-tng-layout:virtuals-at-point ()
"List of virtual `{' `}' and `;' at point, according to the
Haskell2010 Layout rules.
@@ -45,8 +49,24 @@ Designed to be called repeatedly, managing its own caching."
(unless haskell-tng-layout:cache
(haskell-tng-layout:rebuild-cache-full))
- ;; FIXME lookup in cache
- )
+ (let ((pos (point)))
+ (catch 'done
+ (let (breaks
+ closes)
+ (dolist (block haskell-tng-layout:cache)
+ (let ((open (car block))
+ (close (cadr block))
+ (lines (cddr block)))
+ ;;(message "BLOCK = %S (%s, %s, %s)" block open close lines)
+ (when (and (<= open pos) (<= pos close))
+ (when (= open pos)
+ (throw 'done '("{")))
+ (when (= close pos)
+ (push "}" closes))
+ (dolist (line lines)
+ (when (= line pos)
+ (push ";" breaks))))))
+ (append (reverse closes) (reverse breaks))))))
(defun haskell-tng-layout:rebuild-cache-full ()
(let (case-fold-search
@@ -55,7 +75,7 @@ Designed to be called repeatedly, managing its own caching."
(goto-char 0)
(while (not (eobp))
(when-let (wldo (haskell-tng-layout:next-wldo))
- (push haskell-tng-layout:cache cache))))
+ (push wldo cache))))
(setq haskell-tng-layout:cache (reverse cache))))
(defun haskell-tng-layout:next-wldo ()
diff --git a/haskell-tng-smie.el b/haskell-tng-smie.el
index 3bf4d76..250cb66 100644
--- a/haskell-tng-smie.el
+++ b/haskell-tng-smie.el
@@ -27,16 +27,13 @@
;;; Code:
(require 'smie)
+
(require 'haskell-tng-font-lock)
+(require 'haskell-tng-layout)
;; FIXME: this is all broken, use haskell-tng-layout
-(defvar-local haskell-tng-smie:wldos nil)
-;; State: a list of tokens to return at the current point ending with `t' as an
-;; indicator that all virtual tokens have been processed. `nil' means to
proceed
-;; as normal.
-;;
-;; FIXME cache invalidation
+;; TODO: invalidate this state when the lexer jumps around or the user edits
(defvar-local haskell-tng-smie:multi nil)
;; Function to scan forward for the next token.
@@ -49,17 +46,11 @@
;; https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#SMIE-Lexer
(defun haskell-tng-smie:forward-token ()
(interactive) ;; for testing
- (forward-comment (point-max)) ;; TODO: move to after virtual token generation
- (cond
- ;; TODO: remove this hack
- ((eobp)
- "}")
-
- ;; reading from state
- ((stringp (car haskell-tng-smie:multi))
- (pop haskell-tng-smie:multi))
+ (if (stringp (car haskell-tng-smie:multi))
+ ;; reading from state
+ (pop haskell-tng-smie:multi)
- (t
+ (forward-comment (point-max))
(let ((done-multi (pop haskell-tng-smie:multi))
(case-fold-search nil)
(offside (car haskell-tng-smie:wldos)))
@@ -109,7 +100,7 @@
;; single char
(t
(forward-char)
- (string (char-before)))))))))
+ (string (char-before))))))))
(defun haskell-tng-smie:last-match ()
(goto-char (match-end 0))
diff --git a/haskell-tng-util.el b/haskell-tng-util.el
index 6c1e27e..6b32759 100644
--- a/haskell-tng-util.el
+++ b/haskell-tng-util.el
@@ -11,6 +11,12 @@
(require 'subr-x)
+(defmacro haskell-tng:this-lisp-directory ()
+ (expand-file-name
+ (if load-file-name
+ (file-name-directory load-file-name)
+ default-directory)))
+
(defun haskell-tng:paren-close (&optional pos)
"The next `)', if it closes `POS's paren depth."
(save-excursion
diff --git a/test/haskell-tng-layout-test.el b/test/haskell-tng-layout-test.el
index f29fff6..a4db333 100644
--- a/test/haskell-tng-layout-test.el
+++ b/test/haskell-tng-layout-test.el
@@ -9,11 +9,43 @@
(require 'ert)
(require 's)
-;; FIXME a testing framework for layout
+(defun haskell-tng-layout-test:parse-to-string ()
+ (goto-char 0)
+ (let (tokens)
+ (while (not (eobp))
+ (when-let (virtuals (haskell-tng-layout:virtuals-at-point))
+ (push (s-join "" virtuals) tokens))
+ (push (string (char-after)) tokens)
+ (forward-char))
+ (s-join "" (reverse tokens))))
-;; (ert-deftest haskell-tng-layout-file-tests ()
-;; (should (have-expected-forward-lex "src/medley.hs"))
-;; (should (have-expected-forward-lex "src/layout.hs"))
-;; )
+;; TODO share principle with SMIE (and maybe faceup) tests
+(defun have-expected-layout (file)
+ (let* ((backup-inhibited t)
+ (filename (expand-file-name
+ file
+ (haskell-tng:this-lisp-directory)))
+ (golden (concat filename ".layout"))
+ (expected (with-temp-buffer
+ (insert-file-contents golden)
+ (buffer-string)))
+ (got (with-temp-buffer
+ (insert-file-contents filename)
+ ;; TODO mode should be a parameter
+ (haskell-tng-mode)
+ (haskell-tng-layout-test:parse-to-string))))
+ (or (equal got expected)
+ ;; TODO make this a setting
+ ;; writes out the new version on failure
+ (progn
+ (write-region got nil golden)
+ nil))))
+
+(ert-deftest haskell-tng-layout-file-tests ()
+ ;; the Haskell2010 test case
+ (should (have-expected-layout "src/layout.hs"))
+
+ (should (have-expected-layout "src/medley.hs"))
+ )
;;; haskell-tng-layout-test.el ends here
diff --git a/test/haskell-tng-smie-test.el b/test/haskell-tng-smie-test.el
index 9fb86f8..350da9f 100644
--- a/test/haskell-tng-smie-test.el
+++ b/test/haskell-tng-smie-test.el
@@ -9,12 +9,6 @@
(require 'ert)
(require 's)
-(defmacro haskell-tng-smie:this-lisp-directory ()
- (expand-file-name
- (if load-file-name
- (file-name-directory load-file-name)
- default-directory)))
-
;; copy/pasta of `smie-indent-forward-token' but rendering lexed tokens in a
way
;; more ammenable to regression testing (e.g. syntax table usage)
(defun haskell-tng-smie:indent-forward-token ()
@@ -67,7 +61,7 @@ When called interactively, shows the tokens in a buffer."
(let* ((backup-inhibited t)
(filename (expand-file-name
file
- (haskell-tng-smie:this-lisp-directory)))
+ (haskell-tng:this-lisp-directory)))
(golden (concat filename ".lexer"))
(expected (with-temp-buffer
(insert-file-contents golden)
diff --git a/test/src/layout.hs.layout b/test/src/layout.hs.layout
new file mode 100644
index 0000000..1115f57
--- /dev/null
+++ b/test/src/layout.hs.layout
@@ -0,0 +1,19 @@
+-- Figure 2.1 from the Haskell2010 report
+module AStack( Stack, push, pop, top, size ) where
+{data Stack a = Empty
+ | MkStack a (Stack a)
+
+;push :: a -> Stack a -> Stack a
+;push x s = MkStack x s
+
+;size :: Stack a -> Int
+;size s = length (stkToLst s) where
+ {stkToLst Empty = []
+ ;stkToLst (MkStack x s) = x:xs where {xs = stkToLst s
+
+}};pop :: Stack a -> (a, Stack a)
+;pop (MkStack x s)
+ = (x, case s of {r -> i r where {i x = x}}) -- (pop Empty) is an error
+
+;top :: Stack a -> a
+;top (MkStack x s) = x -- (top Empty) is an error
diff --git a/test/src/medley.hs.layout b/test/src/medley.hs.layout
new file mode 100644
index 0000000..0731662
--- /dev/null
+++ b/test/src/medley.hs.layout
@@ -0,0 +1,133 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+-- | This file is a medley of various constructs and some corner cases
+module Foo.Bar.Main
+ ( Wibble(..), Wobble(Wobb, (!!!)), Woo
+ -- * Operations
+ , getFooByBar, getWibbleByWobble
+ , module Bloo.Foo
+ ) where
+
+{import Control.Applicative (many, optional, pure, (<*>), (<|>))
+;import Data.Foldable (traverse_)
+;import Data.Functor ((<$>))
+;import Data.List (intercalate)
+;import Data.Monoid ((<>))
+;import qualified Options.Monad
+;import qualified Options.Applicative as Opts
+;import qualified Options.Divisible -- wibble (wobble)
+ as Div
+;import qualified ProfFile.App hiding (as, hiding, qualified)
+;import ProfFile.App (as, hiding, qualified)
+;import ProfFile.App hiding (as, hiding, qualified)
+;import qualified ProfFile.App (as, hiding, qualified)
+;import System.Exit (ExitCode (..), exitFailure, qualified,
+ Typey,
+ wibble,
+ Wibble)
+;import System.FilePath (replaceExtension, Foo(Bar, (:<))
+;import System.IO (IOMode (..), hClose, hGetContents,
+ hPutStr, hPutStrLn, openFile, stderr,
+ stdout, MoarTypey)
+;import System.Process (CreateProcess (..), StdStream (..),
+ createProcess, proc, waitForProcess)
+
+-- some chars that should be propertized
+;chars = ['c', '\n', '\'']
+
+;foo = "wobble (wibble)"
+
+;class Get a s where
+ {get :: Set s -> a
+
+};instance {-# OVERLAPS #-} Get a (a ': s) where
+ {get (Ext a _) = a
+
+};instance {-# OVERLAPPABLE #-} Get a s => Get a (b ': s) where
+ {get (Ext _ xs) = get xs
+
+};data Options = Options
+ { optionsReportType :: ReportType
+ , optionsProfFile :: Maybe FilePath
+ , optionsOutputFile :: Maybe FilePath
+ , optionsFlamegraphFlags :: [String]
+ } deriving (Eq, Show)
+
+;class (Eq a) => Ord a where
+ {(<), (<=), (>=), (>) :: a -> a -> Bool
+ ;max @Foo, min :: a -> a -> a
+
+};instance (Eq a) => Eq (Tree a) where
+ {Leaf a == Leaf b = a == b
+ ;(Branch l1 r1) == (Branch l2 r2) = (l1==l2) && (r1==r2)
+ ;_ == _ = False
+
+};data ReportType = Alloc -- ^ Report allocations, percent
+ | Entries -- ^ Report entries, number
+ | Time -- ^ Report time spent in closure, percent
+ | Ticks -- ^ Report ticks, number
+ | Bytes -- ^ Report bytes allocated, number
+ deriving (Eq, Show)
+
+;type family G a where
+ {G Int = Bool
+ ;G a = Char
+
+};data Flobble = Flobble
+ deriving (Eq) via (NonNegative (Large Int))
+ deriving stock (Floo)
+ deriving anyclass (WibblyWoo, OtherlyWoo)
+
+;newtype Flobby = Flobby
+
+;foo ::
+ Wibble -- wibble
+ -> Wobble -- wobble
+ -> Wobble -- wobble
+ -> Wobble -- wobble
+ -> (wob :: Wobble)
+ -> (Wobble -- wobble
+ a b c)
+
+;(foo :: (Wibble Wobble)) foo
+
+;newtype TestApp
+ (logger :: TestLogger)
+ (scribe :: TestScribe)
+ config
+ a
+ = TestApp a
+
+;optionsParser :: Opts.Parser Options
+;optionsParser = Options
+ <$> (Opts.flag' Alloc (Opts.long "alloc" <> Opts.help "wibble")
+ <|> Opts.flag' Entries (Opts.long "entry" <> Opts.help "wobble")
+ <|> Opts.flag' Bytes (Opts.long "bytes" <> Opts.help "i'm a fish"))
+ <*> optional
+ (Opts.strArgument
+ (Opts.metavar "MY-FILE" <>
+ Opts.help "meh"))
+
+;type PhantomThing
+
+;type SomeApi =
+ "thing" :> Capture "bar" Index :> QueryParam "wibble" Text
+ :> QueryParam "wobble" Natural
+ :> Header TracingHeader
TracingId
+ :> ThingHeader
+ :> Get '[JSON] (The ReadResult)
+ :<|> "thing" :> ReqBody '[JSON] Request
+ :> Header TracingHeader TracingId
+ :> SpecialHeader
+ :> Post '[JSON] (The Response)
+
+;deriving instance FromJSONKey StateName
+;deriving anyclass instance FromJSON Base
+;deriving newtype instance FromJSON Treble
+
+;foo = bar
+ where {baz = _
+ -- checking that comments are ignored in layout
+ -- and that a starting syntax entry is ok
+ ;(+) = _
- [nongnu] elpa/haskell-tng-mode 3194e62 074/385: stefan to the rescue, (continued)
- [nongnu] elpa/haskell-tng-mode 3194e62 074/385: stefan to the rescue, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode b690037 081/385: comment-* support, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 502cc26 085/385: document a failure mode, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 08f924c 088/385: simplify the grammar rules, better s-exps, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 71cf945 048/385: lexer test based on Haskell2010, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 4d6bbfc 050/385: feedback from Stefan, improving lexing, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 96609e4 052/385: thoughts on layout inference, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 06b357c 054/385: hacky closing braces, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 64ad4a8 057/385: refactored to centralise state, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 0ac5a2f 059/385: copyright years and move the test assertions, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode a6bb27e 061/385: [ci skip] layout algorithm implemented and tested,
ELPA Syncer <=
- [nongnu] elpa/haskell-tng-mode 7d2863e 065/385: tests for SMIE state invalidation, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 41a29dd 066/385: backward lexer, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode c48e7a5 069/385: starting to transcribe the expression table, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 1f1110a 073/385: transcribe the grammar rules, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 01789b1 075/385: y u no haskell-mode?, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode b8f3e3f 079/385: back out incomplete grammar rules, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 9e19b2b 080/385: double down on simpler grammar, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 6e7a24f 083/385: lexer identifies conid / varid, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode b12e49a 086/385: consym, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 7d6fa3d 091/385: thoughts on lexers, ELPA Syncer, 2021/10/06