Skip to content

monsterkodi/kode

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

kode is a programming language that transpiles to JavaScript.

It is highly inspired by and tries to be compatible with CoffeeScript, while adding some features and further its minimalistic approach:

...

a = 1...3
for i in 0..5

Square brackets around ranges are optional.

console

log 'hello'     ▸ hello
error 'world!'  ▸ world!

Simple shortcuts for log, warn and error methods of console.

negative indexing

"abc"[-2]       ▸ 'b'
[1,2,3][-2]     ▸ 2

v[-n] is a shortcut for v[-n..-n][0] for number literals n

if

if  
    a ➜ X
    b ➜ Y
      ➜ Z

is a shortcut for

if      a then X
else if b then Y
          else Z

switch

switch x
    1
    2 3   ➜ X
    'abc' ➜ Y
          ➜ Z      

is a shortcut for

switch x
    when 1,2,3 then X
    when 'abc' then Y
    else            Z

is

1 is 'number' and '' is 'string' and {} is Object and [] is Array   ▸ true
1 is Number or '' is String or [] is 'array'                        ▸ false

is is a shortcut for typeof and instanceof. The first is used, when the right hand side is a string.

num str obj

"0xFF" is num and "-4.536" is num and 42 is num                     ▸  true
'' is str and "a" is str and new String("abc") is str               ▸  true
{} is obj and new Object() is obj                                   ▸  true
null is obj or new Map() is obj or [] is obj                        ▸  false

is num does a string coersion via parseFloat in the test. is str checks both, type == 'string' or instanceof String. is obj evaluates to true for plain Objects only.

empty

empty [] and empty {} and empty '' and empty null and empty NaN     ▸ true
empty 0 or empty 'a' or empty [null] or empty Infinity              ▸ false

Returns true for null, undefined, NaN and empty array, object or string.

valid

valid 0 and valid 'a' and valid [null] and valid Infinity           ▸ true
valid [] or valid {} or valid '' or valid null or valid NaN         ▸ false

Just the negation of empty.

each

obj each (k,v) -> [k,v]
obj each (v) -> v

The each operator takes an object, array or string on the left hand side and a function on the right hand side. The function is called for each key/value, index/item, index/character pair. A new object, array or string is build from the results and returned:

'hello'   each (c) -> c+c                                           ▸ 'hheelllloo'
[1,3]     each (i,v) -> [1-i,v*v]                                   ▸ [9,1]
{a:1,b:3} each (k,v) -> ['▸'+k, k+v]                                ▸ { '▸a': 'a1', '▸b': 'b3' }

If the function takes only one argument, it is the value/item/character and a single return value is expected.

for

x = null
for a in x
    log 'hello'

The above code would throw an exception at runtime in CoffeeScript. kode generates code that doesn't fail if x is not an array.

constructor

class C
    @: ->

is a shortcut for

class C
    constructor: ->

list comprehension

l = [1,2,3]
a = [x for x in l]                                                  ▸ [1,2,3]
a = (x for x in l)                                                  ▸ [1,2,3]

kode doesn't distuinguish between round and square brackets around list comprehensions.

ternary

false ? 1 : 2                                                       ▸ 2

A nifty if then else shortcut. It introduces some ambiguity in a few corner cases, which can be resolved by different spacing:

null ? a: 'b'                                                       ▸ {a:'b'}

old school

kode gives you the option to use the old school function style classes of CoffeeScript v1:

function C
    @: ->

The generated code might be a bit more ugly, but the function based classes don't suffer from some of the limitations of the new class syntax. For example, keywords can be used as method names and super doesn't have to be called first in the constructor. New and old school styles can be used in the same module, but obviously not in the same class hierarchy.

optional commata

CoffeeScript has a very nice way of initializing arrays:

a = [
        1
        2
        3
    ]

If you decide to join these into a single line, you have a problem: for each of the lines a comma must be inserted. The same goes for objects that span over multiple lines.

