formatting

formatting

module.exports (terms) = terms.term {
    constructor (iterator, collection, stmts) =
        self.is for in = true
        self.iterator = iterator
        self.collection = collection
        self.statements = stmts

    generate java script (buffer, scope) =
        buffer.write ('for(var ')
        self.iterator.generate java script (buffer, scope)
        buffer.write (' in ')
        self.collection.generate java script (buffer, scope)
        buffer.write ('){')

        self.cg.sub expression (
            self.cg.function call (
                self.cg.block (
                    [self.iterator]
                    self.statements
                    return last statement: false
                )
                [self.iterator]
            )
        ).generate java script statement (buffer, scope)

        buffer.write ('}')

    generate java script statement (args, ...) = self.generate java script (args, ...)
    generate java script return (args, ...) = self.generate java script (args, ...)

    definitions (scope) =
      defs = []
      index name = self.iterator.definition name (scope)
      if (indexName)
        defs.push (indexName)

      defs.concat (self.statements.definitions (scope))
}

module.exports (terms) = terms.term {
    constructor (iterator, collection, stmts) =
        self.is for in = true
        self.iterator = iterator
        self.collection = collection
        self.statements = stmts

    generate java script (buffer, scope) =
        buffer.write('for(var ')
        self.iterator.generate java script(buffer, scope)
        buffer.write(' in ')
        self.collection.generate java script(buffer, scope)
        buffer.write('){')

        self.cg.sub expression(
            self.cg.function call(
                self.cg.block(
                    [self.iterator]
                    self.statements
                    return last statement: false
                )
                [self.iterator]
            )
        ).generate java script statement(buffer, scope)

        buffer.write('}')

    generate java script statement (args, ...) = self.generate java script (args, ...)
    generate java script return (args, ...) = self.generate java script (args, ...)

    definitions (scope) =
      defs = []
      index name = self.iterator.definition name(scope)
      if (indexName)
        defs.push(indexName)

      defs.concat(self.statements.definitions(scope))
}


new regexp syntax for commandLine.pogo

new regexp syntax for commandLine.pogo

fs = require 'fs'
ms = require '../lib/memorystream'
parser = require './parser'
parse = parser.parse
uglify = require 'uglify-js'
errors = require './codeGenerator/errors'
_ = require 'underscore'
readline = require 'readline'
util = require 'util'
Module = require 'module'
path = require 'path'

generate code (term) =
    memory stream = new (ms.MemoryStream)
    term.generate java script (memory stream)
    memory stream.to string ()

beautify (code) =
    ast = uglify.parser.parse (code)
    uglify.uglify.gen_code (ast, beautify: true)

exports.compile file = compile file (filename, ugly: false) =
    js = compile from file (filename, ugly: ugly)

    js filename = js filename from pogo filename (filename)
    fs.write file sync (js filename, js)

when (filename) changes (act) =
    fs.watch file (filename) {persistent, interval 500} @(prev, curr)
        if ((curr.size == prev.size) && (curr.mtime.get time () == prev.mtime.get time ()))
            return

        act ()

exports.watch file (filename, options) =
    compile () =
        console.log "compiling #(filename) => #(js filename from pogo filename (filename))"
        compile file (filename, options)

    compile ()

    when (filename) changes
        compile ()

exports.lex file (filename) =
    source = fs.read file sync (filename) 'utf-8'
    tokens = parser.lex (source)

    for each @(token) in (tokens)
        text = (token.1 && "'#(token.1)'") || ''
        console.log "<#(token.0)> #(text)"

js filename from pogo filename (pogo) =
    pogo.replace r/\.pogo$/ '' + '.js'

exports.run file (filename) in module (module) =
    js = compile from file (filename)
    module._compile (js, filename)

exports.run main (filename) =
    full filename = fs.realpath sync (filename)

    process.argv.shift ()
    process.argv.0 = 'pogo'
    process.argv.1 = full filename

    module = new (Module (full filename, null))
    process.main module = module
    module.id = '.'
    module.filename = full filename
    module.paths = Module._node module paths (path.dirname (full filename))
    exports.run file (full filename) in module (module)
    module.loaded = true

exports.compile (pogo, filename: nil, in scope: true, ugly: false, global: false, return result: false) =
    module term = parse (pogo)
    module term.in scope = in scope
    module term.global = global
    module term.return result = return result

    code = generate code (module term)

    if (!ugly)
        code = beautify (code)

    if (errors.has errors ())
        errors.print errors (source location printer (filename: filename, source: pogo))
        process.exit 1
    else
        code

exports.evaluate (pogo, definitions: {}, global: false) =
    js = exports.compile (pogo, ugly: true, in scope: !global, global: global, return result: global)
    definition names = _.keys (definitions)

    parameters = definition names.join ','

    run script = new (Function (parameters, js))

    definition values = _.map (definition names) @(name)
        definitions.(name)

    run script.apply (undefined) (definition values)

exports.repl () =
    interface = readline.create interface (process.stdin, process.stdout)
    prompt = 'λ '

    interface.set prompt (prompt, prompt.length)
    interface.prompt ()

    interface.on 'line' @(line)
        evalute repl line (line)
        interface.prompt ()

    interface.on 'close'
        process.stdout.write "\n"
        process.exit 0

evalute repl line (line) =
    try
        result = exports.evaluate (line, global: true)
        console.log ' =>' (util.inspect (result, undefined, undefined, true))
    catch @(ex)
        console.log (ex.message)

compile from file (filename, ugly: false) =
    contents = fs.read file sync (filename) 'utf-8'
    exports.compile (contents, filename: filename, ugly: ugly)

source location printer (filename: nil, source: nil) =
    object =>
        self.lines in range (range) =
            lines = source.split r/\n/
            lines.slice (range.from - 1) (range.to)

        self.print lines in range (prefix: '', from: nil, to: nil) =
            for each @(line) in (self.lines in range (from: from, to: to))
                process.stderr.write (prefix + line + "\n")

        self.print location (location) =
            process.stderr.write (filename + ':' + location.first line + "\n")

            if (location.first line == location.last line)
                self.print lines in range (from: location.first line, to: location.last line)
                spaces = self.' ' times (location.first column)
                markers = self.'^' times (location.last column - location.first column)
                process.stderr.write (spaces + markers + "\n")
            else
                self.print lines in range (prefix: '> ', from: location.first line, to: location.last line)

        self.(s) times (n) =
            strings = []
            for (i = 0, i < n, i = i + 1)
                strings.push (s)

            strings.join ''

require.extensions.'.pogo' (module, filename) =
    exports.run file (filename) in module (module)

fs = require 'fs'
ms = require '../lib/memorystream'
parser = require './parser'
parse = parser.parse
uglify = require 'uglify-js'
errors = require './codeGenerator/errors'
_ = require 'underscore'
readline = require 'readline'
util = require 'util'
Module = require 'module'
path = require 'path'

generate code (term) =
    memory stream = new (ms.MemoryStream)
    term.generate java script (memory stream)
    memory stream.to string ()

beautify (code) =
    ast = uglify.parser.parse (code)
    uglify.uglify.gen_code (ast, beautify: true)

exports.compile file = compile file (filename, ugly: false) =
    js = compile from file (filename, ugly: ugly)

    js filename = js filename from pogo filename (filename)
    fs.write file sync (js filename, js)

when (filename) changes (act) =
    fs.watch file (filename) {persistent, interval 500} @(prev, curr)
        if ((curr.size == prev.size) && (curr.mtime.get time () == prev.mtime.get time ()))
            return

        act ()

exports.watch file (filename, options) =
    compile () =
        console.log "compiling #(filename) => #(js filename from pogo filename (filename))"
        compile file (filename, options)

    compile ()

    when (filename) changes
        compile ()

exports.lex file (filename) =
    source = fs.read file sync (filename) 'utf-8'
    tokens = parser.lex (source)

    for each @(token) in (tokens)
        text = (token.1 && "'#(token.1)'") || ''
        console.log "<#(token.0)> #(text)"

js filename from pogo filename (pogo) =
    pogo.replace `\.pogo$` '' + '.js'

exports.run file (filename) in module (module) =
    js = compile from file (filename)
    module._compile (js, filename)

exports.run main (filename) =
    full filename = fs.realpath sync (filename)

    process.argv.shift ()
    process.argv.0 = 'pogo'
    process.argv.1 = full filename

    module = new (Module (full filename, null))
    process.main module = module
    module.id = '.'
    module.filename = full filename
    module.paths = Module._node module paths (path.dirname (full filename))
    exports.run file (full filename) in module (module)
    module.loaded = true

exports.compile (pogo, filename: nil, in scope: true, ugly: false, global: false, return result: false) =
    module term = parse (pogo)
    module term.in scope = in scope
    module term.global = global
    module term.return result = return result

    code = generate code (module term)

    if (!ugly)
        code = beautify (code)

    if (errors.has errors ())
        errors.print errors (source location printer (filename: filename, source: pogo))
        process.exit 1
    else
        code

exports.evaluate (pogo, definitions: {}, global: false) =
    js = exports.compile (pogo, ugly: true, in scope: !global, global: global, return result: global)
    definition names = _.keys (definitions)

    parameters = definition names.join ','

    run script = new (Function (parameters, js))

    definition values = _.map (definition names) @(name)
        definitions.(name)

    run script.apply (undefined) (definition values)

exports.repl () =
    interface = readline.create interface (process.stdin, process.stdout)
    prompt = 'λ '

    interface.set prompt (prompt, prompt.length)
    interface.prompt ()

    interface.on 'line' @(line)
        evalute repl line (line)
        interface.prompt ()

    interface.on 'close'
        process.stdout.write "\n"
        process.exit 0

evalute repl line (line) =
    try
        result = exports.evaluate (line, global: true)
        console.log ' =>' (util.inspect (result, undefined, undefined, true))
    catch @(ex)
        console.log (ex.message)

compile from file (filename, ugly: false) =
    contents = fs.read file sync (filename) 'utf-8'
    exports.compile (contents, filename: filename, ugly: ugly)

