Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
904 lines (555 sloc) 13 KB

Big Picture TODO

I'm reaching the point of limited gains with reducing syntax. There are still a few big things left:

  • Dot (.) back-refs will be huge
  • Inline Types will be huge for Art.Nano.*
  • await

Streamlining development is going to be my next focus:

  • Make webpack compile errors clearer
  • Try write-back mode for CaffeineMc for compile errors
  • Start a campaign to really make good compile-errors (and fix the totally broken ones)
  • Get help with source-maps. Why are mine ignore almost everywhere? But sometimes not?

Help with CoffeeScript conversion:

  • Allow for, but log a DEPRECATION
  • Can we make my old-style "array fromArray, (v, k) ->" lib a compile error? Right now they compile into something really broken.
  • Allow {\n\tblah\n} both for structuring and destructuring.

Syntax Highlighting

  • support the other syntax-highlighting file-type that everyone else uses
  • support starting blocks with """ at the end of a line instead of only at the start
  • support #{} block syntax highlighting

To Sort

find {}
# should probably return undefined...
# Why? well, we'd like to distinguish between finding and not finding:
find a in b when a == null
# IDEA: this:
if find v, k in record when allowedFields[k]
  object v, k in record when allowedFields[k]

# could be:
object-if-find v, k in record when allowedFields[k]

# array-version:
array-if-find v, k in record when allowedFields[k]

# I don't quite like that syntax, but the idea is:
# For either 'object' or 'array', return null instead of
# an empty {} or [] - if empty it would be.
# This is an optional mode; most the time I want
# that empty {} or [] so other things don't break.

# OOPS - and interesting. THIS is actually correct:
if (find  v, k in record when v? && allowedFields[k])?
  object v, k in record when allowedFields[k]
# If when we find the first k in allowedFields, and v == 0,
# the if will be false; ack! In fact, I'd like to have even v == null be OK
# I really like the idea of object-if-find now. It would be just like object,
# except it would vivify the return-object upon the first key it finds that
# passes 'when'.
# IDEA alias opportunity: found == find
# It's nice when combined with 'if'
if found v in records when

# hey, that'z nize!
if found records with .foo?

# or if we do the object-if syntax:
object-if-found records with allowedFields[..] # .. == second param which is the key

# I kinda like it since it's more declarative-feeling vs imparative.


if !response.isRootRequest || response.requestProps.prefetch == false || response.requestProps.include == false || # DEPRICATED response.type == :delete



b = {} = a

could be:

b = object a

OK, so not a big savings there, but what I want is this:

{} {} = a foo: bar


The ability to merge "a" into the new object we are also

merging other things into.

Example 2:

{} {} = a {} = b

i.e.: merge a, b

OR equiv:

{} object a object b

None look terribly "obvious" to me, but they are useful,

and currently illegal...


[] &Filters {} config pipelines &Session.session # ...

could be:

{} {} = &Filters config pipelines &Session.session

I like "{} = foo" best, it's consistent with what I know-i-want:

{} {a, b} = foo c: 123


a: foo.a b: foo.b c: 123


c = {-a} = b


c = object v, k in b when k != :a

AND, how about this one: c = {/^a.*/} = b


c = object v, k in b when /^a.*/.test k

mix-and-match: (?)

c = {/^a/, -a} = b

since that could just be this, maybe we only allow one regexp:

c = {/^a.+/} = b

in fact, I almost think {/ /} is a special thing, since you

can express any possible selector that way, adding special logic

w.r.t. how separate selectors combine (is it AND or is it OR?)

is just messy.

NOTE, I have no idea what this means:

{/^a/i} = b # This has no side-effects and if the return is ignored...

Probably: cpu burner

Could be ILLEGAL, but I like to minimize what's ILLEGAL.


Another, realworld example:


7 tokens

merge objectWithout responseProps, :dataUpdates {} data

OR, only creates 1 obj, 12 tokens

out = objectWithout responseProps, :dataUpdates = data out


NOTE: this would only create 1 object instead of 3!

8 tokens

{} {-dataUpdates} = responseProps data

Here is another, current option, that only creates 1 object:

18 tokens

object v, k in responseProps into {} data when k != :dataUpdates && k != :data

Should this be legal?

1 /2

right now you have two spacing options:

1 / 2 1/2

I just made it illegal when I fixed this:

"1 -2" == "[1, -2]" and "a 1 -2" == "a(1, -2)"

# Improvements

  {foo, fun} = bar
# should be: {baz: baz, foo:, fun:}
# also sets: foo and bar as expected
  bar extract foo, fun
# should be: {baz: baz, fun:}
# also sets: foo and fun as expected
# TODO: - word-string-interpolation:
# should be: `foo${bar}`
# extract should support '?' and '||/or'
# we should ALSO support these options for function defaults
# extract ? vs = vs ||
a extract
  b ?= :default  # default-if-undefined-or-null
  c = :default   # default-if-undefined
  d ||= :default # default-if-false
# extract should set defaults no matter what
o = a extract?
  d = :noD
# d AND o should == :noD when !a?

# should apply recursively:
o = a extract?
  b extract?
    d = :noD
# o, b, and d should == :noD when !a?

# should apply recursively:
o = a extract?
  b = c extract?
    d = :noD
# o, b, and d should == (if c? then c.d else :noD) when !a?

# let's do this soon:
{@foo} = bar
bar extract @foo

# regex needs interpolation blocks:
  hi #{}
    myString + "foo"

{} a = b = 1
# Should be:
# temp = 1; {a: temp, b: temp}
# in-array should work
array a in-array b

  } = myObject

  } = myObject

    hi: 1

  = myObject

break & return for comprehensions

Comment Todo

The real solution looks like this: Every block sub-parsed, other than literals like string-blocks or comment-blocks themselves, needs something akin to the current preprocess step: Any under-indented comments should be up-indented to the base of the sub-block. I -think- that'll solve it.

# extra-indented comments should be ignored
    # extra indented first comment

Generates invalid javascript:

# compiler ERROR


(-> arguments.length)()

[].slice 0, 100

# compile ERROR
each from a til 3


(a.b) -> a

# simplest example
foo (a)->

Above one is super tricky! The function definition correctly fails to match the indented block starting with a dot-line-start, but then the indented-dot-line-start happily accepts it. It actually could be considered legal! However, it's horrific to my eyes. It breaks principle-of-least-surprise badly.

I think we need "match-block-or-no-block" to solve this.

NOTE: It isn't just dot-line-starts. This also fails fore operator-line-starts.

App extends FluxComponent


  directory structure:

# Should generate: require('./.DotSubdir')
# bad regexp detect
rect a.left,, a.w/2, a.h/2
array a in things when a &&

# AHEM. That should NOT be:
# > Caf.array(things, null, a => a) && true
# It should either be an error, or it should be what I was wanting:
# > array a in things when a && true

I think the following code is solvable if we make the "comma-then-block-extends-list" an optional comma. I -think- it'll work.

# this:
a :string
# should probably be this:
a :string, b
# not: a(:string)(b)

(a || b)

# should be:
(a || b)(c);
# Shouldn't this:
log {} currentTopicChanged, currentPostChanged, postsChanged,
  post: !!post?.id
  posts: posts?.length
  topic: !!topic?.id

# be the same as this?
log {}
  currentTopicChanged, currentPostChanged, postsChanged,
  post: !!post?.id
  posts: posts?.length
  topic: !!topic?.id

object v, k with-key lowerCamelCase k.replace /^posterText/, '' in a: 1 b: 2

# should be the same as:
object v, k in a: 1 b: 2 with-key lowerCamelCase k.replace /^posterText/, ''


foo extract
# this should mean:
foo1 = foo
foo =
bar =

if i == cats.length - 1 then Promise.then -> action event, props else {}

action event, props should be inside the .then funciton. The problem probably comes from this parse error:

# does not parse!
if a then -> c else d

array item in list.sort (a, b) -> b - a when item

# Should NOT be:
Caf.array(list.sort(function(a, b) {})(b - a), null, item => item);

# Should be:
Caf.array(list.sort(function(a, b) {return b - a}), null, item => item);

Probably same problem as above:

# this does not parse!
array item in -> a when item

Improved Parse Errors

# TODO: "UnaryOperator not allowed when structuring an object" should reveal a line-number:
log {} "#{message}": bitmap.clone(), size: bitmap.size, testArea

ERROR in ./test/tests/Art.Engine/Core/CoreHelper.caf
Module build failed (from ../caffeine-mc/webpack-loader.js):
Error: UnaryOperator not allowed when structuring an object. Legal examples: foo.accessors, &requires and identifiers.
# should show <here> right before &&&, not at start of line

Should Be Legal

# should be legal:


a = switch
when foo()
when bar()
# right now, a == undefined
# could mean:
a = switch
when temp1 = foo() then temp1
when temp2 = bar() then temp2

# what-does-this-mean-for-new-'if'-switcher?
  foo() then
  bar() then
# I feel like that should be illegal;
# hanging prepositions feel bad :)

Major Plans

Fix Comprehension Scoping

# when should share scope with the with-clause (and with-key) clause
# I think we can rework iterators JavaScript code to use
# only one funciton instead of two, even when there is a when
# or with-key clause.
array a in b when c =


extract in comprehensions and function definitions:

# these should all be equivalent
(a extract b) ->
(extract b) ->

{b} ->

# these should all be equivalent
each a from c with a.b
each a extract b from c
each extract b from c

each a.b from c
each .b from c

Improve While Scoping

# This SHOULD 'let p' in the while-test, not in the body, assuming
# javascript lets us do that.
while p = @nextPoint
  {x, y} = p

# What about this? Should also let-p in the while-test, but trickier.
while someFun p = @nextPoint
  {x, y} = p

New IF-Block

# IF, SWITCH and more BLOCK options:

# can we make this legal?
   && b

 console.log "dude"
# and for switch-when as well

# I want this, too:
  console.log "dude"

# and for switch-when as well:
  console.log "dude"

# Don't for get the new magic-if:

  a then b
  c then d

if foo
  is Object then e
  > 10      then f
  4 < .     then g
  .isFoo()  then h

  some.long.test .
  then i

  # implicit else-block:

  # explicit indented else:
  else foo

# de-indented else:
else foo


# If Foo has its own Function object, global.Function will NOT
# be used! Huh.
import Foo
a is Function
# strings in object-construction should either:
#   be an error << MY GUT says error
#   or, be: [myString]: myString
PostDate {}
  :row :childrenCenterRight
  oneLine:  true
  size:     wcw: 1, h: gridSize * 2
  color:    TextPalette.white.secondary
# We should support this:
a extract
  (c = b?.foo) extract? d
      c = b?.foo
      extract? d

# equivelent:
{b} = a
c = b?.foo
c extract? d
# hmm, ES6 is so dumb
  (a = d) -> a
  1 # but ES6 says its 0
# we could just move all defaults inside the body,
# as it should be. Adding defaults should not change the external API! WTF?!?
# This is a problem for my fastBind function which needs to know the number of args a function has
class Foo
  b = []
  constructor: (a = b) ->
You can’t perform that action at this time.