Spec for new language that allows use of ES6 like coffeescript


#1

This is not specifically a post about Atom but the language will have significant ties to Atom. See the “Atom integration” section below. I urge you to read and comment on this.

The language, actually just a pre-processor, is called csyn. See https://github.com/mark-hahn/csyn. The readme follows …

CSYN

Preprocessor to add coffeescript syntax features to standard javascript

CSYN is a preprocessor that allows standard javascript to be created using many syntax features stolen from coffeescript. When combined with ES6 you get a “language” that is similar to coffeescript but is real javascript with simple syntax substitutions.

CSYN is so simple that it could almost be written with all regex replacements. For example the keyword -> is replaced with function. A more complex example is the whitespace-significant indentation being replaced by braces.

CSYN features are optional which means plain JS is valid CSYN, but converting from JS to CSYN will use all available features.

Motivation

I have used coffeescript exclusively for four or five years and loved it. When I originally looked at changing from coffeescript to ES6 I thought I could never use it because it still uses the horrible C syntax with all the noise. Then it occured to me that something like CSYN could fix that. You write the code mentally as real javascript but without the noise.

Features

This is a wish-list. Some may not be included and I assume more will be added.

  • Works with babel to support most browser versions
  • Significant whitespace, no more ugly pyramid of braces
  • Parens usually not needed in for, if, or function call
  • Skinny and fat arrows with almost the same semantics as coffeescript
  • No need for empty parens before function arrows
  • @var replaced with this.var
  • <- replaced with return
  • #var replaced with let var
  • x@y replaced with x.get(y) (map access)

What CSYN doesn’t do

CSYN makes no changes to ES6 just to be more compatible with coffeescript. CSYN is only to improve ES6 noisiness. For example these are not supported.

str = `CSYN doesn't change #{this} to ${that}`
# this non-comment doesn't become // this comment

Atom integration out of the gate

CSYN will be supported by Atom the same way coffeescript is. This is because Atom now supports Babel as a first-class language.

Not only will a standard CSYN grammar support highlighting, but converting the buffer between CSYN and js will be supported with one command.

Also, there will be a mode where the file is always stored as javascript but edited as CSYN. This eliminates the need to run the pre-processor at build time. This will also allow editing other’s javascript files in CSYN without them even knowing about CSYN.

Status

Just a specification at this point. There is nothing more than this readme. However, this looks like a simple project to implement. I doubt that an AST will be needed. Most will be done with regexes.

CSYN will be written in JS ES6 so it will be effectively written in CSYN.

When stored as a CSYN file the file suffix will be .csyn.

Why switch from Coffeescript

Many coffeescript users like me are converting to ES6. For a quick writeup comparing the two see this

Here is my personal list of reasons for changing to ES6.

  • Improved debugging: Even with source maps coffeescript is harder to debug.
    • You can’t hover over a variable like @var to see the value
    • You can’t evaluate coffeescript in the console
    • Stepping can be confusing because of line mismatch. I sometimes have to step many times to get past one line of coffeescript.
  • Larger community: Coffeescript has divided the community. I can finally publish code without people bitching they can’t read it.
  • Advanced features: While some coffeescript features are lost, like all code being expressions, there are many, if not more, features gained from ES6, like iterators.

Examples

These examples are mostly taken from here.

//--- JS ---
let square = x => x * x;
let add = (a, b) => a + b;
let pi = () => 3.1415;

//--- CSYN ---
#square = x => x * x   // # changed to let
#add = (a, b) => a + b // no semicolons
#pi = => 3.1415        // no empty parens
//--- JS ---
var square = function(x) { return x * x; };
var pi = function() { return 3.1415; };

//--- CSYN ---
var square = (x) -> <- x * x  // anonymous function() becomes () ->
var pi = -> <- 3.1415         // return becomes <-
//--- JS ---
if (x == 0) {
  for (let i = 0; i < 10; i++) {
    y += 10;
  }
}

//--- CSYN ---
if x == 0                      // parens optional
  for #i = 0; i < 10; i++  // whitespace significant
    y += 10