source location printer (filename: nil, source: nil) =
    object =>
        self.lines in range (range) =
            lines = source.split `\n`
            lines.slice (range.from - 1) (range.to)

        self.print lines in range (prefix: '', from: nil, to: nil) =
            for each @(line) in (self.lines in range (from: from, to: to))
                process.stderr.write (prefix + line + "\n")

        self.print location (location) =
            process.stderr.write (filename + ':' + location.first line + "\n")

            if (location.first line == location.last line)
                self.print lines in range; from (location.first line); to (location.last line)
                spaces = self.' ' times (location.first column)
                markers = self.'^' times (location.last column - location.first column)
                process.stderr.write (spaces + markers + "\n")
            else
                self.print lines in range; prefix '> '; from (location.first line); to (location.last line)

        self.(s) times (n) =
            strings = []
            for (i = 0, i < n, i = i + 1)
                strings.push (s)

            strings.join ''

require.extensions.'.pogo' (module, filename) =
    exports.run file (filename) in module (module)


fixed typo

fixed typo

connect to (port: 3306, host: "127.0.0.1") =
  console.log "connecting to #(host):#(port)"

connect to (port: 3306, host: "127.0.0.1") =
  console.log "connecting to #(host):#(part)"


fix cli args bug

fix cli args bug

default port = 1337

(arg) as port =
    parse int(arg) || default port

(arg) as host =
    if ((arg) is a url) @{ arg } else @{ "http://127.0.0.1:#(arg)" }

(arg) is a url =
    arg.to string().index of ("http") == 0

cli = {

    server (args) =
        port = (args.shift()) as port
        require './cli_server'.run server(port)

    agent (args) =
        host = (args.shift()) as host
        require './cli_agent'.run agent(host)

    enqueue (args) =
        host = (args.shift()) as host
        require './cli_enqueue'.enqueue(host, args)
}

exports.run (args) =
    service = args.shift()
    cli.(service).call(self, args)

default port = 1337

exports.run (args) =
    service = args.shift()
    port = parse int(args.shift()) || default port
    host = if (port.to string().index of "http" != 0) @{ "http://127.0.0.1:#(port)" } else @{ port }

    if (service == 'server')
        require './cli_server'.run server(port)

    if (service == 'agent')
        require './cli_agent'.run agent(host)

    if (service == 'enqueue')
        require './cli_enqueue'.enqueue(host, args)


beer bottles submission, prints proper lyrics

sing (n) bottles of beer on the wall =
    if (n > 0)
        console.log "#((n) bottles) of beer on the wall, #((n) bottles) of beer.
                     Take one down and pass it around, #((n - 1) bottles) of beer on the wall."
        sing (n - 1) bottles of beer on the wall
    else if (n == 0)
        console.log "No more bottles of beer on the wall, no more bottles of beer.
                     Go to the store and buy some more, 99 bottles of beer on the wall."

(n) bottles =
    if (n == 0)
        "no more bottles"
    else if (n == 1)
        "1 bottle"
    else
        "#(n) bottles"

sing 99 bottles of beer on the wall

sing (n) bottles of beer on the wall =
    if (n > 0)
        console.log ((n) bottles of beer on the wall)
        sing (n - 1) bottles of beer on the wall

(n) bottles of beer on the wall =
    "#((n) bottles) of beer on the wall, #((n) bottles) of beer on the wall
     take one down, pass it around, #((n - 1) bottles) of beer on the wall."

(n) bottles =
    if (n == 0)
        "no bottles"
    else if (n == 1)
        "1 bottle"
    else
        "#(n) bottles"

sing 99 bottles of beer on the wall


improved sample for with expression

improved sample for with expression

things = {}

merge (traits) into (thing) =
  for each @(trait) in (traits)
    for @(attr) in (trait) @ { thing.(attr) = trait.(attr) }

spec = {

  describe (thing) as (traits) = merge (traits) into (things.(thing) = {})

  made of (stuff) = { material = stuff }

  solid material = { breakable = false }

  (direction) orientation = { orientation = direction }

}

with (spec)

  describe 'wall' as [

    made of (solid material)

    'vertical' orientation

  ]

console.log (things)

// { wall: { material: { breakable: false }, orientation: 'vertical' } }

things = []

specification = {

  describe (thing) as (attributes) = things.push [thing, attributes]

  made of (stuff) = { material = stuff }

  solid material = { breakable = false }

  (name) orientation = { orientation = name }

}

with (specification)

  describe 'wall' as [

    made of (solid material)

    'vertical' orientation

  ]


extending prototype test

extending prototype test

require 'chai'.should()

describe 'prototypes'
  it 'can create a prototype'
    a = {
      base = 'base'
      overridden = 'a'
    }

    p = prototype (a)

    b = p {
      overridden = 'b'
      derived = 'derived'
    }

    b.base.should.equal 'base'
    b.overridden.should.equal 'b'
    b.derived.should.equal 'derived'
    Object.getPrototypeOf(b).should.equal(a)

  it 'properties are shared between derived objects'
    array = [1, 2, 3]

    a = prototype {
      array = array
    }

    b = a()
    c = a()

    b.array.should.equal (array)
    c.array.should.equal (array)
    b.should.not.equal (c)

  it 'prototype can extend another prototype'
    array = [1, 2, 3]

    a = prototype {
      a = true
      name = 'a'
    }

    b = prototypeExtending (a) {
      b = true
      name = 'b'
    }

    objectA = a()
    objectB = b()

    objectA.a.should.equal (true)
    objectA.name.should.equal 'a'
    (objectA :: a).should.equal(true)

    objectB.a.should.equal (true)
    objectB.b.should.equal (true)
    objectB.name.should.equal 'b'
    (objectB :: a).should.equal(true)
    (objectB :: b).should.equal(true)

  it 'a prototype can be extended after creation'
    a = prototype {
      a = 'a'
    }

    a.prototype.b = 'b'

    c = a {
      c = 'c'
    }

    c.a.should.equal 'a'
    c.b.should.equal 'b'
    c.c.should.equal 'c'

  it 'prototype is a function'
    (prototype :: Function).should.equal (true)

  it 'prototypeExtending is a function'
    (prototypeExtending :: Function).should.equal (true)

require 'chai'.should()

describe 'prototypes'
  it 'can create a prototype'
    a = {
      base = 'base'
      overridden = 'a'
    }

    p = prototype (a)

    b = p {
      overridden = 'b'
      derived = 'derived'
    }

    b.base.should.equal 'base'
    b.overridden.should.equal 'b'
    b.derived.should.equal 'derived'
    Object.getPrototypeOf(b).should.equal(a)

  it 'properties are shared between derived objects'
    array = [1, 2, 3]

    a = prototype {
      array = array
    }

    b = a()
    c = a()

    b.array.should.equal (array)
    c.array.should.equal (array)
    b.should.not.equal (c)

  it 'prototype can extend another prototype'
    array = [1, 2, 3]

    a = prototype {
      a = true
      name = 'a'
    }

    b = prototypeExtending (a) {
      b = true
      name = 'b'
    }

    objectA = a()
    objectB = b()

    objectA.a.should.equal (true)
    objectA.name.should.equal 'a'
    (objectA :: a).should.equal(true)

    objectB.a.should.equal (true)
    objectB.b.should.equal (true)
    objectB.name.should.equal 'b'
    (objectB :: a).should.equal(true)
    (objectB :: b).should.equal(true)

  it 'prototype is a function'
    (prototype :: Function).should.equal (true)

  it 'prototypeExtending is a function'
    (prototypeExtending :: Function).should.equal (true)


better output for mongodb.pogo

better output for mongodb.pogo

mongodb = require 'mongodb'
assert = require 'assert'

server (address: '127.0.0.1', port: 27017) =
    new (mongodb.Server (address, port))

db (name: nil, svr: server()) =
    new (mongodb.Db (name, svr))

test db = db (name: 'test')

test (err, collection) =
    collection.remove
        console.log "inserting" {a 2}
        collection.insert {a 2} @(err, docs)
            collection.count @(err, count)
                console.log "document count: #(count)"

            console.log "searching"
            collection.find().to array @(err, results)
                console.log "found #(results.length) documents"
                console.log "document:" (results.0)

                test db.close()

test db.open
    test db.collection 'test_insert' (test)

mongodb = require 'mongodb'
assert = require 'assert'

server (address: '127.0.0.1', port: 27017) =
    new (mongodb.Server (address, port))

db (name: nil, server: server()) =
    new (mongodb.Db (name, server))

test db = db (name: 'test')

test (err, collection) =
    collection.remove
        collection.insert {a 2} @(err, docs)
            collection.count @(err, count)
                console.log (count)

            collection.find().to array @(err, results)
                console.log (results.length)
                console.log (results.0.a)

                test db.close()

test db.open
    test db.collection 'test_insert' (test)


updated continuation example

updated continuation example

current continuation! () =
    cont () =
        continuation (nil, cont)

    continuation (nil, cont)

n = 0

cont = current continuation!

console.log (n)
++n

if (n < 10)
    cont ()

current continuation (callback) =
    continuation () =
        callback (nil, continuation)

    callback (nil, continuation)

n = 0

cont = current continuation!

console.log (n)
++n

if (n < 10)
    cont ()


formatting

formatting

identifier pattern = '[a-zA-Z_$][a-zA-Z_$0-9]*'
comment pattern = '(/\*([^*](\*[^/]|))*(\*/|$)|//[^\n]*)'

