Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding plugins to coffeescript (i.e. preprocessor for logging) #1466

Closed
tauren opened this issue Jun 25, 2011 · 29 comments
Closed

Adding plugins to coffeescript (i.e. preprocessor for logging) #1466

tauren opened this issue Jun 25, 2011 · 29 comments

Comments

@tauren
Copy link

tauren commented Jun 25, 2011

I would like to see coffeescript have a plugin system that would allow users to develop enhancements that can be inserted into the coffeescript compile process.

For instance, I scatter console.log output throughout my application, but there are times that I want to have loglevel features, such as console.debug or console.trace. To make this work cross-browser, I create my own logging functions. The problem is that console output shows the file name and line number of where console.log was called, not where my wrapper function is called. This makes it more time consuming to debug in a browser.

Furthermore, I want all of my logging code to be removed when in production mode. It seems to me that coffeescript would be an ideal place to handle custom logging features, and it could easily choose to include or exclude logging code in production mode. I would love to see coffeescript enhanced to allow users to build preprocessors that would be run on the code before the compiler is run.

Imagine a preprocessor that defines some custom functions. These functions would inline code in the output based on some condition. For instance, my preprocessor defines a logger object and adds some methods to it. This could be used with coffeescript like this:

logger.loglevel 'debug'
logger.info 'Info'
logger.debug 'Debug'
logger.trace 'Trace'

This would generate:

console.log('Info');
console.log('Debug');

Note that 'Trace' isn't output because the loglevel excludes it. The values of logger.loglevel could be kept simple, or could allow lots of levels: none, fatal, error, warn, info, debug, and trace.

The output would be dynamically included depending upon the function called and the current log level. It would be great if the command line compiler could somehow take parameters for preprocessors so that something like --loglevel none could be specified when generating production code.

It would be extremely nice if each file could have it's own loglevel scope. That way if I wanted to only see trace level logging in a certain module of my application, I wouldn't have to see the trace output from everything else.

Anyway, does this seem like a useful idea? Since coffeescript is already compiling code, why not plug into it for features like this? Could this be added without changing coffeescript core, or would it need to go into coffeescript core?

@michaelficarra
Copy link
Collaborator

Just noting some related macro issues, don't mind me: #273, #313, #889

@mark-hahn
Copy link

+1

1 similar comment
@blackbing
Copy link

+1

@twoolie
Copy link

twoolie commented Feb 3, 2012

+1

@chrisfjones
Copy link

+1
line-number reporting in log statements would save a lot of debug time
plus, coffeescript has a major leg up since it can bake this stuff in at compile time

I'm not so sold on a full-blown preprocessor plugin system, but the logging use case on its own is very compelling.

@faridnsh
Copy link

I can work on this, but have you guys decided about a keyword and the syntax?

@michaelficarra
Copy link
Collaborator

@alFReD-NSH: There's a lot left to decide regarding macro/plugin support. How about you make a proposal (with some good reasoning for the design decisions you made) and we go from there?

@faridnsh
Copy link

I think we should stick to C macro syntax:

#define SOAD SYSTEMOFADOWN
#define sq(x) x*x

Though the only reason I can find for this is that C/C++ developers are already familiar with this. Also we can use a coffeescript like syntax:

define lolz (x) -> 'I am loling at ' + x

or with another keyword(macro)

macro lolz (x) -> 'I am loling at ' + x

We can also make it more complicated, exposing the AST or part of the lexical scanner similar to here, which gives us super powers!

Which I think we can add another syntax (->>) to define function that take the macro arguments and the this object as the AST, and return the text to be replaced.

addObjectName (msg) ->> 
  @lex.remove.charBefore('.') # This will remove the dot before the macro
  "(#{msg}, #{@ast.objectName})" # This will return the msg and the latest object inside brackets.

This will replace a.addObjectName('hello') to a('hello', 'a')

@twoolie
Copy link

twoolie commented Mar 20, 2012

I think that the biggest one would have to be the use case demonstrated in @maxtaco's IcedCoffeeScript fork. Not so much the ability to do AST rewriting but the clever way of annotating the call chain with source file/line numbers which can then be walked in a exception handler to generate good debugging information in the absence of sourcemap support.

@faridnsh
Copy link

I found this link and the discussion a bit helpful to choose the syntax for macros: http://news.ycombinator.com/item?id=837099