In kode, you don't need to insert commata after number or string literals and POD structures. Those are all valid expressions:

a = [ 1 2 3 ]
a = { b:1 c:2 d:3 }
a =   b:1 c:2 d:3
a =   b:[ c:2 'd' 3 ]
a = [ [1 2] [d:3] ]

test 'something' ->
    it 'should' ->

on 'event' @myCallback

log 'a:' a , 'd:' 3                     # some commas still make sense :-)

noon

s = noon a:1 b:2
log s                                   ▸ a   1
                                        ▸ b   2

Operator that converts argument into string in noon notation. Handles recursion, unlike JSON.stringify.

dbg

myObj = a:1 b:2 c:d:3
dbg myObj                               ▸ file.kode:2:0 myObj
                                        ▸ a   1
                                        ▸ b   2
                                        ▸ c
                                        ▸     d   3
dbg '1st' 0 '2nd' myObj.c               ▸ file.kode:7:0
                                        ▸ 1st 0 2nd d   3

Logs file and position followed by arguments in noon notation. If first argument is an identifier, appends its name to the file position.

assert

f = (a) -> ▴ a ; a                      ▸ file.kode:1:11 ▴ assert failed! a
▴ 'good' f 1                            
▴ 'bad'  f 0                            ▸ file.kode:3:0 ▴ bad f(0)

Logs file position, message and condition code if condition isn't truish. If message is omitted, 'assert failed!' will be used.

profile

●▸ sunny times

fun = ->                              
    ● funny times                     
    Math.sqrt x for x in 0..100000    
                                      
fun() for i in 1..2                     ▸ funny times 12 ms
                                        ▸ funny times 11 ms
●▪ sunny times                          ▸ sunny times 26 ms

Logs time difference between matching ●▸ ●▪ pairs.

is a shortcut that can be used in functions: ●▪ is inserted automatically before the function returns.

process.hrtime.bigint is used for the timing and the measurements come with μs accuracy. Due to JavaScripts just in time compilation optimizations, the initial results might be greater than later runs.

copy & clone

a = copy b                              # shallow copy of b
a = clone b                             # deep copy of b

Operators that return a shallow or deep copy of their argument. Only plain Objects, Arrays and Strings are copied. Functions, Maps, Sets, etc. are not copied.

eql

a eql b                                 # deep comparison

Does a deep comparison of its operands. Only plain Objects, Arrays and Strings are compared.

tests

kode comes with its own testing 'framework' (in quotes here, because it's too much of a word for such a minimalistic thing:)

▸ test
    ▸ sub test
        something      ▸ result
        something else ▸ other result

If the has nothing on its left hand side, it denotes a test section. Otherwise the expressions on both sides are compared. The files in kode/test provide plenty of examples how to use this:

the output of two runs:

ansi colors

log Y5 r2 'warning!'   ▸ output in dark red on bright yellow

kode injects ansi color code wrappers if it discovers function calls with names like R1 or g8. Color functions: 'r' 'g' 'b' 'c' 'm' 'y' 'w' for foreground (uppercase for background) and a number between 1 and 8.

Compatibility

kode is mostly compatible with CoffeeScript. Converting to kode shouldn't be too painful.

Stuff I rarely used and therefore didn't bother to re-implement:

  • literal coffeescript
  • unless until or= by ...
  • when outside of switch
  • wrapper code
  • string interpolation in object keys
  • implicitly returning arrays if last expression is a loop

features to add

  • use keyword for import
  • include keyword to merge source files
  • render comments
  • sourcemaps
  • error messages

bugs

return issues

  • trailing if after obj args: @func obj:1 if truish
  • indentation issue in else branches:
    if 1 then 
    else # this works
        @s = Immutable 
                lines:lines
    
    if 1 then
    else # this doesn't :(
        @s = Immutable 
            lines:lines
    

About

programming language

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published