* first steps in elisp
@ 2016-11-24 23:00 Mark Piffer
2016-11-25 5:39 ` Marcin Borkowski
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Mark Piffer @ 2016-11-24 23:00 UTC (permalink / raw)
To: help-gnu-emacs
I am trying to write some helper functions which should ease documentation of C as per the method which my customers require (mostly repetition of parameters as Doxygen-enabled comments - I don't think that that's a good idea, but the customer wants it). I coudn't find a package that was primitive enough to help me with the parsing - the code is embedded C and quite non-standard with respect to compiler extensions. So I tried to walk the extra mile and code a little elisp for fun. Which things are especially bad or unusual concerning both, Lisp and emacs?
(defun ignore-multiline-comment (nlines)
"assumes point is inside a C multiline comment /*. Advances
until end of comment */ or nlines becomes 0"
(if (zerop nlines)
nil
(if (looking-at ".*?\\*/")
(progn
(goto-char (match-end 0))
(ignore-line-comments nlines))
(beginning-of-line 2)
(ignore-multiline-comment (1- nlines)))))
(defun ignore-line-comments (nlines)
"return the text starting at point as a list, going nlines lines down, stripped of
all C comments (except pathological cases w/ string literals)"
(if (zerop nlines)
nil
(setq ml-e (if (looking-at "\\(.*?\\)/\\*") ;; test on /* comment
(match-end 1)
nil))
(setq sl-e (if (looking-at "\\(.*?\\)//") ;; test on // comment
(match-end 1)
nil))
(if (or sl-e ml-e) ;; any comment on line?
(if (and ml-e (or (not sl-e) (< ml-e sl-e))) ;; is /* the only or first comment?
(progn
(setq r (buffer-substring-no-properties (point) ml-e))
(goto-char ml-e)
(cons r (ignore-multiline-comment nlines)))
(setq r (buffer-substring-no-properties (point) sl-e))
(beginning-of-line 2)
(cons r (ignore-line-comments (1- nlines))))
(looking-at ".*$")
(setq r (buffer-substring-no-properties (car (match-data)) (cadr (match-data))) )
(beginning-of-line 2)
(cons r (ignore-line-comments (1- nlines))))))
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: first steps in elisp
2016-11-24 23:00 first steps in elisp Mark Piffer
@ 2016-11-25 5:39 ` Marcin Borkowski
2016-11-25 8:00 ` Joost Kremers
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Marcin Borkowski @ 2016-11-25 5:39 UTC (permalink / raw)
To: Mark Piffer; +Cc: help-gnu-emacs
On 2016-11-25, at 00:00, Mark Piffer <mark.piffer@gmail.com> wrote:
> I am trying to write some helper functions which should ease documentation of C as per the method which my customers require (mostly repetition of parameters as Doxygen-enabled comments - I don't think that that's a good idea, but the customer wants it). I coudn't find a package that was primitive enough to help me with the parsing - the code is embedded C and quite non-standard with respect to compiler extensions. So I tried to walk the extra mile and code a little elisp for fun. Which things are especially bad or unusual concerning both, Lisp and emacs?
After just a quick glance:
(if CONDITION (progn THEN-CLAUSES...) nil) == (if CONDITION (progn THEN-CLAUSES...)) == (when CONDITION THEN-CLAUSES...)
(if CONDITION nil ELSE-CLAUSES...) == (unless CONDITION ELSE-CLAUSES...)
Also, instead of using setq and global variables, it's much better to
use let.
Keep up the good work of learning Elisp;-)!
--
Marcin Borkowski
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: first steps in elisp
2016-11-24 23:00 first steps in elisp Mark Piffer
2016-11-25 5:39 ` Marcin Borkowski
@ 2016-11-25 8:00 ` Joost Kremers
2016-12-21 17:57 ` Thien-Thi Nguyen
2017-04-12 6:26 ` Steve
3 siblings, 0 replies; 5+ messages in thread
From: Joost Kremers @ 2016-11-25 8:00 UTC (permalink / raw)
To: Mark Piffer; +Cc: help-gnu-emacs
On Thu, Nov 24 2016, Mark Piffer wrote:
> (defun ignore-multiline-comment (nlines)
It's a good habit to get into to always provide a prefix for any
Elisp functions and variables that you write, even if it's just
for your own personal code. For personal code, most people use
their initials, or simply `my-`.
> "assumes point is inside a C multiline comment /*. Advances
> until end of comment */ or nlines becomes 0"
There are some doc string conventions (which can be found in the
Elisp manual: C-h i m Elisp RET m Documentation Tips RET), the
most important of which is that the first line of a doc string
should be a sentence on its own. For personal code, it doesn't
matter as much, of course, but again, it's a good habit to get
into. Also, the doc string should say what a function does, i.e.,
what it expects as input (or context) and what it returns or what
side effects it has. So, e.g.,:
"Move point past the end of a C multiline comment.
This function assumes that point is inside the comment. This is a
recursive function, its stop condition is met when NLINES is 0."
> (if (zerop nlines)
> nil
> (if (looking-at ".*?\\*/")
> (progn
> (goto-char (match-end 0))
> (ignore-line-comments nlines))
> (beginning-of-line 2)
> (ignore-multiline-comment (1- nlines)))))
Personally, I normally wouldn't explicitly write nil as a return
value but instead rely on the function structure to handle that.
So I'd do something like:
```
(defun my-ignore-multiline-comment (nlines)
"assumes point is inside a C multiline comment /*. Advances
until end of comment */ or nlines becomes 0"
(when (not (zerop nlines))
(if (looking-at ".*?\\*/")
(progn
(goto-char (match-end 0))
(my-ignore-line-comments nlines))
(beginning-of-line 2)
(my-ignore-multiline-comment (1- nlines)))))
```
But in this case the nil return value might make sense to indicate
that the stop condition is met. Personally, I would probably write
that in the doc string, but YMMV.
> (defun ignore-line-comments (nlines)
> "return the text starting at point as a list, going nlines
> lines down, stripped of
> all C comments (except pathological cases w/ string literals)"
> (if (zerop nlines)
> nil
> (setq ml-e (if (looking-at "\\(.*?\\)/\\*") ;; test on /*
> comment
> (match-end 1)
> nil))
> (setq sl-e (if (looking-at "\\(.*?\\)//") ;; test on //
> comment
> (match-end 1)
> nil))
Here, you should definitely use local variables for ml-e and sl-e.
Note that if you use setq on a symbol that hasn't been let-bound,
you automatically create a global variable that stays around until
Emacs is shut down. So unless you need to store some global state,
always use let.
Also, I would use longer names for variables, so it's easier to
see what they're used for. But again, YMMV.
> (if (or sl-e ml-e) ;; any comment on line?
> (if (and ml-e (or (not sl-e) (< ml-e sl-e))) ;;
> is /* the only or first comment?
> (progn
> (setq r (buffer-substring-no-properties
> (point) ml-e))
> (goto-char ml-e)
> (cons r (ignore-multiline-comment
> nlines)))
> (setq r (buffer-substring-no-properties (point)
> sl-e))
> (beginning-of-line 2)
> (cons r (ignore-line-comments (1- nlines))))
> (looking-at ".*$")
> (setq r (buffer-substring-no-properties (car (match-data))
> (cadr (match-data))) )
> (beginning-of-line 2)
> (cons r (ignore-line-comments (1- nlines))))))
So with let, this would become:
```
(defun my-ignore-line-comments (nlines)
"return the text starting at point as a list, going nlines lines
down, stripped of
all C comments (except pathological cases w/ string literals)"
(when (not (zerop nlines))
(let ((ml-e (if (looking-at "\\(.*?\\)/\\*") ;; test on /*
comment
(match-end 1)
nil))
(sl-e (if (looking-at "\\(.*?\\)//") ;; test on //
comment
(match-end 1)
nil))
r)
(if (or sl-e ml-e) ;; any comment on line?
(if (and ml-e (or (not sl-e) (< ml-e sl-e))) ;; is /*
the only or first comment?
(progn
(setq r (buffer-substring-no-properties (point)
ml-e))
(goto-char ml-e)
(cons r (my-ignore-multiline-comment nlines)))
(setq r (buffer-substring-no-properties (point) sl-e))
(beginning-of-line 2)
(cons r (my-ignore-line-comments (1- nlines))))
(looking-at ".*$")
(setq r (buffer-substring-no-properties (car (match-data))
(cadr (match-data))))
(beginning-of-line 2)
(cons r (my-ignore-line-comments (1- nlines)))))))
```
It's perfectly fine to use setq on a variable once it's been
let-bound. If you cannot provide an initial value for a variable,
just leave out the value as done here for `r` and setq it later.
BTW, I find it useful to run flycheck in my Elisp buffers, helps
one to develop good habits. :-)
HTH
--
Joost Kremers
Life has its moments
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: first steps in elisp
2016-11-24 23:00 first steps in elisp Mark Piffer
2016-11-25 5:39 ` Marcin Borkowski
2016-11-25 8:00 ` Joost Kremers
@ 2016-12-21 17:57 ` Thien-Thi Nguyen
2017-04-12 6:26 ` Steve
3 siblings, 0 replies; 5+ messages in thread
From: Thien-Thi Nguyen @ 2016-12-21 17:57 UTC (permalink / raw)
To: Mark Piffer; +Cc: help-gnu-emacs
[-- Attachment #1: Type: text/plain, Size: 1026 bytes --]
() Mark Piffer <mark.piffer@gmail.com>
() Thu, 24 Nov 2016 15:00:59 -0800 (PST)
(defun ignore-multiline-comment (nlines)
DOCSTRING
(if (zerop nlines)
nil
(if (looking-at ".*?\\*/")
(progn
(goto-char (match-end 0))
(ignore-line-comments nlines))
(beginning-of-line 2)
(ignore-multiline-comment (1- nlines)))))
In addition to suggestions made by others, i would replace the
(current) recursion w/ iteration, so as to future-proof against
large ‘nlines’ (maybe the text has short multiline comments now,
but you never know what weirdness may inspire the programmer to
wax eloquent in the future :-D).
--
Thien-Thi Nguyen -----------------------------------------------
(defun responsep (type via)
(case type
(technical (eq 'mailing-list via))
...)) 748E A0E8 1CB8 A748 9BFA
--------------------------------------- 6CE4 6703 2224 4C80 7502
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: first steps in elisp
2016-11-24 23:00 first steps in elisp Mark Piffer
` (2 preceding siblings ...)
2016-12-21 17:57 ` Thien-Thi Nguyen
@ 2017-04-12 6:26 ` Steve
3 siblings, 0 replies; 5+ messages in thread
From: Steve @ 2017-04-12 6:26 UTC (permalink / raw)
To: help-gnu-emacs
Mark Piffer <mark.piffer@gmail.com> writes:
< I am trying to write some helper functions which should ease
< documentation of C as per the method which my customers require
< (mostly repetition of parameters as Doxygen-enabled comments - I don't
< think that that's a good idea, but the customer wants it). I coudn't
< find a package that was primitive enough to help me with the parsing -
< the code is embedded C and quite non-standard with respect to compiler
< extensions.
I have some terrible ideas, but you might find them useful or
interesting.
using grep as a shell command process. I would try looking at
`grep-process-startup' or `shell-command on region'. You don't need to
use an external program (shell script). also, emacs has the
`combine-and-quote-strings' function which is very nice. Also
`looking-at-p' is a newer one, does not load match-data.
I'm sure the doxygen docstrings are parsable with emacs - they are font
locked when I check some C buffers; doxygen is not something I know much
about.
check in site-lisp/progmodes/cc-mode.el - has some functions to
determine if your inside a string or comment.
< Which things are especially bad or unusual concerning both, Lisp and
< emacs?
Concerning lisp, I often hear that lisp programmers are considered a tad
bit goofy :) they seem to like to write everything from scratch until it
becomes a command interpreter; the course of just a few bytecodes...
They used to say emacs and vi are religions; these days they are
starting to seem like latin.
< [ ... ]
>
< (defun ignore-line-comments (nlines)
< "return the text starting at point as a list,
< going nlines lines down, stripped of
< all C comments (except pathological cases w/ string literals)"
< (if (zerop nlines)
< nil
< (setq ml-e (if (looking-at "\\(.*?\\)/\\*") ;; test on /* comment
< (match-end 1)
< nil))
using setq will bind the variable with dynamic scope. to get lexical
scope youe use a lambda function (lambda function usually means `let'.
(defun ignore-line-comments (nlines)
"return [ ... ] "
;; new
(let ((ml-e nil))
;; now setq will bind ml-e lexically for the function
(if (zerop nlines)
nil
(setq ml-e (if (looking-at "\\(.*?\\)/\\*") ;; test on /* comment
(match-end 1)
nil))
Hops this helps.
P.S. in another article about the `serial-term' ; Emacs serial term is
woring great with a parallax propeller. The trick is to use pst#NL (that
is insert newline and then form feed. Arg... just had to get that off my
chest.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2017-04-12 6:26 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-11-24 23:00 first steps in elisp Mark Piffer
2016-11-25 5:39 ` Marcin Borkowski
2016-11-25 8:00 ` Joost Kremers
2016-12-21 17:57 ` Thien-Thi Nguyen
2017-04-12 6:26 ` Steve
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).