@johnfn
Copy link

johnfn commented Jun 7, 2012

I am very interested in this. Extensible coffeescript would be a dream come true. Is there still interest in a general macro system?

Some immediate use cases I could see for this system:

  • Native await / defer
  • Logging
  • Type annotations for the google closure compiler
  • Line number annotations
  • Assertions (stripped from the release version)

Is anyone interested in working with me on drafting a proposal for such a system?

@mark-hahn
Copy link

Check github issues. This has been shut down before.

On Wed, Jun 6, 2012 at 5:14 PM, Grant Mathews <
[email protected]

wrote:

I am very interested in this. Extensible coffeescript would be a dream
come true. Is there still interest in a general macro system?

Some immediate use cases I could see for this system:

  • Native await / defer
  • Logging
  • Type annotations for the google closure compiler
  • Line number annotations

Is anyone interested in working with me on drafting a proposal for such a
system?


Reply to this email directly or view it on GitHub:
#1466 (comment)

@johnfn
Copy link

johnfn commented Jun 7, 2012

@mark-hahn, I cannot find any evidence that this is true.

The most recent issue I can find is #2189 which says patches are welcome. I also see #2080 which in fact points to this question. Do let me know of any other discussion on this topic. This was the largest discussion I could find.

@mark-hahn
Copy link

What I meant to say was that there have been several long threads over two
years and it has gone nowhere.

This was the largest discussion I could find.

The length of the discussion is much less important than what the BDFL
says. This is the only comment I've seen by Jaskenas ...

#273 #273 :

It's fine as a neat trick, but it's never going to be wise in production
code (for compatibility with other libraries), and it's often going to be
better to just modify the language itself, considering that it's fairly
hackable.

You'll note I've given +1s to several of these threads. But I'm not
holding my breath.

On Wed, Jun 6, 2012 at 6:57 PM, Grant Mathews <
[email protected]

wrote:

@mark-hahn, I cannot find any evidence that this is true.

The most recent issue I can find is #2189 which says patches are welcome.
I also see #2080 which in fact points to this question. Do let me know of
any other discussion on this topic. This was the largest discussion I could
find.


Reply to this email directly or view it on GitHub:
#1466 (comment)

@johnfn
Copy link

johnfn commented Jun 7, 2012

In the same thread you referenced, jashkenas offers anyone who wants to write a macro system to write a proposal responding to 4 bullet points. michaelficarra did the same thing in this thread (minus bullet points). That in particular is what I am responding to.

If those offers still stand then I am interested in drafting a proposal. I have assumed that they do since this issue continues to be open.

I of course do not ask of you to hold your breath for me. :) I think that a plugin or macro system would be beneficial to the whole CoffeeScript community, so I want to advance some discussions in that area. I can't find a common reason for why the discussions stopped in the past, other than that no one drafted a proposal.

@mark-hahn
Copy link

Sounds good. Go for it.

On Wed, Jun 6, 2012 at 7:55 PM, Grant Mathews <
[email protected]

wrote:

In the same thread you referenced, jashkenas offers anyone who wants to
write a macro system to write a proposal responding to 4 bullet points.
michaelficarra did the same thing in this thread (minus bullet points).
That in particular is what I am responding to.

If those offers still stand then I am interested in drafting a proposal. I
have assumed that they do since this issue continues to be open.

I of course do not ask of you to hold your breath for me. :) I think that
a plugin or macro system would be beneficial to the whole CoffeeScript
community, so I want to advance some discussions in that area. I can't find
a unified reason for why the discussions stopped in the past, other than
that no one drafted a proposal.


Reply to this email directly or view it on GitHub:
#1466 (comment)

@faridnsh
Copy link

faridnsh commented Jun 7, 2012

That was my proposal, if you guys can't see it #1466 (comment)

@johnfn
Copy link

johnfn commented Jun 7, 2012

@alFReD-NSH: I'm not quite sure I understand your proposal. The advantage of a lisp like macro is that it allows direct manipulation of the AST. But your proposal only allows for manipulation at the token level, which could get hairy for more intricate macros.

I think what would be best is if a macro would take the internal CoffeeScript AST build out of the code that was passed to it, and 'returned' a new AST (which you could tweak with CoffeeScript). It would leave something to be desired from lisp like macro systems, but it would be infinitely better than what we have now (nothing).