//--- JS ---
function helloWorld (a = 'hello', b = 'world') {
try {
 console.log(a);
} catch(e) {
 console.log(
   b
 );
}

//--- CSYN ---
-> helloWorld (a = 'hello', b = 'world')  // -> changed to function
  try
   console.log 'hello'  // call doesn't need parens
  catch(e)
   console.log(   // left paren needed for multi-line params
     'world'
//--- JS ---
class Parrot extends Bird {
  constructor(name) {
    super(name);
    this.name = 'Polly';
  }
  get name() { 
    return this.name;
  }
}

//--- CSYN ---
class Parrot extends Bird
  constructor name      // no parens needed
    super name
    @name = 'Polly'     // @ changed to this.
  get name
    <- @name
//--- JS ---
function* range(start, end, step) {
  while (start < end) {
    yield start;
    start += step;
  }
}

//--- CSYN ---
->* range (start, end, step)  // ->* means generator function
  while start < end
    yield start
    start += step
//--- JS ---
map.set(key, value)
map.get(key)

//--- CSYN ---
map@key = value  //  @  replaces get and set for maps
map@key

License

CSYN is copyright Mark Hahn via the MIT license.


AnySyn: A new way to edit
#2

So I’m a little cautious on this one. What’s the benefit of adding yet another pre-processor when we’re already in a transition phase from es5 to es6 and, as you say, a trend to migrate is already going on?

How would learning Csyn be any different from learning coffeescript, even though it might be somewhat closer to real javascript?


#3

I don’t think learning csyn will be any different than learning ES6 because it is literally a one-to-one conversion. The only extra learning will be things like -> replacing function. How hard can that be?

I tried to figure out a way to not call it a language. It is simply a shorthand for JS. If I can come up with a different way to think about it I’ll remove all references to it as a language.

I am going to be using ES6 to write the csyn processor and any new projects I do from now on. Now that will be hard to learn.


#4

Well, I’m a visual learner so I’ll wait and look out for examples, which may help me make more sense of it.


#5

Actually I don’t know of any other JS pre-processors. Coffeescript, typescript, and many others are transpilers. The distinction is that they change the AST while csyn doesn’t. Coffeescript is truly a different language.

I need to get sample code in the readme to make this whole topic clearer. Csyn next to plain JS hopefully will make the concept obvious.


#6

Yup, I’ll certainly watch this space with interest.


#7

I’ve updated the readme in the top post above and it now has sample code.

I’ve also changed the feature list. It will be changing rapidly for a while. Of course I want feedback and ideas. I especially want feedback on my features that may be impossible or ambiguous. (grin)


#8

I can see the advantage of CSYN over CoffeeScript in that it enables the usage of JS snippets seamlessly, while CS totally breaks the syntax compatibility. Kudos :thumbsup:


#9

I’m thinking that all JS tools can be used since you can flip the source between CSYN and JS instantly with a keypress. So even JSLint could be used.

I’ve considered just releasing this as Atom-only and considering the CSYN format to be an editing tool only. There would be no .csyn files at all. Selling it as an Atom tool would be easier than selling it as a new language. Maybe I’ve finally got the non-language way of looking at it.

I can’t think of any other editor that allows typing in shortcuts. It’s like the whole language is made of snippets, such as -> expanding to function, but you continue to see the shortcut and the snippets are only expanded when the toggle key is pressed.

The version with the snippet abbreviations would be the csyn version and the expanded snippets version would be the real JS.

This can also be considered a type of “folding” where you fold the JS syntax down to CSYN syntax. Just like folding, the file would shrink/grow.


#10

Something like macros? y’know, PHP started as a collection of macros :smiley:


#11

It could be the next PHP!!! (Is there an emoticon for irony?)

I’ve considered implementing this as a set of macros but I don’t think it would work. But this doesn’t really matter since it is just an implementation detail.

If this becomes just an editing tool then one should consider it being available for many languages. It would allow significant-whitespace lovers from CS and Python to use whitespace in Java, Go, etc.

So csyn is really just a transform operator between two views of the same code.

I think this is a new concept, please correct me if I’m wrong. I need new terminology for the whole thing and I need a new meaningful name.


#12

Mmmh, maybe I skipped this detail first: you mean this to be bidirectional? IE, would you be able to convert (for example) CSYN -> JS as well as JS -> CSYN?


#13

Yes. Maybe I should hit that point harder in the readme. Without this bidirectionality you’d lose the ultra-cool feature of editing someone else’s JS by using CSYN. Two people could work on the same codebase and one would see CSYN and the other would see JS.

Even Coffeescript is bidirectional but the formatting is lossy so you can’t get back to the original CS from JS. CSYN is designed to keep the transformation simple enough to be lossless. The challenge here is the significant-whitespace.

Some of the whitespace formatting may have to be changed in the process but it would always change towards a canonical, beautified version of JS. A beautifier could be built into csyn to make sure the transformation is lossless. Hopefully the JS owner wouldn’t mind seeing his code beautified.

Edit: It would be really cool to put the converter in GIT hooks so one person could check out CSYN and another could check out JS, both from the same GIT commit. It would be analogous to automatic line-ending conversions between \n and \r\n.


#14

With this in mind, wouldn’t it be possible to create a large list of ‘settings’ so that the user can pick what shorthands of CSYN he or she would like to use? Since essentially everything is just a macro, this seems possible.

To illustrate better what I mean, I imagine a scenario where after installing csyn every setting is ticked and the full-fledged version is used to display a JS file in CSYN syntax. For the sake of the example, say I dislike that <- resembles a return and I’d prefer to use return instead. As the spec is now, I can perfectly write this in CSYN and everything will be fine when it is converted to JS. However, when I reopen the file every return will be replaced by <-. Unticking a setting like "Convert return to <-" would prevent this.

Taking this a step further, you could even allow the user to define their own syntax. Using the same example as above, it could offer <- as the default substitution for return, but since I am stubborn and backwards I’d prefer to use nruter so I define that instead (just kidding on that one).

I cannot find a link to the topic right now, but I remember reading something about folding function to fn and style it in italics. If I am not mistaken, the conclusion was that this was not (yet) possible, but it could be possible in CSYN if you can define your own substitutions. You could define fn as a shorthand for function and style it accordingly.

I don’t know if CSYN will need its own grammar to style things without breaking styling in plain JS, just some ideas that came to mind.

Slightly off-topic: In an ideal world the converter could even be generic, so that it could work for any language (by means of a plugin). It checks out with a standard style guide and every user can define their own to display the code on their screen. No more coding style debates, everyone is free to use their own coding style. I realize this has a lot of edge cases and things where it could go wrong or becomes tricky, but I think they are all related to the individual languages.


#15

Those are great ideas.

We have drifted this idea to an older idea I gave a talk on over ten years ago. The old idea was to store source code using just the AST. Then everyone that opened their editor can see whatever syntax they want. Then they would save their changes in the same format AST file.

This would allow you to do crazy things like edit the tree directly. Or you could have a graphical icon for return instead of <-. A graphical icon for the right fat arrow could be the lambda symbol. The sky is the limit.

I now realize you don’t have to store it as an AST. We could store it as canonical javascript and parse the AST on every load and regenerate the code on every save. So GIT would only have the universal JS.

If we are going to do this wild thing then I’d like to just do Javascript for now. Trying to make a framework for any language would be taking on too much. Our first efforts would probably be rewritten anyway as we learn.

I’ll trash that readme and start a new one. Ideas for a new name would be welcome. It could be like flexedit but that is probably already taken.

I’m obviously going to start with the csyn syntax since that is what I want. But it is still open for change. And of course others can fork that to use their own syntax.


#16

Unfortunately a new grammar will be needed. The new token parsing is at least needed. But this should stay close to javascript. I don’t think many would use it if the syntax was in klingon. The javascript grammar can be cloned as a start.

Once again we’ll start off simple and require the grammar to be handwritten. Late we could try to generalize the syntax input. More than just checkboxes and input fields like you mentioned would be needed in the long run. Some kind of grammar specification language would be nice.

Now it’s time to strip this idea to it’s minimum and start implementing the CSYN. Anyone want to help?


#17

Unfortunately I’m going to be AFK for the whole August for summer vacation… After that, you can count me on! I’d love to explore the “storing the AST” idea!


Proposal: Real ES6 JS with Coffeescript syntax
#18

CSYN is now AnySyn and is posted as a new thread here.