spy16 / sabre

Sabre is highly customisable, embeddable LISP engine for Go. :computer:
GNU General Public License v3.0
28 stars 5 forks source link

how to implement comments #20

Closed leifj closed 4 years ago

leifj commented 4 years ago

I'm wondering how to go about implementing comments, eg how to make the interpreter (eg the RELP loop) ignore lines that start with (say) #

spy16 commented 4 years ago

Reader.One() returns ErrSkip (with a nil value) in case of forms that are no-op which includes comments. Reader.All() calls Reader.One() until EOF and silently skips ErrSkip..

Since REPL uses All(), if you enter only comment into the REPL prompt, REPL would get an empty Module which always evaluates to nil. This is why, in REPL you will see nil.. But comments are in fact being ignored.

If you want to implement something that is akin to comments, you can also make use of ErrSkip in the ReaderMacro implementation. (Refer readComment for example)

Basically the idea is to consume whatever you consider as part of the comment and then tell the reader to skip it.

lthibault commented 4 years ago

@leifj Also check out defaultReadTable as well -- this might give you a bit more context for how ReaderMacros work. The short version is: at the start of each new token, check if the rune is in the read-table. If so, apply the function to which that rune is mapped.

N.B.: using # for comments is not recommended, since this rune is used for other things (in particular for sets, which are expressed as #{ ... }).

Out of sheer curiosity, what are you building? We're eager to hear experience reports from users.

leifj commented 4 years ago

Yeah I figured that out - what I was really attempting to do was to enable support for she-bang, ie #!/my/program/with/sabre, but that may be better done as a special case since as you say # is special.

spy16 commented 4 years ago

Oh. Actually there is a secondary table which is used when dispatch character (luckily that is #) is seen by the reader. So your use case is actually very simple.. in the dispatch table, add a reader macro with the trigger character as !.. Reader will call that everytime it sees # followed by !.

spy16 commented 4 years ago

So basically, all you need to do is reader.SetMacro('!', yourMacroFunction, true) .. the Boolean argument here indicates that it should be registered as a dispatch macro..

If you want to do something with the shebang path, you can implement the reader macro with that behavior. Or if you simply want to ignore the shebang line, reader macro can simply consume till new line and return ErrSkip

This idea is inspired from Clojure - https://clojure.org/guides/weird_characters#dispatch

leifj commented 4 years ago

thx!