exports: grammar = {
    lex {
        start conditions {interpolated_string, interpolated_string_terminal}

        rules [
            [' +', '/* ignore whitespace */']
            ['\s*$', 'return yy.eof();']
            ['\s*((/\*([^*](\*[^/]|))*(\*/|$)|//[^\n]*)\s*)+', 'var indentation = yy.indentation(yytext); if (indentation) { return indentation; }']
            ['\(\s*', 'yy.setIndentation(yytext); if (yy.terms.interpolation.interpolating()) {yy.terms.interpolation.openBracket()} return "(";']
            ['\s*\)', 'if (yy.terms.interpolation.interpolating()) {yy.terms.interpolation.closeBracket(); if (yy.terms.interpolation.finishedInterpolation()) {this.popState(); this.popState(); yy.terms.interpolation.stopInterpolation()}} return yy.unsetIndentation('')'');']
            ['{\s*', 'yy.setIndentation(yytext); return ''{'';']
            ['\s*}', 'return yy.unsetIndentation(''}'');']
            ['\[\s*', 'yy.setIndentation(yytext); return ''['';']
            ['\s*\]', 'return yy.unsetIndentation('']'')']
            ['(\n *)*\n *', 'return yy.indentation(yytext);']
            ['[0-9]+\.[0-9]+', 'return ''float'';']
            ['[0-9]+', 'return ''integer'';']
            ['([:;=,?!.@~#%^&*+<>/?\\|-])+', 'return yy.terms.lexOperator(yytext);']
            [identifier pattern, 'return ''identifier'';']
            ['$', 'return ''eof'';']
            ['''([^'']*'''')*[^'']*''', 'return ''string'';']
            ['`([^\\]*\\`)*[^`]*`(img|mgi|gim|igm|gmi|mig|im|ig|gm|mg|mi|gi|i|m|g|)', 'return ''reg_exp'';']
            ['"', 'this.begin(''interpolated_string''); return ''start_interpolated_string'';']

            [['interpolated_string'], '\\@', 'return ''escaped_interpolated_string_terminal_start'';']
            [['interpolated_string'], '@', 'this.begin(''interpolated_string_terminal''); return ''interpolated_string_terminal_start'';']
            [['interpolated_string_terminal'], identifier pattern, 'this.popState(); return ''identifier'';']
            [['interpolated_string_terminal'], '\(', 'yy.setIndentation(yytext); yy.terms.interpolation.startInterpolation(); this.begin(''INITIAL''); return ''('';']
            [['interpolated_string'], '"', 'this.popState(); return ''end_interpolated_string'';']
            [['interpolated_string'], '\\.', 'return ''escape_sequence'';']
            [['interpolated_string'], '[^"@\\]*', 'return ''interpolated_string_body'';']

            ['.', 'return ''non_token'';']
        ]
    }

    operators [
        ['right', '=']
        ['left', ':']
    ]

    start 'module'

    bnf {
        module [
            ['statements eof', 'return yy.terms.module($1);']
        ]
        statements [
            ['statements_list', '$$ = yy.terms.statements($1);']
        ]
        hash_entries [
            ['hash_entries comma_dot expression', '$1.push($3.hashEntry()); $$ = $1;']
            ['expression', '$$ = [$1.hashEntry()];']
            ['', '$$ = [];']
        ]
        comma_dot [
            ['.', '$$ = $1;']
            [',', '$$ = $1;']
        ]
        statements_list [
            ['statements_list comma_dot statement', '$1.push($3); $$ = $1;']
            ['statement', '$$ = [$1];']
            ['', '$$ = [];']
        ]
        arguments_list [
            ['arguments_list , expression_list', '$1.push($3); $$ = $1;']
            ['expression_list', '$$ = [$1];']
            ['', '$$ = [];']
        ]
        parameter_list [
            ['parameter_list , statement', '$1.push($3); $$ = $1;']
            ['statement', '$$ = [$1];']
        ]
        expression_list [
            ['expression_list . statement', '$1.push($3); $$ = $1;']
            ['statement', '$$ = [$1];']
        ]
        list_statements_list [
            ['list_statements_list comma_dot list_statement', '$1.push($3); $$ = $1;']
            ['list_statement', '$$ = [$1];']
            ['', '$$ = [];']
        ]
        statement [
            ['expression', '$$ = $1.expression();']
        ]
        list_statement [
            ['list_expression', '$$ = $1.expression();']
        ]
        expression [
            ['expression = expression', '$$ = $1.definition($3.expression());']
            ['operator_expression', '$$ = $1;']
        ]
        list_expression [
            ['list_expression = list_expression', '$$ = $1.definition($3.expression());']
            ['list_operator_expression', '$$ = $1;']
        ]
        operator_with_newline [
            ['operator .', '$$ = $1']
            ['operator', '$$ = $1']
        ]
        operator_expression [
            ['operator_expression operator_with_newline unary_operator_expression', '$1.addOperatorExpression($2, $3); $$ = $1;']
            ['unary_operator_expression', '$$ = yy.terms.operatorExpression($1);']
        ]
        list_operator_expression [
            ['list_operator_expression operator_with_newline list_unary_operator_expression', '$1.addOperatorExpression($2, $3); $$ = $1;']
            ['list_unary_operator_expression', '$$ = yy.terms.operatorExpression($1);']
        ]
        unary_operator_expression [
            ['object_operation', '$$ = $1;']
            ['unary_operator object_operation', '$$ = yy.terms.newUnaryOperatorExpression({operator: $1, expression: $2.expression()});']
        ]
        list_unary_operator_expression [
            ['list_object_operation', '$$ = $1;']
            ['unary_operator list_object_operation', '$$ = yy.terms.newUnaryOperatorExpression({operator: $1, expression: $2.expression()});']
        ]
        object_reference_with_newline [
            [': .', '$$ = $1']
            [':', '$$ = $1']
        ]
        object_operation [
            ['object_operation object_reference_with_newline complex_expression', '$$ = $3.objectOperation($1.expression());']
            [': complex_expression', '$$ = $2.objectOperation(yy.terms.selfExpression());']
            ['complex_expression', '$$ = $1;']
        ]
        list_object_operation [
            ['list_object_operation object_reference_with_newline list_complex_expression', '$$ = $3.objectOperation($1.expression());']
            [': list_complex_expression', '$$ = $2.objectOperation(yy.terms.selfExpression());']
            ['list_complex_expression', '$$ = $1;']
        ]
        complex_expression [
            ['basic_expression_list', '$$ = yy.terms.complexExpression($1);']
        ]
        list_complex_expression [
            ['list_basic_expression', '$$ = yy.terms.complexExpression($1);']
        ]
        basic_expression_list [
            ['basic_expression_list ; terminal_list', '$1.push($3); $$ = $1;']
            ['terminal_list_no_arg', '$$ = [$1];']
        ]
        list_basic_expression [
            ['terminal_list_no_arg', '$$ = [$1];']
        ]
        terminal_list_no_arg [
            ['terminal_list no_arg_punctuation', '$1.push($2); $$ = $1;']
            ['terminal_list', '$$ = $1;']
        ]
        basic_expression [
            ['terminal_list', '$$ = yy.terms.basicExpression($1);']
        ]
        no_arg_punctuation [
            ['no_arg', '$$ = yy.terms.loc(yy.terms.noArgSuffix(), @$);']
        ]
        no_arg [
            ['!', '$$ = $1;']
            ['?', '$$ = $1;']
        ]
        terminal_list [
            ['terminal_list terminal', '$1.push($2); $$ = $1;']
            ['terminal', '$$ = [$1];']
        ]
        terminal [
            ['( arguments_list )', '$$ = yy.terms.loc(yy.terms.argumentList(yy.terms.normaliseArguments($2)), @$);']
            ['@ ( parameter_list )', '$$ = yy.terms.loc(yy.terms.parameters($3), @$);']
            ['block_start statements }', '$$ = yy.terms.loc(yy.terms.block([], $2), @$);']
            ['=> block_start statements }', '$$ = yy.terms.loc(yy.terms.block([], $3, {redefinesSelf: true}), @$);']
            ['[ statements_list ]', '$$ = yy.terms.loc(yy.terms.list($2), @$);']
            ['{ hash_entries }', '$$ = yy.terms.loc(yy.terms.hash($2), @$);']
            ['float', '$$ = yy.terms.loc(yy.terms.float(parseFloat(yytext)), @$);']
            ['integer', '$$ = yy.terms.loc(yy.terms.integer(parseInt(yytext)), @$);']
            ['identifier', '$$ = yy.terms.loc(yy.terms.identifier(yytext), @$);']
            ['string', '$$ = yy.terms.loc(yy.terms.string(yy.terms.unindent(@$.first_column + 1, yy.terms.normaliseString(yytext))), @$);']
            ['reg_exp', '$$ = yy.terms.loc(yy.terms.regExp(yy.terms.parseRegExp(yy.terms.unindent(@$.first_column + 1, yytext))), @$);']
            ['interpolated_string', '$$ = yy.terms.loc($1, @$);']
            ['...', '$$ = yy.terms.loc(yy.terms.splat(), @$);']
        ]
        block_start [
            ['@ {', '$$ = ''@{''']
            ['@{', '$$ = ''@{''']
        ]
        unary_operator [
            ['operator', '$$ = $1;']
            ['!', '$$ = $1;']
        ]
        interpolated_terminal [
            ['( statement )', '$$ = $2;']
            ['identifier', '$$ = yy.terms.variable([$1]);']
        ]
        interpolated_string [
            ['start_interpolated_string interpolated_string_components end_interpolated_string', '$$ = yy.terms.interpolatedString($2, @$.first_column);']
            ['start_interpolated_string end_interpolated_string', '$$ = yy.terms.interpolatedString([], @$.first_column);']
        ]
        interpolated_string_components [
            ['interpolated_string_components interpolated_string_component', '$1.push($2); $$ = $1;']
            ['interpolated_string_component', '$$ = [$1];']
        ]
        interpolated_string_component [
            ['interpolated_string_terminal_start interpolated_terminal', '$$ = $2;']
            ['interpolated_string_body', '$$ = yy.terms.string($1);']
            ['escaped_interpolated_string_terminal_start', '$$ = yy.terms.string("@");']
            ['escape_sequence', '$$ = yy.terms.string(yy.terms.normaliseInterpolatedString($1));']
        ]
    }
}

identifier pattern = '[a-zA-Z_$][a-zA-Z_$0-9]*'
comment pattern = '(/\*([^*](\*[^/]|))*(\*/|$)|//[^\n]*)'