I'm still thinking about how best to do this syntactically.

@jashkenas, before I get too deep, could some sort of macro system eventually see the light of day in CoffeeScript?

@Evgenus
Copy link

Evgenus commented Aug 6, 2012

This proposal is kind of trivial, but... Thinking of plugins. Since coffee-script is made of coffee-script, I'd like to add new compiler rules, BNF-rules and token (yes, hardcore). Forking isn't seems to be a good option, because it will be hard to use my and someones else extensions together. Could it be some way to make plug-able language extension in generalized way?

@michaelficarra
Copy link
Collaborator

@Evgenus: https://github.com/michaelficarra/CoffeeScriptRedux has most of what you want. It will be complete in around 2 months. You can already start experimenting with it, though.

@johnfn
Copy link

johnfn commented Aug 8, 2012

@michaelficarra CoffeeScript Redux plans to support some sort of preprocessor system? That's exciting. Have you written up the exact plan somewhere? I read through CoffeeOfMyDreams but couldn't find anything on the preprocessor.

@bunyk
Copy link

bunyk commented Jul 8, 2013

Can anybody give me some pointers about how to extend compiler, so it can handle something like:

#if debug
    #define log(x) "console.log(#{x})"
#else
    #define log(x) "#{# x}"
#endif

?

@faridnsh
Copy link

faridnsh commented Jul 8, 2013

coffee-script now has support for source maps, which solved a problem that this feature was trying to solve. Don't forget guys, you can always use cpp(C pre processor) which supports a lot of suggested syntax in this issue.

@pixelpax
Copy link

pixelpax commented Oct 8, 2015

I know that the original problem this thread set out to solve has been resolved, but I'm looking for information about customizing the coffee compiler.

Say, for example, that I wanted to augment the functionality of a all arrays and objects with underscore functions, allowing me to do something like testArray.first() and have it compile to _.first(testArray)

This is something which would be very dangerous to do in plain javascript, as I would have to extend the Array.prototype and might break functionality of the array in other libraries. It seems like it would be safe and fun to do with coffee-script, though!

It would be great if there was a way to do this in a way which is:

  1. Modular - I could add multiple pre-processing steps, pulling from different sources which make programming more easy and elegant in different ways.
  2. Integrated - I want to be able to change something in the configuration files of coffeescript so that I don't have to use a custom binary and replace the command in every single development tool which is calling the coffee compiler (for live compilation, etc).

Does this exist built into coffeescript now? If not, it seems like it should. I realize this opens up a can of worms and would probably lead to some horrible misuse. But, hey, with great power comes great responsibility!

@akre54
Copy link

akre54 commented Oct 8, 2015

@HeroicAutodidact leaving aside whether that's a good idea, I don't see a way of doing that without runtime checks. Check out #3171 for a stab at hygenic macros, which may be what you're looking for.

@carlsmith
Copy link
Contributor

The desire to avoid runtime checks seems to have caused an unhelpful aversion to runtime in general. It doesn't really matter how much we sugar a user's invocations. It's not a runtime check to compile 2px to px(2) or with _ then @first array to _.first(array).

Invocation sugar seems to get conflated with runtime checking.

@akre54
Copy link

akre54 commented Oct 8, 2015

But think of how much slower your app would be if you had to wrap every member access call to .first() to see if the variable is an array. It's also surprising behavior that some method invocations would act differently depending on what method was called. This is a poor idea.

@carlsmith
Copy link
Contributor

Agreed. I wouldn't want this feature as suggested either.

I was just saying that having more sugar for expressing invocations (the two I mentioned are just for example) is totally different to wrapping stuff in checks.

It just seems like we could allow for a lot more of what people wanted to do if there were more ways to write an expression that invokes a user defined function on the expression's operands. Instead of exploring how to do that best, we tend to dismiss it for sounding like it introduces runtime checks.

You are totally correct though @akre54: We can't fix methods without expensive checks all over the place.

@GeoffreyBooth
Copy link
Collaborator

Closing this issue as it appears that a --logLevel flag or something like it isn’t currently in the plans. However there definitely is need for making the compiler extensible, so if someone wants to propose a feasible way for implementing a plugin architecture that would be greatly appreciated. Please make such suggestions as new issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests