[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/haskell-tng-mode 9e19b2b 080/385: double down on simpler g
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/haskell-tng-mode 9e19b2b 080/385: double down on simpler grammar |
Date: |
Tue, 5 Oct 2021 23:59:05 -0400 (EDT) |
branch: elpa/haskell-tng-mode
commit 9e19b2b1e62b3348325d661a1e0e3717da9722df
Author: Tseen She <ts33n.sh3@gmail.com>
Commit: Tseen She <ts33n.sh3@gmail.com>
double down on simpler grammar
---
haskell-tng-smie.el | 96 +++++++++++++++----------------------------
test/haskell-tng-sexp-test.el | 15 +++++--
test/haskell-tng-testutils.el | 8 ++++
test/src/grammar.hs | 7 ++++
test/src/grammar.hs.sexps | 8 ++++
test/src/layout.hs.sexps | 20 ++++-----
6 files changed, 77 insertions(+), 77 deletions(-)
diff --git a/haskell-tng-smie.el b/haskell-tng-smie.el
index a584b2c..55832f6 100644
--- a/haskell-tng-smie.el
+++ b/haskell-tng-smie.el
@@ -25,92 +25,62 @@
;; https://www.gnu.org/software/emacs/manual/html_mono/elisp.html#SMIE-Grammar
;; https://www.haskell.org/onlinereport/haskell2010/haskellch3.html
;;
-;; Transcribed here. Many of these grammar rules cannot be expressed in SMIE
-;; because Haskell uses whitespace separators a lot, whereas the BNF must use
-;; non-terminals.
+;; Many of these grammar rules cannot be expressed in SMIE because Haskell uses
+;; whitespace separators a lot, whereas the BNF must use non-terminals.
;;
-;; exp infixexp :: [context =>] type (expression type signature)
-;; | infixexp
+;; Rules that are unbounded on the right tend to misbehave quite badly, since
+;; there is no way to know how to end the s-expression. For example, the BNF
+;; definition of a TYPE will typically extend to an arbitrary point later in
the
+;; file. We cannot use `;' to end the TYPE definition, because symbols cannot
be
+;; closers and "neither" (i.e. infix) at the same time. An option is always to
+;; push contextual functionality into the lexer, but one must draw a line
+;; somewhere.
;;
-;; infixexp lexp qop infixexp (infix operator application)
-;; | - infixexp (prefix negation)
-;; | lexp
-;;
-;; lexp \ apat1 … apatn -> exp (lambda abstraction, n ≥ 1)
-;; | let decls in exp (let expression)
-;; | if exp [;] then exp [;] else exp (conditional)
-;; | case exp of { alts } (case expression)
-;; | do { stmts } (do expression)
-;; | fexp
-;;
-;; fexp [fexp] aexp (function application)
-;;
-;; aexp qvar (variable)
-;; | gcon (general constructor)
-;; | literal
-;; | ( exp ) (parenthesized expression)
-;; | ( exp1 , … , expk ) (tuple, k ≥ 2)
-;; | [ exp1 , … , expk ] (list, k ≥ 1)
-;; | [ exp1 [, exp2] .. [exp3] ] (arithmetic sequence)
-;; | [ exp | qual1 , … , qualn ] (list comprehension, n ≥ 1)
-;; | ( infixexp qop ) (left section)
-;; | ( qop⟨-⟩ infixexp ) (right section)
-;; | qcon { fbind1 , … , fbindn } (labeled construction, n ≥
0)
-;; | aexp⟨qcon⟩ { fbind1 , … , fbindn } (labeled update, n ≥ 1)
+;; We do not include rules unless they have an impact on indentation.
Navigation
+;; with a more complete grammar has been shown to be less than satisfactory,
+;; therefore there is no reason to do more than is needed.
(defvar haskell-tng-smie:grammar
(smie-prec2->grammar
(smie-bnf->prec2
'((id)
- ;; We do not include rules that do not have an impact on indentation.
- ;; Navigation with the more complete grammar is less than satisfactory,
- ;; therefore there is no reason to maintain it.
- ;; (exp
- ;; (infixexp "::" context "=>" type)
- ;; (infixexp "::" type)
- ;; (infixexp))
- (exp (id))
-
- ;; TODO => and -> may require custom indentation rules
-
- ;; FIXME don't give up hope yet, first see if exp is useful when type is
- ;; defined properly.
+ ;; commas only allowed in brackets
(context
("(" context ")")
(context "," context))
- ;; ;; TODO the lexer should provide virtual infix operators
- ;; (infixexp
- ;; (lexp "$" infixexp)
- ;; (lexp))
+ ;; operators
+ ;; TODO lexer should identify / normalise operators.
+ (infixexp
+ (id "$" infixexp)
+ (id "*" infixexp)
+ (id "+" infixexp)
+ (id))
- (lexp
- ("if" exp "then" exp "else" exp)
+ ;; WLDOs
+ (wldo
("where" decls)
- ("let" decls "in" exp)
+ ("let" decls)
("do" stmts)
- ("case" exp "of" alts))
-
+ ("of" alts))
(decls
("{" decls "}")
(decls ";" decls)
- (id "=" exp))
- (alts
- ("{" alts "}")
- (alts ";" alts)
- (id "->" exp))
+ (id "=" id))
(stmts
("{" stmts "}")
(stmts ";" stmts)
- (id "<-" exp))
+ (id "<-" id))
+ (alts
+ ("{" alts "}")
+ (alts ";" alts)
+ (id "->" id))
+
)
;; operator precedences
- '(;;(left ";" "," "::" "else" "in" "of" "->" "do" "<-" "where" "=")
- ;;(left ";" ",")
- (assoc ",") ;; TODO , and ; conflict but what's the correct ordering?
- (assoc ";")
-;; (left "$")
+ '((assoc ";")
+ (assoc ",")
)
)))
diff --git a/test/haskell-tng-sexp-test.el b/test/haskell-tng-sexp-test.el
index d0abd96..e263d77 100644
--- a/test/haskell-tng-sexp-test.el
+++ b/test/haskell-tng-sexp-test.el
@@ -21,9 +21,12 @@
;; tokens.
(ert-deftest haskell-tng-sexp-file-tests ()
- ;; the baselines have some pretty funky stuff in them...
+ ;; some bizarre output here:
+ ;; 1. `size' definition has an s-exp that extends to the end of `top'
(should (have-expected-sexps (testdata "src/layout.hs")))
+ (should (have-expected-sexps (testdata "src/grammar.hs")))
+
;; to the extent that they aren't even useful
;;(should (have-expected-sexps (testdata "src/medley.hs")))
)
@@ -70,8 +73,9 @@
(goto-char (point-min))
(let (sexps)
(while (not (eobp))
- (let ((here (haskell-tng-sexp-test:sexps-at-point (point))))
- (setq sexps (append here sexps)))
+ (unless (is-comment-at-point)
+ (let ((here (haskell-tng-sexp-test:sexps-at-point (point))))
+ (setq sexps (append here sexps))))
(forward-char))
(delete-dups sexps)))
@@ -88,7 +92,10 @@
(t nil)))
(if (eobp)
(setq exit 't)
- (push (string (char-after)) chars)
+ (let ((c (string (char-after))))
+ ;; output is cleaner if we don't double print parens
+ (unless (member c '("(" ")"))
+ (push c chars)))
(forward-char)))
(s-join "" (reverse chars))))
diff --git a/test/haskell-tng-testutils.el b/test/haskell-tng-testutils.el
index 32713f1..e2546b5 100644
--- a/test/haskell-tng-testutils.el
+++ b/test/haskell-tng-testutils.el
@@ -40,5 +40,13 @@ Will fail and write out the expected version to FILE.SUFFIX."
file
(haskell-tng-testutils:this-lisp-directory)))
+(defun is-comment-at-point ()
+ ;; this could be sped up by storing all comment regions in an alist
+ (or (nth 8 (syntax-ppss))
+ (looking-at "--")
+ (and (looking-at "-")
+ (looking-back "-" 1)))
+ )
+
(provide 'haskell-tng-testutils)
;;; haskell-tng-testutils.el ends here
diff --git a/test/src/grammar.hs b/test/src/grammar.hs
new file mode 100644
index 0000000..4631ea2
--- /dev/null
+++ b/test/src/grammar.hs
@@ -0,0 +1,7 @@
+-- | Tests for grammar rules (i.e. sexps, not indentation)
+module Foo.Bar where
+
+calc :: Int -> Int
+calc a = if a < 10
+ then a + a * a + a
+ else (a + a) * (a + a)
diff --git a/test/src/grammar.hs.sexps b/test/src/grammar.hs.sexps
new file mode 100644
index 0000000..2e8f24b
--- /dev/null
+++ b/test/src/grammar.hs.sexps
@@ -0,0 +1,8 @@
+-- | Tests for grammar rules i.e. sexps, not indentation
+(module) (Foo.Bar) (where
+
+(((calc) (::) (Int) (->) (Int))
+((calc) (a) = (if) (a) (<) (10)
+ (then) (a) + (a) * (a) + (a)
+ (else) ((a) + (a)) * ((a) + (a)))
+))
\ No newline at end of file
diff --git a/test/src/layout.hs.sexps b/test/src/layout.hs.sexps
index 4106a8f..4519f81 100644
--- a/test/src/layout.hs.sexps
+++ b/test/src/layout.hs.sexps
@@ -1,20 +1,20 @@
-((--) (Figure) (2.1) (from) (the) (Haskell2010) (report)
-(module)) (AStack)(( (Stack), (push), (pop), (top), (size) )) (where
+-- Figure 2.1 from the Haskell2010 report
+(module) (AStack)( (Stack), (push), (pop), (top), (size) ) (where
((data) (Stack) (a) = (Empty)
- (|) (MkStack) (a) (((Stack) (a)))
+ (|) (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
+((size) (s) = (length) ((stkToLst) (s)) (where
((stkToLst) (Empty) = ([])
- ((stkToLst) (((MkStack) (x) (s))) = (x:xs) (where ((xs) =
(stkToLst) (s)
+ ((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)
+))))((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)
+(((top) (::) (Stack) (a) (->) (a)))
+((top) ((MkStack) (x) (s)) = (x)))) -- top Empty is an
error
))
\ No newline at end of file
- [nongnu] elpa/haskell-tng-mode 06b357c 054/385: hacky closing braces, (continued)
- [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, 2021/10/06
- [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 <=
- [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
- [nongnu] elpa/haskell-tng-mode 6a05d12 090/385: planning for indentation, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 2060f7a 092/385: thoughts on indentation testing, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 6d2d764 094/385: skeleton for indentation tests, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 0d04664 115/385: implement batch compilation, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode adb3c50 143/385: better insert indentation suggestions, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode e79577e 132/385: match ghc source paths when compiling, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 8ec4807 145/385: somehow dropped font-lock-extend-region-multiline, ELPA Syncer, 2021/10/06