exports: grammar = {
    lex {
        start conditions {interpolated_string, interpolated_string_terminal}

        rules [
            [' +'. '/* ignore whitespace */']
            ['\s*$'. 'return yy.eof();']
            ['\s*((/\*([^*](\*[^/]|))*(\*/|$)|//[^\n]*)\s*)+'. 'var indentation = yy.indentation(yytext); if (indentation) { return indentation; }']
            ['\(\s*'. 'yy.setIndentation(yytext); if (yy.terms.interpolation.interpolating()) {yy.terms.interpolation.openBracket()} return "(";']
            ['\s*\)'. 'if (yy.terms.interpolation.interpolating()) {yy.terms.interpolation.closeBracket(); if (yy.terms.interpolation.finishedInterpolation()) {this.popState(); this.popState(); yy.terms.interpolation.stopInterpolation()}} return yy.unsetIndentation('')'');']
            ['{\s*'. 'yy.setIndentation(yytext); return ''{'';']
            ['\s*}'. 'return yy.unsetIndentation(''}'');']
            ['\[\s*'. 'yy.setIndentation(yytext); return ''['';']
            ['\s*\]'. 'return yy.unsetIndentation('']'')']
            ['(\n *)*\n *'. 'return yy.indentation(yytext);']
            ['[0-9]+\.[0-9]+'. 'return ''float'';']
            ['[0-9]+'. 'return ''integer'';']
            ['([:;=,?!.@~#%^&*+<>/?\\|-])+'. 'return yy.terms.lexOperator(yytext);']
            [identifier pattern. 'return ''identifier'';']
            ['$'. 'return ''eof'';']
            ['''([^'']*'''')*[^'']*'''. 'return ''string'';']
            ['`([^\\]*\\`)*[^`]*`(img|mgi|gim|igm|gmi|mig|im|ig|gm|mg|mi|gi|i|m|g|)'. 'return ''reg_exp'';']
            ['"'. 'this.begin(''interpolated_string''); return ''start_interpolated_string'';']

            [['interpolated_string']. '\\@'. 'return ''escaped_interpolated_string_terminal_start'';']
            [['interpolated_string']. '@'. 'this.begin(''interpolated_string_terminal''); return ''interpolated_string_terminal_start'';']
            [['interpolated_string_terminal']. identifier pattern. 'this.popState(); return ''identifier'';']
            [['interpolated_string_terminal']. '\('. 'yy.setIndentation(yytext); yy.terms.interpolation.startInterpolation(); this.begin(''INITIAL''); return ''('';']
            [['interpolated_string']. '"'. 'this.popState(); return ''end_interpolated_string'';']
            [['interpolated_string']. '\\.'. 'return ''escape_sequence'';']
            [['interpolated_string']. '[^"@\\]*'. 'return ''interpolated_string_body'';']

            ['.'. 'return ''non_token'';']
        ]
    }

    operators [
        ['right'. '=']
        ['left'. ':']
    ]

    start 'module'

    bnf {
        module [
            ['statements eof'. 'return yy.terms.module($1);']
        ]
        statements [
            ['statements_list'. '$$ = yy.terms.statements($1);']
        ]
        hash_entries [
            ['hash_entries comma_dot expression'. '$1.push($3.hashEntry()); $$ = $1;']
            ['expression'. '$$ = [$1.hashEntry()];']
            [''. '$$ = [];']
        ]
        comma_dot [
            ['.'. '$$ = $1;']
            [','. '$$ = $1;']
        ]
        statements_list [
            ['statements_list comma_dot statement'. '$1.push($3); $$ = $1;']
            ['statement'. '$$ = [$1];']
            [''. '$$ = [];']
        ]
        arguments_list [
            ['arguments_list , expression_list'. '$1.push($3); $$ = $1;']
            ['expression_list'. '$$ = [$1];']
            [''. '$$ = [];']
        ]
        parameter_list [
            ['parameter_list , statement'. '$1.push($3); $$ = $1;']
            ['statement'. '$$ = [$1];']
        ]
        expression_list [
            ['expression_list . statement'. '$1.push($3); $$ = $1;']
            ['statement'. '$$ = [$1];']
        ]
        list_statements_list [
            ['list_statements_list comma_dot list_statement'. '$1.push($3); $$ = $1;']
            ['list_statement'. '$$ = [$1];']
            [''. '$$ = [];']
        ]
        statement [
            ['expression'. '$$ = $1.expression();']
        ]
        list_statement [
            ['list_expression'. '$$ = $1.expression();']
        ]
        expression [
            ['expression = expression'. '$$ = $1.definition($3.expression());']
            ['operator_expression'. '$$ = $1;']
        ]
        list_expression [
            ['list_expression = list_expression'. '$$ = $1.definition($3.expression());']
            ['list_operator_expression'. '$$ = $1;']
        ]
        operator_with_newline [
            ['operator .'. '$$ = $1']
            ['operator'. '$$ = $1']
        ]
        operator_expression [
            ['operator_expression operator_with_newline unary_operator_expression'. '$1.addOperatorExpression($2, $3); $$ = $1;']
            ['unary_operator_expression'. '$$ = yy.terms.operatorExpression($1);']
        ]
        list_operator_expression [
            ['list_operator_expression operator_with_newline list_unary_operator_expression'. '$1.addOperatorExpression($2, $3); $$ = $1;']
            ['list_unary_operator_expression'. '$$ = yy.terms.operatorExpression($1);']
        ]
        unary_operator_expression [
            ['object_operation'. '$$ = $1;']
            ['unary_operator object_operation'. '$$ = yy.terms.newUnaryOperatorExpression({operator: $1, expression: $2.expression()});']
        ]
        list_unary_operator_expression [
            ['list_object_operation'. '$$ = $1;']
            ['unary_operator list_object_operation'. '$$ = yy.terms.newUnaryOperatorExpression({operator: $1, expression: $2.expression()});']
        ]
        object_reference_with_newline [
            [': .'. '$$ = $1']
            [':'. '$$ = $1']
        ]
        object_operation [
            ['object_operation object_reference_with_newline complex_expression'. '$$ = $3.objectOperation($1.expression());']
            [': complex_expression'. '$$ = $2.objectOperation(yy.terms.selfExpression());']
            ['complex_expression'. '$$ = $1;']
        ]
        list_object_operation [
            ['list_object_operation object_reference_with_newline list_complex_expression'. '$$ = $3.objectOperation($1.expression());']
            [': list_complex_expression'. '$$ = $2.objectOperation(yy.terms.selfExpression());']
            ['list_complex_expression'. '$$ = $1;']
        ]
        complex_expression [
            ['basic_expression_list'. '$$ = yy.terms.complexExpression($1);']
        ]
        list_complex_expression [
            ['list_basic_expression'. '$$ = yy.terms.complexExpression($1);']
        ]
        basic_expression_list [
            ['basic_expression_list ; terminal_list'. '$1.push($3); $$ = $1;']
            ['terminal_list_no_arg'. '$$ = [$1];']
        ]
        list_basic_expression [
            ['terminal_list_no_arg'. '$$ = [$1];']
        ]
        terminal_list_no_arg [
            ['terminal_list no_arg_punctuation'. '$1.push($2); $$ = $1;']
            ['terminal_list'. '$$ = $1;']
        ]
        basic_expression [
            ['terminal_list'. '$$ = yy.terms.basicExpression($1);']
        ]
        no_arg_punctuation [
            ['no_arg'. '$$ = yy.terms.loc(yy.terms.noArgSuffix(), @$);']
        ]
        no_arg [
            ['!'. '$$ = $1;']
            ['?'. '$$ = $1;']
        ]
        terminal_list [
            ['terminal_list terminal'. '$1.push($2); $$ = $1;']
            ['terminal'. '$$ = [$1];']
        ]
        terminal [
            ['( arguments_list )'. '$$ = yy.terms.loc(yy.terms.argumentList(yy.terms.normaliseArguments($2)), @$);']
            ['@ ( parameter_list )'. '$$ = yy.terms.loc(yy.terms.parameters($3), @$);']
            ['block_start statements }'. '$$ = yy.terms.loc(yy.terms.block([], $2), @$);']
            ['=> block_start statements }'. '$$ = yy.terms.loc(yy.terms.block([], $3, {redefinesSelf: true}), @$);']
            ['[ statements_list ]'. '$$ = yy.terms.loc(yy.terms.list($2), @$);']
            ['{ hash_entries }'. '$$ = yy.terms.loc(yy.terms.hash($2), @$);']
            ['float'. '$$ = yy.terms.loc(yy.terms.float(parseFloat(yytext)), @$);']
            ['integer'. '$$ = yy.terms.loc(yy.terms.integer(parseInt(yytext)), @$);']
            ['identifier'. '$$ = yy.terms.loc(yy.terms.identifier(yytext), @$);']
            ['string'. '$$ = yy.terms.loc(yy.terms.string(yy.terms.unindent(@$.first_column + 1, yy.terms.normaliseString(yytext))), @$);']
            ['reg_exp'. '$$ = yy.terms.loc(yy.terms.regExp(yy.terms.parseRegExp(yy.terms.unindent(@$.first_column + 1, yytext))), @$);']
            ['interpolated_string'. '$$ = yy.terms.loc($1, @$);']
            ['...'. '$$ = yy.terms.loc(yy.terms.splat(), @$);']
        ]
        block_start [
            ['@ {'. '$$ = ''@{''']
            ['@{'. '$$ = ''@{''']
        ]
        unary_operator [
            ['operator'. '$$ = $1;']
            ['!'. '$$ = $1;']
        ]
        interpolated_terminal [
            ['( statement )'. '$$ = $2;']
            ['identifier'. '$$ = yy.terms.variable([$1]);']
        ]
        interpolated_string [
            ['start_interpolated_string interpolated_string_components end_interpolated_string'. '$$ = yy.terms.interpolatedString($2, @$.first_column);']
            ['start_interpolated_string end_interpolated_string'. '$$ = yy.terms.interpolatedString([], @$.first_column);']
        ]
        interpolated_string_components [
            ['interpolated_string_components interpolated_string_component'. '$1.push($2); $$ = $1;']
            ['interpolated_string_component'. '$$ = [$1];']
        ]
        interpolated_string_component [
            ['interpolated_string_terminal_start interpolated_terminal'. '$$ = $2;']
            ['interpolated_string_body'. '$$ = yy.terms.string($1);']
            ['escaped_interpolated_string_terminal_start'. '$$ = yy.terms.string("@");']
            ['escape_sequence'. '$$ = yy.terms.string(yy.terms.normaliseInterpolatedString($1));']
        ]
    }
}


refactoring

refactoring

jison parser = require 'jison':Parser
terms = require './codeGenerator/codeGenerator'
ms = require '../lib/memorystream'

create parser with grammar @grammar =
    new (jison parser @grammar)

identifier pattern = '[a-zA-Z_$][a-zA-Z_$0-9]*'

