emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/haskell-tng-mode a4a664b 056/385: layout inference


From: ELPA Syncer
Subject: [nongnu] elpa/haskell-tng-mode a4a664b 056/385: layout inference
Date: Tue, 5 Oct 2021 23:59:01 -0400 (EDT)

branch: elpa/haskell-tng-mode
commit a4a664b1c54cec53b50b16a49ad5eb8dd93926f6
Author: Tseen She <ts33n.sh3@gmail.com>
Commit: Tseen She <ts33n.sh3@gmail.com>

    layout inference
---
 haskell-tng-smie.el           | 172 ++++++++++++++++++------------------------
 haskell-tng-util.el           |  17 +----
 test/faces/medley.hs          |   2 +-
 test/faces/medley.hs.faceup   |   2 +-
 test/faces/medley.hs.lexer    |  85 ++++++++++-----------
 test/haskell-tng-smie-test.el |   2 +-
 6 files changed, 120 insertions(+), 160 deletions(-)

diff --git a/haskell-tng-smie.el b/haskell-tng-smie.el
index 037f6c1..addeff0 100644
--- a/haskell-tng-smie.el
+++ b/haskell-tng-smie.el
@@ -29,20 +29,18 @@
 (require 'smie)
 (require 'haskell-tng-font-lock)
 
-;; FIXME: the "massive hack"s only work for a full forward parse of a file. If
-;; these hacks can't be removed it may be the death of SMIE, and we'll need a
-;; custom s-expression parser and indentation engine.
+;; FIXME: massive hack. Holds an ordered list of (position . level) that close
+;; an inferred layout block. This could be turned into a (cached) function call
+;; plus some state in wldo-state.
+(defvar-local haskell-tng-smie:wldos nil)
+
+;; FIXME: massive hack. State of previous lexeme. Unsure how to remove this.
+;; Ideally we would be able to return multiple tokens to SMIE and we wouldn't
+;; need this.
 ;;
-;; Maybe we could create state for a block of code (maybe top-level), hashed by
-;; the content. Then context-less forward/backward-token requests would always
-;; be able to consult the state without having to update it.
-
-;; FIXME: massive hack. Holds an ordered list of positions that close an
-;; inferred layout block.
-(defvar haskell-tng-smie:wldos nil)
-
-;; FIXME: massive hack. t if the previous lexeme was a WLDO
-(defvar haskell-tng-smie:wldo nil)
+;; TODO: refactor so this stores the list of tokens to return at the current
+;; point, and some information allowing cache invalidation.
+(defvar-local haskell-tng-smie:wldo-state nil)
 
 ;; Function to scan forward for the next token.
 ;;
@@ -54,100 +52,74 @@
 ;; https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#SMIE-Lexer
 (defun haskell-tng-smie:forward-token ()
   (interactive) ;; for testing
-  (let ((start (point))
-        (wldo haskell-tng-smie:wldo))
-    (setq haskell-tng-smie:wldo nil)
+  (forward-comment (point-max))
+  (if (eobp)
+      "}"
+    (let ((case-fold-search nil)
+          (syntax (char-syntax (char-after)))
+          (wldo-state haskell-tng-smie:wldo-state)
+          (offside (car haskell-tng-smie:wldos)))
+      (setq haskell-tng-smie:wldo-state nil)
+      (cond
+       ;; layout
+       ((and (eq wldo-state 'start) (not (looking-at "{")))
+        (push (haskell-tng:layout-close-and-level) haskell-tng-smie:wldos)
+        (setq haskell-tng-smie:wldo-state 'middle)
+        "{")
+       ((when-let (close (car offside))
+          (= (point) close))
+        (pop haskell-tng-smie:wldos)
+        "}")
+       ((when-let (level (cdr offside))
+          (and
+           (= (current-column) level)
+           (not (eq wldo-state 'middle))))
+        (setq haskell-tng-smie:wldo-state 'middle)
+        ";")
+
+       ;; parens
+       ((member syntax '(?\( ?\) ?\" ?$)) nil)
+
+       ;; layout detection
+       ((looking-at (rx word-start (| "where" "let" "do" "of") word-end))
+        (setq haskell-tng-smie:wldo-state 'start)
+        (haskell-tng-smie:last-match))
+
+       ;; regexps
+       ((or
+         ;; known identifiers
+         (looking-at haskell-tng:regexp:reserved)
+         ;; symbols
+         (looking-at (rx (+ (| (syntax word) (syntax symbol)))))
+         ;; whatever the current syntax class is
+         (looking-at (rx-to-string `(+ (syntax ,syntax)))))
+        (haskell-tng-smie:last-match))))))
+
+(defun haskell-tng:layout-of-next-token ()
+  (save-excursion
     (forward-comment (point-max))
-    (unless (eobp)
-      (let ((start-line (line-number-at-pos start))
-            (this-line (line-number-at-pos))
-            (case-fold-search nil)
-            (syntax (char-syntax (char-after))))
-        (cond
-         ;; layout of wldo blocks: braces
-         ;;
-         ;; Starting braces can be detected with a lookback when we hit a non-{
-         ;; lexeme following a WLDO. Ending braces are a lot harder, as we need
-         ;; to calculate "do we need to close a brace here" every time the
-         ;; indentation level decreases.
-         ;;
-         ;; A hacky solution is to calculate and cache the closing brace when
-         ;; discovering an open brace, but that just introduces more problems.
-         ((and wldo (not (looking-at "{")))
-          (let ((close (haskell-tng:layout-close)))
-            (message "WLDO opened at %s setting level to %s, closing at %s"
-                     start (current-column) close)
-            (push close haskell-tng-smie:wldos))
-          "{")
-         ((when-let (close (car haskell-tng-smie:wldos))
-            (>= (point) close))
-          (message "WLDO closed at %s" (point))
-          (pop haskell-tng-smie:wldos)
-          "}")
-
-         ;; TODO should only trigger inside a WLDO block
-         ;; layout of wldo blocks: semicolons
-         ((not (eq start-line this-line))
-          (let ((start-layout (haskell-tng-smie:layout-level start-line))
-                (this-layout (current-indentation)))
-            ;;(message "LAYOUT %s %s" start-layout this-layout)
-            (cond
-             ((null start-layout) "")
-             ;;((eq start-layout this-layout) ";")
-             (t ""))))
-
-         ;; parens
-         ((member syntax '(?\( ?\) ?\" ?$)) nil)
-
-         ;; layout, wldo detection
-         ((looking-at (rx word-start (| "where" "let" "do" "of") word-end))
-          (message "WLDO is at %s" (point))
-          (setq haskell-tng-smie:wldo t)
-          (haskell-tng-smie:last-match))
-
-         ;; regexps
-         ((or
-           ;; known identifiers
-           (looking-at haskell-tng:regexp:reserved)
-           ;; symbols
-           (looking-at (rx (+ (| (syntax word) (syntax symbol)))))
-           ;; whatever the current syntax class is
-           (looking-at (rx-to-string `(+ (syntax ,syntax)))))
-          (haskell-tng-smie:last-match)))))))
-
-(defun haskell-tng-smie:looking-back-wldo (p)
-  "t if the previous token before point P is `where', `let', `do' or `of'."
-  ;; FIXME this is really hacky, it tries to reparse the last token. We should
-  ;; doing a backwards token parse to take comments into account, or at least
-  ;; caching the previous token.
+    (current-column)))
+
+(defun haskell-tng:layout-close-and-level (&optional pos)
+  "A cons cell of the closing point for the layout beginning at POS, and 
level."
   (save-excursion
-    (goto-char p)
-    (let ((hit (looking-back
-                (rx word-start (| "where" "let" "do" "of") word-end point)
-                nil
-                ;;(- p 5)
-                )))
-      (message "WLDO is %s at `...%s'" hit (buffer-substring-no-properties (- 
p 5) p))
-      hit)))
+    (goto-char (or pos (point)))
+    (let ((level (current-column))
+          (close (or (haskell-tng:paren-close) (point-max))))
+      (catch 'closed
+        (while (not (eobp))
+          (forward-line)
+          (forward-comment (point-max))
+          (when (< close (point))
+            (throw 'closed (cons close level)))
+          (when (< (current-column) level)
+            (throw 'closed (cons (point) level))))
+        (cons (point-max) level)))))
 
 (defun haskell-tng-smie:last-match ()
   (goto-char (match-end 0))
   (match-string-no-properties 0))
 
-(defun haskell-tng-smie:layout-level (line)
-  "Calculates the layout indentation at the end of the given line."
-
-  ;; TODO starting at the end of the line, look backwards for wldo (where, 
let, do, of).
-  ;; If the wldo is the last lexeme, then the layout level is set by the next 
line (return nil).
-  ;; If the wldo is followed by a non-brace lexeme, set the layout level.
-  ;;
-  ;; If there is no wldo, the layout level is set by the indentation level
-  ;; (think about this some more)
-  (save-excursion
-    (forward-line (- line (line-number-at-pos)))
-    ;; now at start of line
-    (current-indentation)))
-
 ;; TODO a haskell grammar
 ;; https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#SMIE-Grammar
 (defvar haskell-tng-smie:grammar
diff --git a/haskell-tng-util.el b/haskell-tng-util.el
index 9f90b00..d7cca01 100644
--- a/haskell-tng-util.el
+++ b/haskell-tng-util.el
@@ -20,7 +20,8 @@
       (when (looking-at ")")
         (point)))))
 
-;; FIXME comment aware
+;; TODO comment / paren aware, like haskell-tng:layout-of-next-token
+;; TODO refactor to share code with haskell-tng:layout-of-next-token
 (defun haskell-tng:indent-close (&optional pos)
   "The beginning of the line with indentation that closes `POS'."
   (save-excursion
@@ -32,20 +33,6 @@
             (throw 'closed (point))))
         nil))))
 
-;; FIXME comment aware
-;; TODO share with haskell-tng:indent-close?
-(defun haskell-tng:layout-close (&optional pos)
-  "The point with indentation that closes `POS'."
-  (save-excursion
-    (goto-char (or pos (point)))
-    (let ((level (current-column)))
-      (catch 'closed
-        (while (and (forward-line) (not (eobp)))
-          (when (< (current-indentation) level)
-            (forward-char (current-indentation))
-            (throw 'closed (point))))
-        nil))))
-
 (defun haskell-tng:indent-close-previous ()
   "Indentation closing the previous symbol."
   (save-excursion
diff --git a/test/faces/medley.hs b/test/faces/medley.hs
index 5b950e5..f182758 100644
--- a/test/faces/medley.hs
+++ b/test/faces/medley.hs
@@ -34,7 +34,7 @@ import           System.Process      (CreateProcess (..), 
StdStream (..),
                                       createProcess, proc, waitForProcess)
 
 -- some chars that should be propertized
-'c' '\n' '\''
+chars = ['c', '\n', '\'']
 
 foo = "wobble (wibble)"
 
diff --git a/test/faces/medley.hs.faceup b/test/faces/medley.hs.faceup
index 822121c..2f33e9a 100644
--- a/test/faces/medley.hs.faceup
+++ b/test/faces/medley.hs.faceup
@@ -34,7 +34,7 @@
                                       createProcess«:haskell-tng:keyword:,» 
proc«:haskell-tng:keyword:,» waitForProcess«:haskell-tng:keyword:)»
 
 «x:-- some chars that should be propertized
-»«s:'c'» «s:'\n'» «s:'\''»
+»«:haskell-tng:toplevel:chars» «:haskell-tng:keyword:=» 
«:haskell-tng:keyword:[»«s:'c'»«:haskell-tng:keyword:,» 
«s:'\n'»«:haskell-tng:keyword:,» «s:'\''»«:haskell-tng:keyword:]»
 
 «:haskell-tng:toplevel:foo» «:haskell-tng:keyword:=» «s:"wobble (wibble)"»
 
diff --git a/test/faces/medley.hs.lexer b/test/faces/medley.hs.lexer
index 42da296..89748ba 100644
--- a/test/faces/medley.hs.lexer
+++ b/test/faces/medley.hs.lexer
@@ -10,78 +10,78 @@ _( Wibble _( .. _) , Wobble _( Wobb , _( !!! _) _) , Woo
 _) 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
+; 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
 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 ,
+; 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 ,
+; import System.FilePath _( replaceExtension , Foo _( Bar , _( :< _) _)
+; import System.IO _( IOMode _( .. _) , hClose , hGetContents ,
 hPutStr , hPutStrLn , openFile , stderr ,
 stdout , MoarTypey _)
-import System.Process _( CreateProcess _( .. _) , StdStream _( .. _) ,
+; import System.Process _( CreateProcess _( .. _) , StdStream _( .. _) ,
 createProcess , proc , waitForProcess _)
 
 
-_'c' _'\n' _'\''
+; chars = _[ _'c' , _'\n' , _'\'' _]
 
-foo = _"wobble (wibble)"
+; foo = _"wobble (wibble)"
 
-class Get a s where
+; class Get a s where
 { get :: Set s -> a
 
-} instance Get a _( a ': s _) where
+} ; instance Get a _( a ': s _) where
 { get _( Ext a _ _) = a
 
-} instance Get a s => Get a _( b ': s _) where
+} ; instance Get a s => Get a _( b ': s _) where
 { get _( Ext _ xs _) = get xs
 
-} data Options = Options
+} ; 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
+; class _( Eq a _) => Ord a where
+{ _; < _) , _( <= _) , _( >= _) , _( > _) :: a -> a -> Bool
+; max @Foo , min :: a -> a -> a
 
-} instance _( Eq a _) => Eq _( Tree a _) where
+} ; instance _( Eq a _) => Eq _( Tree a _) where
 { Leaf a == Leaf b = a == b
-_( Branch l1 r1 _) == _( Branch l2 r2 _) = _( l1==l2 _) && _( r1==r2 _)
-_ == _ = False
+; _; Branch l1 r1 _) == _( Branch l2 r2 _) = _( l1==l2 _) && _( r1==r2 _)
+; _ == _ = False
 
-} data ReportType = Alloc
+} ; data ReportType = Alloc
 | Entries
 | Time
 | Ticks
 | Bytes
 deriving _( Eq , Show _)
 
-type family G a where
+; type family G a where
 { G Int = Bool
-G a = Char
+; G a = Char
 
-} data Flobble = Flobble
+} ; data Flobble = Flobble
 deriving _( Eq _) via _( NonNegative _( Large Int _) _)
 deriving stock _( Floo _)
 deriving anyclass _( WibblyWoo , OtherlyWoo _)
 
-newtype Flobby = Flobby
+; newtype Flobby = Flobby
 
-foo ::
+; foo ::
 Wibble
 -> Wobble
 -> Wobble
@@ -90,17 +90,17 @@ Wibble
 -> _( Wobble
 a b c _)
 
-_( foo :: _( Wibble Wobble _) _) foo
+; _; foo :: _( Wibble Wobble _) _) foo
 
-newtype TestApp
+; newtype TestApp
 _( logger :: TestLogger _)
 _( scribe :: TestScribe _)
 config
 a
 = TestApp a
 
-optionsParser :: Opts.Parser Options
-optionsParser = Options
+; 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" _) _)
@@ -109,9 +109,9 @@ _( Opts.strArgument
 _( Opts.metavar _"MY-FILE" <>
 Opts.help _"meh" _) _)
 
-type PhantomThing
+; type PhantomThing
 
-type SomeApi =
+; type SomeApi =
 _"thing" :> Capture _"bar" Index :> QueryParam _"wibble" Text
 :> QueryParam _"wobble" Natural
 :> Header TracingHeader TracingId
@@ -122,6 +122,7 @@ _"thing" :> Capture _"bar" Index :> QueryParam _"wibble" 
Text
 :> SpecialHeader
 :> Post ' _[ JSON _] _( The Response _)
 
-deriving instance FromJSONKey StateName
-deriving anyclass instance FromJSON Base
-deriving newtype instance FromJSON Treble
+; deriving instance FromJSONKey StateName
+; deriving anyclass instance FromJSON Base
+; deriving newtype instance FromJSON Treble
+}
diff --git a/test/haskell-tng-smie-test.el b/test/haskell-tng-smie-test.el
index b2cd085..82755b1 100644
--- a/test/haskell-tng-smie-test.el
+++ b/test/haskell-tng-smie-test.el
@@ -46,7 +46,7 @@ When called interactively, shows the tokens in a buffer."
         ordered))))
 
 (defun haskell-tng-smie:tokens-to-string (lines)
-  (s-join "\n" (--map (s-join " " it) lines)))
+  (concat (s-join "\n" (--map (s-join " " it) lines)) "\n"))
 
 (defun haskell-tng-smie:display-tokens (lines)
   (with-current-buffer (get-buffer-create "*Haskell-TNG-SMIE-test*")



reply via email to

[Prev in Thread] Current Thread [Next in Thread]