[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/haskell-tng-mode a5f779d 047/385: initial SMIE tests
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/haskell-tng-mode a5f779d 047/385: initial SMIE tests |
Date: |
Tue, 5 Oct 2021 23:58:59 -0400 (EDT) |
branch: elpa/haskell-tng-mode
commit a5f779dc32fc7757f39c0af7af3735d552fc52a4
Author: Tseen She <ts33n.sh3@gmail.com>
Commit: Tseen She <ts33n.sh3@gmail.com>
initial SMIE tests
---
haskell-tng-font-lock.el | 2 +-
haskell-tng-mode.el | 5 +-
haskell-tng-smie.el | 87 +++--
test/faces/medley.hs.forward | 736 ++++++++++++++++++++++++++++++++++++++++++
test/haskell-tng-smie-test.el | 69 ++--
5 files changed, 856 insertions(+), 43 deletions(-)
diff --git a/haskell-tng-font-lock.el b/haskell-tng-font-lock.el
index d3ca587..d4daea4 100644
--- a/haskell-tng-font-lock.el
+++ b/haskell-tng-font-lock.el
@@ -87,7 +87,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Here is the `font-lock-keywords' table of matchers and highlighters.
-(setq
+(defvar
haskell-tng:keywords
;; These regexps use the `rx' library so we can reuse common subpatterns. It
;; also increases the readability of the code and, in many cases, allows us to
diff --git a/haskell-tng-mode.el b/haskell-tng-mode.el
index 275eb1c..23a14b5 100644
--- a/haskell-tng-mode.el
+++ b/haskell-tng-mode.el
@@ -15,8 +15,10 @@
;;; Code:
(require 'dabbrev)
+
(require 'haskell-tng-syntax)
(require 'haskell-tng-font-lock)
+(require 'haskell-tng-smie)
;;;###autoload
(define-derived-mode haskell-tng-mode prog-mode "Hask"
@@ -52,7 +54,8 @@
;; whitespace is meaningful, no electric indentation
electric-indent-inhibit t)
- )
+
+ (haskell-tng-smie:setup))
(defcustom haskell-tng-mode-hook nil
"List of functions to run after `haskell-tng-mode' is enabled."
diff --git a/haskell-tng-smie.el b/haskell-tng-smie.el
index 436b17a..c08b252 100644
--- a/haskell-tng-smie.el
+++ b/haskell-tng-smie.el
@@ -8,34 +8,77 @@
;; SMIE lexer, precedence table (providing s-expression navigation), and
;; indentation rules.
;;
+;; Note that we don't need to support every aspect of the Haskell language in
+;; these grammar rules: only the parts that are relevant for the features that
+;; are provided.
+;;
+;; If we had access to all the operators in scope, and their fixity, we could
+;; create file-specific precendences. However, the complexity-to-benefit
payoff
+;; is minimal.
+;;
+;; Users may consult the SMIE manual to customise their indentation rules:
;; https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#SMIE
;;
;;; Code:
(require 'smie)
- ;; (defvar sample-keywords-regexp
- ;; (regexp-opt '("+" "*" "," ";" ">" ">=" "<" "<=" ":=" "=")))
- ;; (defun sample-smie-forward-token ()
- ;; (forward-comment (point-max))
- ;; (cond
- ;; ((looking-at sample-keywords-regexp)
- ;; (goto-char (match-end 0))
- ;; (match-string-no-properties 0))
- ;; (t (buffer-substring-no-properties
- ;; (point)
- ;; (progn (skip-syntax-forward "w_")
- ;; (point))))))
- ;; (defun sample-smie-backward-token ()
- ;; (forward-comment (- (point)))
- ;; (cond
- ;; ((looking-back sample-keywords-regexp (- (point) 2) t)
- ;; (goto-char (match-beginning 0))
- ;; (match-string-no-properties 0))
- ;; (t (buffer-substring-no-properties
- ;; (point)
- ;; (progn (skip-syntax-backward "w_")
- ;; (point))))))
+(defvar haskell-tng-smie:keywords
+ (regexp-opt '("+" "*" "=")))
+
+;; TODO custom Haskell lexer
+;; TODO convert significant whitespace to semicolons
+;;
+;; Function to scan forward for the next token.
+;; - Called with no argument should return a token and move to its end.
+;; - If no token is found, return nil or the empty string.
+;; - It can return nil when bumping into a parenthesis, which lets SMIE
+;; - use syntax-tables to handle them in efficient C code.
+;;
+;; 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))
+ (cond
+ ((looking-at haskell-tng-smie:keywords)
+ (goto-char (match-end 0))
+ (match-string-no-properties 0))
+ (t (buffer-substring-no-properties
+ (point)
+ (progn (skip-syntax-forward "w_")
+ (point))))))
+
+;; TODO a haskell grammar
+;; https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#SMIE-Grammar
+(defvar haskell-tng-smie:grammar
+ (smie-prec2->grammar
+ (smie-bnf->prec2
+ '((id)
+ (inst ("if" exp "then" inst "else" inst)
+ (id "<-" exp)
+ (id "=" exp)
+ (exp))
+ (insts (insts ";" insts) (inst))
+ (exp (exp "+" exp)
+ (exp "*" exp)
+ ("(" exps ")")
+ ("{" exps "}"))
+ (exps (exps "," exps) (exp)))
+ '((assoc ";"))
+ '((assoc ","))
+ '((assoc "+") (assoc "*")))))
+
+;; TODO indentation rules
+;;
https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#SMIE-Indentation
+(defvar haskell-tng-smie:rules nil)
+
+(defun haskell-tng-smie:setup ()
+ (smie-setup
+ haskell-tng-smie:grammar
+ haskell-tng-smie:rules
+ :forward-token #'haskell-tng-smie:forward-token
+ ;; TODO :backward-token #'haskell-tng-smie:backward-token
+ ))
(provide 'haskell-tng-smie)
;;; haskell-tng-smie.el ends here
diff --git a/test/faces/medley.hs.forward b/test/faces/medley.hs.forward
new file mode 100644
index 0000000..e784f41
--- /dev/null
+++ b/test/faces/medley.hs.forward
@@ -0,0 +1,736 @@
+module
+Foo.Bar.Main
+
+(
+Wibble
+(
+..
+)
+,
+Wobble
+(
+Wobb
+,
+
+(
+!!!
+)
+)
+,
+Woo
+
+,
+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
+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
+)
+
+'
+c
+'
+
+'
+\
+n
+'
+
+'
+\
+'
+'
+foo
+=
+
+"
+wobble
+
+(
+wibble
+)
+"
+class
+Get
+a
+s
+where
+get
+::
+Set
+s
+->
+a
+instance
+Get
+a
+
+(
+a
+':
+s
+)
+where
+get
+
+(
+Ext
+a
+_
+)
+=
+a
+instance
+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
+|
+Entries
+|
+Time
+|
+Ticks
+|
+Bytes
+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
+->
+Wobble
+->
+Wobble
+->
+Wobble
+->
+
+(
+wob
+::
+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
+
diff --git a/test/haskell-tng-smie-test.el b/test/haskell-tng-smie-test.el
index 2905484..f5253f6 100644
--- a/test/haskell-tng-smie-test.el
+++ b/test/haskell-tng-smie-test.el
@@ -6,32 +6,63 @@
(require 'haskell-tng-mode)
(require 'ert)
-(require 'faceup)
+(require 's)
-(defun haskell-tng-smie:lex-forward-buffer ()
+(defmacro haskell-tng-smie:this-lisp-directory ()
+ (expand-file-name
+ (if load-file-name
+ (file-name-directory load-file-name)
+ default-directory)))
+
+(defvar smie-forward-token-function)
+;; TODO make this behave consistently interactive / non-interactive
+;; (maybe wrap it)
+(defun haskell-tng-smie:forward-token-to-buffer ()
+ "Forward lex the current buffer using SMIE lexer and dump to a buffer."
+ (interactive)
(let* ((buf (current-buffer))
- (work (switch-to-buffer (concat (buffer-file-name)
".lexer.forward"))))
- (switch-to-buffer buf)
+ (work (generate-new-buffer (buffer-name))))
(goto-char (point-min))
+ (while (not (eobp))
+ (let* ((start (point))
+ (token (apply smie-forward-token-function ())))
+ (when (= (point) start)
+ (unless (or (s-present? token) (eobp))
+ (setq token (char-to-string (char-after (point)))))
+ (forward-char))
+ (with-current-buffer work
+ (insert token "\n"))))
+ (if (called-interactively-p 'interactive)
+ (switch-to-buffer work)
+ work)))
- ;; FIXME progress through the buf writing the returned values to work
- ;; maybe with a character to indicate invocations, maybe newlines.
-
- ))
-
-(defun have-expected-forward-lexer (file)
- (let* ((filename (expand-file-name
+(defun have-expected-forward-lex (file)
+ (let* ((backup-inhibited t)
+ (filename (expand-file-name
file
- (eval-when-compile (faceup-this-file-directory))))
- (golden (concat filename ".lexer.forward")))
-
- ;; FIXME run the lex-forward-buffer and compare the result with the version
- ;; on disk, perhaps a trimmed diff.
-
- ))
+ (haskell-tng-smie:this-lisp-directory)))
+ (golden (concat filename ".forward"))
+ (expected (with-temp-buffer
+ (insert-file-contents golden)
+ (buffer-string)))
+ (lexed (with-temp-buffer
+ ;; TODO load this buffer correctly, to id the mode
+ (haskell-tng-mode)
+ (insert-file-contents filename)
+ (haskell-tng-smie:forward-token-to-buffer)))
+ (got (with-current-buffer lexed (buffer-string))))
+ (unwind-protect
+ (or (s-equals? got expected)
+ ;; TODO make this a parameter
+ ;; writes out the new version on failure
+ (progn
+ (with-current-buffer lexed
+ (write-file golden))
+ nil))
+ (kill-buffer lexed))))
(ert-deftest haskell-tng-smie-file-tests ()
- (should (have-expected-forward-lexer "faces/medley.hs")))
+ (should (have-expected-forward-lex "faces/medley.hs")))
;; ideas for an indentation tester
;;
https://github.com/elixir-editors/emacs-elixir/blob/master/test/test-helper.el#L52-L63
- [nongnu] elpa/haskell-tng-mode f342041 118/385: better SMIE blinkers, (continued)
- [nongnu] elpa/haskell-tng-mode f342041 118/385: better SMIE blinkers, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 249f507 121/385: support whitespace gaps, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 6ae08ec 021/385: fixup! multiline topdecl type sections, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode a808c7b 033/385: notes on language extensions, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode a4ec07a 032/385: fix install instructions, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 3e8efdc 023/385: type aliases and deriving, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode ad570a0 039/385: out of date comments, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 7326aad 041/385: modules and more efficient none, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 49611c6 042/385: regression tests for fontification, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode c22f7d2 045/385: thoughts on future plans, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode a5f779d 047/385: initial SMIE tests,
ELPA Syncer <=
- [nongnu] elpa/haskell-tng-mode dae43ac 049/385: improvements to the default lexer, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode d76c6ad 053/385: some thoughts on WLDO detection, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 3e53f56 055/385: cleaner lexer test output, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 73e2b11 063/385: the new lexer works!, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 8e1a225 068/385: sexp tests, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 269be91 072/385: revert broken grammar rules, ELPA Syncer, 2021/10/06
- [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