grammar = #
    lex #
        start conditions #{interpolated_string, interpolated_string_terminal}

        rules [
            ['\\s+'. '/* ignore whitespace */']
            ['[0-9]+\\.[0-9]+'. 'return ''float'';']
            ['[0-9]+'. 'return ''integer'';']
            ['@' + identifier pattern. 'return ''argument'';']
            ['@:' + identifier pattern. 'return ''self_argument'';']
            ['\\?' + identifier pattern. 'return ''parameter'';']
            [identifier pattern. 'return ''identifier'';']
            ['\\??\\('. 'if (yy.interpolation.interpolating()) {yy.interpolation.openBracket()} return yytext;']
            ['\\)'. 'if (yy.interpolation.interpolating()) {yy.interpolation.closeBracket(); if (yy.interpolation.finishedInterpolation()) {this.popState(); this.popState(); yy.interpolation.stopInterpolation()}} return '')'';']
            ['{'. 'return ''{'';']
            ['}'. 'return ''}'';']
            ['\\['. 'return ''['';']
            ['\\]'. 'return '']'';']
            ['\\\\[.]'. 'return yytext.substring(1);']
            ['\\\\@[{]'. 'if (!yy.stringBrackets) {return yytext.substring(1);} else {++yy.stringBrackets;}']
            ['\\\\[}]'. 'if (!yy.stringBrackets) {return yytext.substring(1);} else {--yy.stringBrackets;}']
            ['\\.\\.\\.'. 'return ''...''']
            ['([:=,?!.@`~#$%^&*+<>/?|-]|\\\\\\\\)+'. 'return yy.lexOperator(yytext);']
            ['$'. 'return ''eof'';']
            ['''([^'']*'''')*[^'']*'''. 'return ''string'';']
            ['"'. 'this.begin(''interpolated_string''); return ''start_interpolated_string'';']
            [['interpolated_string']. '@'. 'this.begin(''interpolated_string_terminal''); return ''interpolated_string_terminal_start'';']
            [['interpolated_string_terminal']. identifier pattern. 'this.popState(); return ''identifier'';']
            [['interpolated_string_terminal']. '\\('. 'yy.interpolation.startInterpolation(); this.begin(''INITIAL''); return ''('';']
            [['interpolated_string']. '"'. 'this.popState(); return ''end_interpolated_string'';']
            [['interpolated_string']. '\\\\[.]'. '/* ignore */']
            [['interpolated_string']. '\\\\[{]'. 'yy.stringBrackets++']
            [['interpolated_string']. '\\\\[}]'. 'yy.stringBrackets--;']
            [['interpolated_string']. '\\\\\\\\\\\\\\\\'. 'return ''escaped_escape_interpolated_string_body'';']
            [['interpolated_string']. '\\\\\\\\.'. 'return ''escaped_interpolated_string_body'';']
            [['interpolated_string']. '[^"@\\\\]*'. 'return ''interpolated_string_body'';']
            ['.'. 'return ''non_token'';']
        ]

    operators [
        ['right'. '=']
        ['left'. ':']
    ]

    start 'module'

    bnf #
        module [
            ['statements eof'. 'return yy.module($1);']
        ]
        statements [
            ['statements_list'. '$$ = yy.statements($1);']
        ]
        hash_entries [
            ['hash_entries comma_dot basic_expression'. '$1.push($3.hashEntry()); $$ = $1;']
            ['basic_expression'. '$$ = [$1.hashEntry()];']
            [''. '$$ = [];']
        ]
        comma_dot [
            ['.'. '$$ = $1;']
            [','. '$$ = $1;']
        ]
        statements_list [
            ['statements_list . statement'. '$1.push($3); $$ = $1;']
            ['statement'. '$$ = [$1];']
            [''. '$$ = [];']
        ]
        statement [
            ['expression'. '$$ = $1.expression();']
        ]
        expression [
            ['expression = expression'. '$$ = $1.definition($3.expression());']
            ['operator_expression'. '$$ = $1;']
        ]
        operator_expression [
            ['operator_expression operator unary_operator_expression'. '$1.addOperatorExpression($2, $3); $$ = $1;']
            ['unary_operator_expression'. '$$ = yy.operatorExpression($1);']
        ]
        unary_operator_expression [
            ['object_operation'. '$$ = $1;']
            ['unary_operator object_operation'. '$$ = yy.newUnaryOperatorExpression({operator: $1, expression: $2.expression()});']
        ]
        object_operation [
            ['object_operation : complex_expression'. '$$ = $3.objectOperation($1.expression());']
            [': complex_expression'. '$$ = $2.objectOperation(yy.selfExpression());']
            ['complex_expression'. '$$ = $1;']
        ]
        complex_expression [
            ['basic_expression_list'. '$$ = yy.complexExpression($1);']
        ]
        basic_expression_list [
            ['basic_expression_list , terminal_list'. '$1.push($3); $$ = $1;']
            ['terminal_list_no_arg'. '$$ = [$1];']
        ]
        terminal_list_no_arg [
            ['terminal_list no_arg_punctuation'. '$1.push($2); $$ = $1;']
            ['terminal_list'. '$$ = $1;']
        ]
        basic_expression [
            ['terminal_list'. '$$ = yy.basicExpression($1);']
        ]
        no_arg_punctuation [
            ['no_arg'. '$$ = yy.loc(yy.noArgSuffix(), @$);']
        ]
        no_arg [
            ['!'. '$$ = $1;']
            ['?'. '$$ = $1;']
        ]
        terminal_list [
            ['terminal_list terminal'. '$1.push($2); $$ = $1;']
            ['terminal'. '$$ = [$1];']
        ]
        terminal [
            ['( statement )'. '$$ = $2;']
            ['?( statement )'. '$$ = yy.parameter($2);']
            ['block_start statements }'. '$$ = yy.loc(yy.block([], $2), @$);']
            ['=> { statements }'. '$$ = yy.loc(yy.block([], $3, {redefinesSelf: true}), @$);']
            ['[ statements_list ]'. '$$ = yy.loc(yy.list($2), @$);']
            ['{ hash_entries }'. '$$ = yy.loc(yy.hash($2), @$);']
            ['float'. '$$ = yy.loc(yy.float(parseFloat(yytext)), @$);']
            ['integer'. '$$ = yy.loc(yy.integer(parseInt(yytext)), @$);']
            ['identifier'. '$$ = yy.loc(yy.identifier(yytext), @$);']
            ['argument'. '$$ = yy.loc(yy.variable([yytext.substring(1)]), @$);']
            ['self_argument'. '$$ = yy.loc(yy.fieldReference(yy.variable([''self'']), [yytext.substring(2)]), @$);']
            ['parameter'. '$$ = yy.loc(yy.parameter(yy.variable([yytext.substring(1)])), @$);']
            ['string'. '$$ = yy.loc(yy.string(yy.normaliseString(yytext)), @$);']
            ['interpolated_string'. '$$ = yy.loc($1, @$);']
            ['...'. '$$ = yy.loc(yy.splat(), @$);']
        ]
        block_start [
            ['@ {'. '$$ = ''@{''']
            ['@{'. '$$ = ''@{''']
        ]
        operator [
            ['raw_operator'. '$$ = yy.normaliseOperator(yytext);']
        ]
        unary_operator [
            ['operator'. '$$ = $1;']
            ['!'. '$$ = $1;']
        ]
        interpolated_terminal [
            ['( statement )'. '$$ = $2;']
            ['identifier'. '$$ = yy.variable([$1]);']
        ]
        interpolated_string [
            ['start_interpolated_string interpolated_string_components end_interpolated_string'. '$$ = yy.interpolatedString($2);']
            ['start_interpolated_string end_interpolated_string'. '$$ = yy.interpolatedString([]);']
        ]
        interpolated_string_components [
            ['interpolated_string_components interpolated_string_component'. '$1.push($2); $$ = $1;']
            ['interpolated_string_component'. '$$ = [$1];']
        ]
        interpolated_string_component [
            ['interpolated_string_terminal_start interpolated_terminal'. '$$ = $2;']
            ['interpolated_string_body'. '$$ = yy.string($1);']
            ['escaped_interpolated_string_body'. '$$ = yy.string(yy.normaliseInterpolatedString($1.substring(1)));']
            ['escaped_escape_interpolated_string_body'. '$$ = yy.string($1.substring(3));']
        ]

exports: parser = parser = create parser with grammar @grammar
parser: yy = terms

exports: parse @source = parser: parse @source

jison parser = require 'jison':Parser
terms = require './codeGenerator/codeGenerator'
ms = require '../lib/memorystream'

create parser with grammar @grammar =
    new (jison parser @grammar)

identifier pattern = '[a-zA-Z_$][a-zA-Z_$0-9]*'

grammar = #
    lex #
        start conditions #{interpolated_string, interpolated_string_terminal}

        rules [
            ['\\s+'. '/* ignore whitespace */']
            ['[0-9]+\\.[0-9]+'. 'return ''float'';']
            ['[0-9]+'. 'return ''integer'';']
            ['@' + identifier pattern. 'return ''argument'';']
            ['@:' + identifier pattern. 'return ''self_argument'';']
            ['\\?' + identifier pattern. 'return ''parameter'';']
            [identifier pattern. 'return ''identifier'';']
            ['\\??\\('. 'if (yy.interpolation.interpolating()) {yy.interpolation.openBracket()} return yytext;']
            ['\\)'. 'if (yy.interpolation.interpolating()) {yy.interpolation.closeBracket(); if (yy.interpolation.finishedInterpolation()) {this.popState(); this.popState(); yy.interpolation.stopInterpolation()}} return '')'';']
            ['{'. 'return ''{'';']
            ['}'. 'return ''}'';']
            ['\\['. 'return ''['';']
            ['\\]'. 'return '']'';']
            ['\\\\[.]'. 'return yytext.substring(1);']
            ['\\\\@[{]'. 'if (!yy.stringBrackets) {return yytext.substring(1);} else {++yy.stringBrackets;}']
            ['\\\\[}]'. 'if (!yy.stringBrackets) {return yytext.substring(1);} else {--yy.stringBrackets;}']
            ['\\.\\.\\.'. 'return ''...''']
            ['([:=,?!.@`~#$%^&*+<>/?|-]|\\\\\\\\)+'. 'return yy.lexOperator(yytext);']
            ['$'. 'return ''eof'';']
            ['''([^'']*'''')*[^'']*'''. 'return ''string'';']
            ['"'. 'this.begin(''interpolated_string''); return ''start_interpolated_string'';']
            [['interpolated_string']. '@'. 'this.begin(''interpolated_string_terminal''); return ''interpolated_string_terminal_start'';']
            [['interpolated_string_terminal']. identifier pattern. 'this.popState(); return ''identifier'';']
            [['interpolated_string_terminal']. '\\('. 'yy.interpolation.startInterpolation(); this.begin(''INITIAL''); return ''('';']
            [['interpolated_string']. '"'. 'this.popState(); return ''end_interpolated_string'';']
            [['interpolated_string']. '\\\\[.]'. '/* ignore */']
            [['interpolated_string']. '\\\\[{]'. 'yy.stringBrackets++']
            [['interpolated_string']. '\\\\[}]'. 'yy.stringBrackets--;']
            [['interpolated_string']. '\\\\\\\\\\\\\\\\'. 'return ''escaped_escape_interpolated_string_body'';']
            [['interpolated_string']. '\\\\\\\\.'. 'return ''escaped_interpolated_string_body'';']
            [['interpolated_string']. '[^"@\\\\]*'. 'return ''interpolated_string_body'';']
            ['.'. 'return ''non_token'';']
        ]

    operators [
        ['right'. '=']
        ['left'. ':']
    ]

    start 'module'

    bnf #
        module [
            ['statements eof'. 'return yy.module($1);']
        ]
        statements [
            ['statements_list'. '$$ = yy.statements($1);']
        ]
        hash_entries [
            ['hash_entries comma_dot basic_expression'. '$1.push($3.hashEntry()); $$ = $1;']
            ['basic_expression'. '$$ = [$1.hashEntry()];']
            [''. '$$ = [];']
        ]
        comma_dot [
            ['.'. '$$ = $1;']
            [','. '$$ = $1;']
        ]
        statements_list [
            ['statements_list . statement'. '$1.push($3); $$ = $1;']
            ['statement'. '$$ = [$1];']
            [''. '$$ = [];']
        ]
        statement [
            ['expression'. '$$ = $1.expression();']
        ]
        expression [
            ['expression = expression'. '$$ = $1.definition($3.expression());']
            ['operator_expression'. '$$ = $1;']
        ]
        operator_expression [
            ['operator_expression operator unary_operator_expression'. '$1.addOperatorExpression($2, $3); $$ = $1;']
            ['unary_operator_expression'. '$$ = yy.operatorExpression($1);']
        ]
        unary_operator_expression [
            ['object_operation'. '$$ = $1;']
            ['unary_operator object_operation'. '$$ = yy.newUnaryOperatorExpression({operator: $1, expression: $2.expression()});']
        ]
        object_operation [
            ['object_operation : complex_expression'. '$$ = $3.objectOperation($1.expression());']
            [': complex_expression'. '$$ = $2.objectOperation(yy.selfExpression());']
            ['complex_expression'. '$$ = $1;']
        ]
        complex_expression [
            ['basic_expression_list'. '$$ = yy.complexExpression($1);']
        ]
        basic_expression_list [
            ['basic_expression_list , terminal_list'. '$1.push($3); $$ = $1;']
            ['terminal_list_no_arg'. '$$ = [$1];']
        ]
        terminal_list_no_arg [
            ['terminal_list no_arg_punctuation'. '$1.push($2); $$ = $1;']
            ['terminal_list'. '$$ = $1;']
        ]
        basic_expression [
            ['terminal_list'. '$$ = yy.basicExpression($1);']
        ]
        no_arg_punctuation [
            ['no_arg'. '$$ = yy.loc(yy.noArgSuffix(), @$);']
        ]
        no_arg [
            ['!'. '$$ = $1;']
            ['?'. '$$ = $1;']
        ]
        terminal_list [
            ['terminal_list terminal'. '$1.push($2); $$ = $1;']
            ['terminal'. '$$ = [$1];']
        ]
        terminal [
            ['( statement )'. '$$ = $2;']
            ['?( statement )'. '$$ = yy.parameter($2);']
            ['block_start statements }'. '$$ = yy.loc(yy.block([], $2), @$);']
            ['=> { statements }'. '$$ = yy.loc(yy.block([], $3, {redefinesSelf: true}), @$);']
            ['[ statements_list ]'. '$$ = yy.loc(yy.list($2), @$);']
            ['{ hash_entries }'. '$$ = yy.loc(yy.hash($2), @$);']
            ['float'. '$$ = yy.loc(yy.float(parseFloat(yytext)), @$);']
            ['integer'. '$$ = yy.loc(yy.integer(parseInt(yytext)), @$);']
            ['identifier'. '$$ = yy.loc(yy.identifier(yytext), @$);']
            ['argument'. '$$ = yy.loc(yy.variable([yytext.substring(1)]), @$);']
            ['self_argument'. '$$ = yy.loc(yy.fieldReference(yy.variable([''self'']), [yytext.substring(2)]), @$);']
            ['parameter'. '$$ = yy.loc(yy.parameter(yy.variable([yytext.substring(1)])), @$);']
            ['string'. '$$ = yy.loc(yy.string(yy.normaliseString(yytext)), @$);']
            ['interpolated_string'. '$$ = yy.loc($1, @$);']
            ['...'. '$$ = yy.loc(yy.splat(), @$);']
        ]
        'block_start' [
            ['@ {'. '$$ = ''@{''']
            ['@{'. '$$ = ''@{''']
        ]
        operator [
            ['raw_operator'. '$$ = yy.normaliseOperator(yytext);']
        ]
        unary_operator [
            ['operator'. '$$ = $1;']
            ['!'. '$$ = $1;']
        ]
        interpolated_terminal [
            ['( statement )'. '$$ = $2;']
            ['identifier'. '$$ = yy.variable([$1]);']
        ]
        interpolated_string [
            ['start_interpolated_string interpolated_string_components end_interpolated_string'. '$$ = yy.interpolatedString($2);']
            ['start_interpolated_string end_interpolated_string'. '$$ = yy.interpolatedString([]);']
        ]
        interpolated_string_components [
            ['interpolated_string_components interpolated_string_component'. '$1.push($2); $$ = $1;']
            ['interpolated_string_component'. '$$ = [$1];']
        ]
        interpolated_string_component [
            ['interpolated_string_terminal_start interpolated_terminal'. '$$ = $2;']
            ['interpolated_string_body'. '$$ = yy.string($1);']
            ['escaped_interpolated_string_body'. '$$ = yy.string(yy.normaliseInterpolatedString($1.substring(1)));']
            ['escaped_escape_interpolated_string_body'. '$$ = yy.string($1.substring(3));']
        ]

exports: parser = parser = create parser with grammar @grammar
parser: yy = terms

exports: parse @source = parser: parse @source


basicExpressionSpec.pogo using new syntax

require 'cupoftea'
cg = require './codeGenerator/codeGenerator'
require './assertions.pogo'
assert = require 'assert'

spec 'basic expression'
  with terminals @terminals should not have arguments =
    ex = cg: basic expression @terminals
    (ex: has arguments?) should be falsy

  with terminals @terminals should have arguments =
    ex = cg: basic expression @terminals
    (ex: has arguments?) should be truthy

  variable = cg: variable ['a']
  block = cg: block [] (cg: statements [variable])
  id @name = cg: identifier @name
  int @n =
    cg: integer @n

  string @n =
    cg: string @n

  no arg punctuation = cg: no arg suffix?

  spec 'has arguments'
    spec 'with one variable'
      with terminals [variable] should have arguments

    spec 'with a block'
      with terminals [block] should have arguments

    spec 'with name and a block'
      with terminals [id 'c'. block] should have arguments

    spec 'with name, no arguments but a no arg punctuation'
      with terminals [id 'c'. no arg punctuation] should have arguments

  spec 'doesnt have arguments'
    spec 'with just an identifier'
      with terminals [id 'a'] should not have arguments

    spec 'with two identifiers'
      with terminals [id 'a'. id 'b'] should not have arguments

  spec 'arguments'
    terminals @terminals should have arguments @arguments =
      (cg: basic expression @terminals: arguments?) should contain fields @arguments

    spec 'single variable'
      terminals [variable] should have arguments [variable]

    spec 'variable with name'
      terminals [id 'move'. variable] should have arguments [variable]

    spec 'block'
      terminals [block] should have arguments [{
        is block
        body {
          statements [{is variable, variable ['a']}]
        }
      }]

    spec 'block with a parameter'
      terminals [cg: parameter (cg: variable ['x']). block] should have arguments [{
        is block
        parameters [{is parameter, expression {variable ['x']}}]
        body {
          statements [{is variable, variable ['a']}]
        }
      }]

  spec 'parameters'
    target @expression has some parameters =
      (cg: basic expression @expression: has parameters?) should be truthy

    target @expression doesnt have some parameters =
      (cg: basic expression @expression: has parameters?) should be falsy

    target @expression has parameters @parameters =
      (cg: basic expression @expression: parameters?) should contain fields @parameters

    spec 'single name'
      target [id 'car'] doesnt have some parameters

    spec 'name and variable'
        spec 'has parameters'
            target [id 'car'. variable] has some parameters

        spec 'parameters'
            target [id 'car'. variable] has parameters [{is parameter, expression {variable ['a']}}]

    spec 'no arg punctuation'
        spec 'has parameters'
            target [id 'car'. no arg punctuation] has some parameters

        spec 'parameters'
            target [id 'car'. no arg punctuation] has parameters []

  spec 'has name'
    terminals @terminals should have a name =
      (cg: basic expression @terminals: has name?) should be truthy

    spec 'with two identifiers'
      terminals [id 'car'. id 'idle'] should have a name

  spec 'name'
    terminals @terminals should have name @name =
      (cg: basic expression @terminals: name?) should contain fields @name

    spec 'with two identifiers'
      terminals [id 'car'. id 'idle'] should have name ['car'. 'idle']

    spec 'with two identifiers and arg'
      terminals [id 'car'. cg: variable ['car']. id 'idle'] should have name ['car'. 'idle']

  spec 'hash entry'
    hash entry @terminals should contain fields @f =
      (cg: basic expression @terminals: hash entry?) should contain fields @f

    spec 'with an argument'
      hash entry [id 'port'. int 10] should contain fields {
        is hash entry
        field ['port']
        value {integer 10}
      }

    spec 'without an argument'
      hash entry [id 'port'] should contain fields {
        is hash entry
        field ['port']
        value @undefined
      }

    spec 'with a string name'
      hash entry [string 'the port'. int 8] should contain fields {
        is hash entry
        field ['the port']
        value {integer 8}
      }

  spec 'hash entry, without block'
    hash entry @terminals should contain fields @f =
      (cg: basic expression @terminals: hash entry, without block) should contain fields @f

    spec 'with block'
      hash entry [id 'port'. int 10. block] should contain fields {
        is hash entry
        field ['port']
        value {integer 10}
      }

    spec 'without arguments'
      hash entry [id 'port'] should contain fields {
        is hash entry
        field ['port']
        value @undefined
      }

  spec 'hash entry block'
    hash entry block @terminals should contain fields @f =
      (cg: basic expression @terminals: hash entry block?) should contain fields @f

    spec 'with block'
      hash entry block [id 'port'. int 10. block] should contain fields {
        is block
        body {statements [{variable ['a']}]}
      }

    spec 'without block'
      assert: (cg: basic expression [id 'port'. int 10]: hash entry block?) equal @undefined

    spec 'without hash'
      assert: (cg: basic expression [id 'port']: hash entry block?) equal @undefined

require 'cupoftea'
cg = require './codeGenerator/codeGenerator'
require './assertions.pogo'
assert = require 'assert'

spec 'basic expression'
  with terminals @terminals should not have arguments =
    ex = cg: basic expression @terminals
    (ex: has arguments?) should be falsy

  with terminals @terminals should have arguments =
    ex = cg: basic expression @terminals
    (ex: has arguments?) should be truthy

  variable = cg: variable ['a']
  block = cg: block [] (cg: statements [variable])
  id @name = cg: identifier @name
  int @n =
    cg: integer @n

  string @n =
    cg: string @n

  no arg punctuation = cg: no arg suffix?

  spec 'has arguments'
    spec 'with one variable'
      with terminals [variable] should have arguments

    spec 'with a block'
      with terminals [block] should have arguments

    spec 'with name and a block'
      with terminals [id 'c'. block] should have arguments

    spec 'with name, no arguments but a no arg punctuation'
      with terminals [id 'c'. no arg punctuation] should have arguments

  spec 'doesnt have arguments'
    spec 'with just an identifier'
      with terminals [id 'a'] should not have arguments

    spec 'with two identifiers'
      with terminals [id 'a'. id 'b'] should not have arguments

  spec 'arguments'
    terminals @terminals should have arguments @arguments =
      (cg: basic expression @terminals: arguments?) should contain fields @arguments

    spec 'single variable'
      terminals [variable] should have arguments [variable]

    spec 'variable with name'
      terminals [id 'move'. variable] should have arguments [variable]

    spec 'block'
      terminals [block] should have arguments [#{
        is block
        body #{
          statements [#{is variable, variable ['a']}]
        }
      }]

    spec 'block with a parameter'
      terminals [cg: parameter (cg: variable ['x']). block] should have arguments [#{
        is block
        parameters [#{is parameter, expression #{variable ['x']}}]
        body #{
          statements [#{is variable, variable ['a']}]
        }
      }]

  spec 'parameters'
    target @expression has some parameters =
      (cg: basic expression @expression: has parameters?) should be truthy

    target @expression doesnt have some parameters =
      (cg: basic expression @expression: has parameters?) should be falsy

    target @expression has parameters @parameters =
      (cg: basic expression @expression: parameters?) should contain fields @parameters

    spec 'single name'
      target [id 'car'] doesnt have some parameters

    spec 'name and variable'
        spec 'has parameters'
            target [id 'car'. variable] has some parameters

        spec 'parameters'
            target [id 'car'. variable] has parameters [#{is parameter, expression #{variable ['a']}}]

    spec 'no arg punctuation'
        spec 'has parameters'
            target [id 'car'. no arg punctuation] has some parameters

        spec 'parameters'
            target [id 'car'. no arg punctuation] has parameters []

  spec 'has name'
    terminals @terminals should have a name =
      (cg: basic expression @terminals: has name?) should be truthy

    spec 'with two identifiers'
      terminals [id 'car'. id 'idle'] should have a name

  spec 'name'
    terminals @terminals should have name @name =
      (cg: basic expression @terminals: name?) should contain fields @name

    spec 'with two identifiers'
      terminals [id 'car'. id 'idle'] should have name ['car'. 'idle']

    spec 'with two identifiers and arg'
      terminals [id 'car'. cg: variable ['car']. id 'idle'] should have name ['car'. 'idle']

  spec 'hash entry'
    hash entry @terminals should contain fields @f =
      (cg: basic expression @terminals: hash entry?) should contain fields @f

    spec 'with an argument'
      hash entry [id 'port'. int 10] should contain fields #
        is hash entry
        field ['port']
        value #{integer 10}

    spec 'without an argument'
      hash entry [id 'port'] should contain fields #
        is hash entry
        field ['port']
        value @undefined

    spec 'with a string name'
      hash entry [string 'the port'. int 8] should contain fields #
        is hash entry
        field ['the port']
        value #{integer 8}

  spec 'hash entry, without block'
    hash entry @terminals should contain fields @f =
      (cg: basic expression @terminals: hash entry, without block) should contain fields @f

    spec 'with block'
      hash entry [id 'port'. int 10. block] should contain fields #
        is hash entry
        field ['port']
        value #{integer 10}

    spec 'without arguments'
      hash entry [id 'port'] should contain fields #
        is hash entry
        field ['port']
        value @undefined

  spec 'hash entry block'
    hash entry block @terminals should contain fields @f =
      (cg: basic expression @terminals: hash entry block?) should contain fields @f

    spec 'with block'
      hash entry block [id 'port'. int 10. block] should contain fields #
        is block
        body #{statements [#{variable ['a']}]}

    spec 'without block'
      assert: (cg: basic expression [id 'port'. int 10]: hash entry block?) equal @undefined

    spec 'without hash'
      assert: (cg: basic expression [id 'port']: hash entry block?) equal @undefined


additional for loop tests

additional for loop tests

script = require './scriptAssertions'

describe 'for'
    describe 'for each'
      it "returns in functions within for don't return from for"
        script.'items = [[1, 2, 3], [1, 2], [1]]

                for each @(item) in (items)
                  item count () = return (item.length)

                  print (item count ())' shouldOutput '3
                                                       2
                                                       1'

      describe 'async'
        it "waits for loop to finish resolving promise before moving onto next loop"
          script.'items = [1, 2, 3]

                  for each @(item) in (items)
                    print "before #(item)"
                    p()!
                    print "after #(item)"

                  print "finished"' shouldOutput "'before 1'
                                                  'after 1'
                                                  'before 2'
                                                  'after 2'
                                                  'before 3'
                                                  'after 3'
                                                  'finished'"

        it "doesn't loop if there aren't any items"
          script.'items = []

                  for each @(item) in (items)
                    print "before #(item)"
                    p()!
                    print "after #(item)"

                  print "finished"' shouldOutput "'finished'"

    describe 'for loop'
      it 'can be returned from'
        script.'count to three () =
                  for (n = 0, n < 10, ++n)
                    if (n > 2)
                      return "three"

                print (count to three ())' shouldOutput "'three'"

      it 'can loop'
        script.'count to three () =
                  for (n = 0, n < 10, ++n)
                    print (n)

                count to three ()' shouldOutput '0
                                                 1
                                                 2
                                                 3
                                                 4
                                                 5
                                                 6
                                                 7
                                                 8
                                                 9'

      describe 'async'
        it 'waits for loop to finish resolving promise before moving onto next loop'
          script.'for (n = 0, n < 3, ++n)
                    print "before #(n)"
                    p()!
                    print "after #(n)"

                  print "finished"' shouldOutput "'before 0'
                                                  'after 0'
                                                  'before 1'
                                                  'after 1'
                                                  'before 2'
                                                  'after 2'
                                                  'finished'"

        it "doesn't loop if the test fails"
          script.'for (n = 0, false, ++n)
                    print "before #(n)"
                    p()!
                    print "after #(n)"

                  print "finished"' shouldOutput "'finished'"

    describe 'for in'
        it "iterates over object's fields"
            script.'object = {a = 1, b = 2}

                    for @(field) in (object)
                        print (field)' shouldOutput "'a'
                                                     'b'"

script = require './scriptAssertions'

describe 'for'
    describe 'for each'
      it "returns in functions within for don't return from for"
        script.'items = [[1, 2, 3], [1, 2], [1]]

                for each @(item) in (items)
                  item count () = return (item.length)

                  print (item count ())' shouldOutput '3
                                                       2
                                                       1'

      it "waits for loop to finish resolving promise before moving onto next loop"
        script.'items = [1, 2, 3]

                for each @(item) in (items)
                  print "before #(item)"
                  p()!
                  print "after #(item)"

                print "finished"' shouldOutput "'before 1'
                                                'after 1'
                                                'before 2'
                                                'after 2'
                                                'before 3'
                                                'after 3'
                                                'finished'"

    describe 'for loop'
      it 'can be returned from'
        script.'count to three () =
                  for (n = 0, n < 10, ++n)
                    if (n > 2)
                      return "three"

                print (count to three ())' shouldOutput "'three'"

      it 'can loop'
        script.'count to three () =
                  for (n = 0, n < 10, ++n)
                    print (n)

                count to three ()' shouldOutput '0
                                                 1
                                                 2
                                                 3
                                                 4
                                                 5
                                                 6
                                                 7
                                                 8
                                                 9'

      it 'waits for loop to finish resolving promise before moving onto next loop'
        script.'for (n = 0, n < 3, ++n)
                  print "before #(n)"
                  p()!
                  print "after #(n)"

                print "finished"' shouldOutput "'before 0'
                                                'after 0'
                                                'before 1'
                                                'after 1'
                                                'before 2'
                                                'after 2'
                                                'finished'"

    describe 'for in'
        it "iterates over object's fields"
            script.'object = {a = 1, b = 2}

                    for @(field) in (object)
                        print (field)' shouldOutput "'a'
                                                     'b'"


removed a few @ symbols :)

removed a few @ symbols :)

fs = require "fs"
async = require "async"
handlebars = require "handlebars"
exec = require "child_process" : exec
highlight = require "highlight" : Highlight

html = "

    <title>Pogo Examples</title>
    <link rel=\"stylesheet\" type=\"text/css\" href=\"samples.css\" />
    <link rel=\"stylesheet\" type=\"text/css\" href=\"highlight.css\" />

PogoScript to JavaScript Examples

      {{#each examples}}

{{this.name}}

{{{pogo this}}}

{{{js this}}}

      {{/each}}

"
template = handlebars: compile @html

title case @string =
  reg = new (RegExp "_" "g")
  string = string : replace @reg " "
  reg = new (RegExp "\w\S*" "g")
  string: replace @reg #text
    (text : char at 0 : to upper case!) + (text : substr 1 : to lower case!)

remove closure from @js =
  reg = new (RegExp "(^[^\n]+\n\s*)|(\n[^\n]+$)" "g")
  js : replace @reg (new (String))

unindent @js =
  reg = new (RegExp "\n    " "g")
  js : replace @reg "\n"

simplify @js =
  unindent (remove closure from @js)

read compiled js at @path @pogo @callback =
  fs : read file @path "utf-8" #jserr #js
    js = simplify @js
    name = path : replace "./examples/" (new (String))
    name = name : replace ".js" (new (String))
    @callback @null {
      js = @highlight @js
      pogo = @highlight @pogo
      name = (title case) @name
    }

compile pogo @path @pogo @callback =
  js path = path: replace ".pogo" ".js"
  exec "pogo -c @path" #error #stdout #stderr
    read compiled js at (js path) @pogo @callback

render @file @callback =
  path = "./examples/@file"
  fs: read file @path "utf-8" #err #pogo
    compile pogo @path @pogo @callback

print @err @results =
  rendered = template { examples = @results }
  console: log @rendered

is @path pogo =
  path : index of ".pogo" > -1

dir @err @files =
  pogos = files : filter (is pogo)
  async: map @pogos @render @print

fs: readdir "./examples/" @dir

fs = require "fs"
async = require "async"
handlebars = require "handlebars"
exec = require "child_process" : exec
highlight = require "highlight" : Highlight

html = "

    <title>Pogo Examples</title>
    <link rel=\"stylesheet\" type=\"text/css\" href=\"samples.css\" />
    <link rel=\"stylesheet\" type=\"text/css\" href=\"highlight.css\" />

PogoScript to JavaScript Examples

      {{#each examples}}

{{this.name}}

{{{pogo this}}}

{{{js this}}}

      {{/each}}

"
template = handlebars: compile @html

title case @string =
  reg = new (RegExp "_" "g")
  string = string : replace @reg " "
  reg = new (RegExp "\w\S*" "g")
  string: replace @reg #text
    (text : char at 0 : to upper case!) + (text : substr 1 : to lower case!)

remove closure from @js =
  reg = new (RegExp "(^[^\n]+\n\s*)|(\n[^\n]+$)" "g")
  js : replace @reg (new (String))

unindent @js =
  reg = new (RegExp "\n    " "g")
  js : replace @reg "\n"

simplify @js =
  unindent (remove closure from @js)

read compiled js at @path @pogo @callback =
  fs : read file @path "utf-8" #jserr #js
    js = simplify @js
    name = @path : replace "./examples/" (new (String))
    name = @name : replace ".js" (new (String))
    @callback @null {
      js = @highlight @js
      pogo = @highlight @pogo
      name = (title case) @name
    }

compile pogo @path @pogo @callback =
  js path = @path: replace ".pogo" ".js"
  exec "pogo -c @path" #error #stdout #stderr
    read compiled js at (js path) @pogo @callback

render @file @callback =
  path = "./examples/@file"
  fs: read file @path "utf-8" #err #pogo
    compile pogo @path @pogo @callback

print @err @results =
  rendered = template { examples = @results }
  console: log @rendered

is @path pogo =
  path : index of ".pogo" > -1

dir @err @files =
  pogos = files : filter (is pogo)
  async: map @pogos @render @print

fs: readdir "./examples/" @dir


atoms: not yet!

atoms: not yet!

require './runtime.pogo'

atom prototype = object {
    arguments () = []
    block parameters () = []
    word () = null
    block () = null
}

self.atom (forms, members) =
    a = object extending (atom prototype) (members)
    a.forms = forms
    a

self.argument (forms, argument) = self.atom (forms) {
    arguments () = [argument]
}

self.block atom (forms, block) = self.atom (forms) {
    block () = block
}

self.word (forms, word) = self.atom (forms) {
    word () = word
}

self.block parameters (forms, parameters) = self.atom (forms) {
    block parameters () = parameters
}


reorganise test

reorganise test

parser = require("../parser").parser
Node = require("./renderer").Node

describe 'parser'

    parser.yy.create (data) = @new Node (data)

    parses (input) as (output) =
        it "parses #(input) as #(output)"
            parser.parse(input).render().should.equal(output.replace('*', ''))

    parses (input) =
        parses (input) as (input)

    parses "*"
    parses "a"
    parses "a, b"
    parses "a,b" as "a, b"
    parses "a, b,c" as "a, b, c"
    parses "a.b"
    parses "a.b.c"
    parses "#a"
    parses "#a.b"
    parses ".a #b"
    parses "a[b]"
    parses "a[b][c]"

    parses "a[b = c]"
    parses "a[b= c]" as "a[b = c]"
    parses "a[b =c]" as "a[b = c]"
    parses "a[b=c]" as "a[b = c]"
    parses "a[b = 'c']" as "a[b = c]"
    parses "a[b= 'c']" as "a[b = c]"
    parses "a[b ='c']" as "a[b = c]"
    parses "a[b='c']" as "a[b = c]"
    parses 'a[b = "c"]' as "a[b = c]"
    parses 'a[b= "c"]' as 'a[b = c]'
    parses 'a[b ="c"]' as 'a[b = c]'
    parses 'a[b="c"]' as 'a[b = c]'

    parses "a[b ~= c]"
    parses "a[b~= c]" as "a[b ~= c]"
    parses "a[b ~=c]" as "a[b ~= c]"
    parses "a[b~=c]" as "a[b ~= c]"
    parses "a[b ~= 'c']" as "a[b ~= c]"
    parses "a[b~= 'c']" as "a[b ~= c]"
    parses "a[b ~='c']" as "a[b ~= c]"
    parses "a[b~='c']" as "a[b ~= c]"
    parses 'a[b ~= "c"]' as "a[b ~= c]"
    parses 'a[b~= "c"]' as 'a[b ~= c]'
    parses 'a[b ~="c"]' as 'a[b ~= c]'
    parses 'a[b~="c"]' as 'a[b ~= c]'

    parses "a[b |= c]"
    parses "a[b|= c]" as "a[b |= c]"
    parses "a[b |=c]" as "a[b |= c]"
    parses "a[b|=c]" as "a[b |= c]"
    parses "a[b |= 'c']" as "a[b |= c]"
    parses "a[b|= 'c']" as "a[b |= c]"
    parses "a[b |='c']" as "a[b |= c]"
    parses "a[b|='c']" as "a[b |= c]"
    parses 'a[b |= "c"]' as "a[b |= c]"
    parses 'a[b|= "c"]' as 'a[b |= c]'
    parses 'a[b |="c"]' as 'a[b |= c]'
    parses 'a[b|="c"]' as 'a[b |= c]'

    parses "a b"
    parses "a > b"
    parses "a> b" as "a > b"
    parses "a >b" as "a > b"
    parses "a>b" as "a > b"
    parses "a>b >c" as "a > b > c"
    parses "a > b > c d"
    parses "> a" as "* > a"
    parses "> a > b" as "* > a > b"

    parses "*:a"
    parses ":a"
    parses ":a-b"
    parses "a:b"
    parses "a:b:c"
    parses ":a(b)"
    parses ":a-b(c)"
    parses "a:b(c)"
    parses "a:b(c > d)"

    parses ":has(> a)" as ":has(* > a)"

    parses "a[b = c], c[d]:e:f(g *:h:i[j]:k), :l > m[n ~= o][p = q]"

parser = require("../parser").parser
Node = require("./renderer").Node

describe 'parser'

    parser.yy.create (data) = @new Node (data)

    parses (input) as (output) =
        it "parses #(input) as #(output)"
            parser.parse(input).render().should.equal(output.replace('*', ''))

    parses (input) =
        parses (input) as (input)

    parses "*"
    parses "a"
    parses "a, b"
    parses "a,b" as "a, b"
    parses "a, b,c" as "a, b, c"
    parses "a.b"
    parses "a.b.c"
    parses "#a"
    parses "#a.b"
    parses ".a #b"
    parses "a[b]"

    parses "a[b = c]"
    parses "a[b= c]" as "a[b = c]"
    parses "a[b =c]" as "a[b = c]"
    parses "a[b=c]" as "a[b = c]"
    parses "a[b = 'c']" as "a[b = c]"
    parses "a[b= 'c']" as "a[b = c]"
    parses "a[b ='c']" as "a[b = c]"
    parses "a[b='c']" as "a[b = c]"
    parses 'a[b = "c"]' as "a[b = c]"
    parses 'a[b= "c"]' as 'a[b = c]'
    parses 'a[b ="c"]' as 'a[b = c]'
    parses 'a[b="c"]' as 'a[b = c]'

    parses "a[b ~= c]"
    parses "a[b~= c]" as "a[b ~= c]"
    parses "a[b ~=c]" as "a[b ~= c]"
    parses "a[b~=c]" as "a[b ~= c]"
    parses "a[b ~= 'c']" as "a[b ~= c]"
    parses "a[b~= 'c']" as "a[b ~= c]"
    parses "a[b ~='c']" as "a[b ~= c]"
    parses "a[b~='c']" as "a[b ~= c]"
    parses 'a[b ~= "c"]' as "a[b ~= c]"
    parses 'a[b~= "c"]' as 'a[b ~= c]'
    parses 'a[b ~="c"]' as 'a[b ~= c]'
    parses 'a[b~="c"]' as 'a[b ~= c]'

    parses "a[b |= c]"
    parses "a[b|= c]" as "a[b |= c]"
    parses "a[b |=c]" as "a[b |= c]"
    parses "a[b|=c]" as "a[b |= c]"
    parses "a[b |= 'c']" as "a[b |= c]"
    parses "a[b|= 'c']" as "a[b |= c]"
    parses "a[b |='c']" as "a[b |= c]"
    parses "a[b|='c']" as "a[b |= c]"
    parses 'a[b |= "c"]' as "a[b |= c]"
    parses 'a[b|= "c"]' as 'a[b |= c]'
    parses 'a[b |="c"]' as 'a[b |= c]'
    parses 'a[b|="c"]' as 'a[b |= c]'

    parses "a b"
    parses "a > b"
    parses "a> b" as "a > b"
    parses "a >b" as "a > b"
    parses "a>b" as "a > b"
    parses "a>b >c" as "a > b > c"
    parses "a > b > c d"

    parses "a, [b = c], c"
    parses "*:a"
    parses ":a"
    parses ":a-b"
    parses "a:b"
    parses "a:b:c"
    parses ":a(b)"
    parses ":a-b(c)"
    parses "a:b(c)"
    parses "a:b(c > d)"
    parses "a[b = c], c[d]:e:f(g *:h:i[j]:k), :l > m[n ~= o]"

    parses "> a" as "* > a"
    parses ":has(> a)" as ":has(* > a)"