2015-08-18 14:09:47 +00:00
|
|
|
{car, cdr, cons, nil, nilp, pairp, vectorToList, list} = require 'cons-lists/lists'
|
|
|
|
{inspect} = require "util"
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
{Comment, Symbol} = require "../chapter5/reader_types"
|
2015-08-18 14:09:47 +00:00
|
|
|
|
|
|
|
NEWLINES = ["\n", "\r", "\x0B", "\x0C"]
|
|
|
|
WHITESPACE = [" ", "\t"].concat(NEWLINES)
|
|
|
|
|
|
|
|
EOF = new (class Eof)()
|
|
|
|
EOO = new (class Eoo)()
|
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
class ReadError extends Error
|
|
|
|
name: 'LispInterpreterError'
|
|
|
|
constructor: (@message) ->
|
|
|
|
|
2015-08-18 14:09:47 +00:00
|
|
|
class Source
|
|
|
|
constructor: (@inStream) ->
|
|
|
|
@index = 0
|
|
|
|
@max = @inStream.length - 1
|
|
|
|
@line = 0
|
|
|
|
@column = 0
|
|
|
|
|
|
|
|
peek: -> @inStream[@index]
|
|
|
|
|
|
|
|
position: -> [@line, @column]
|
|
|
|
|
|
|
|
next: ->
|
|
|
|
c = @peek()
|
|
|
|
return EOF if @done()
|
|
|
|
@index++
|
|
|
|
[@line, @column] = if @peek() in NEWLINES then [@line + 1, 0] else [@line, @column + 1]
|
|
|
|
c
|
|
|
|
|
|
|
|
done: -> @index > @max
|
|
|
|
|
|
|
|
# IO -> IO
|
|
|
|
skipWS = (inStream) ->
|
|
|
|
while inStream.peek() in WHITESPACE then inStream.next()
|
|
|
|
|
|
|
|
readMaybeNumber = (symbol) ->
|
|
|
|
if symbol[0] == '+'
|
|
|
|
return readMaybeNumber symbol.substr(1)
|
|
|
|
if symbol[0] == '-'
|
|
|
|
ret = readMaybeNumber symbol.substr(1)
|
|
|
|
return if ret? then -1 * ret else undefined
|
|
|
|
if symbol.search(/^0x[0-9a-fA-F]+$/) > -1
|
|
|
|
return parseInt(symbol, 16)
|
|
|
|
if symbol.search(/^0[0-9a-fA-F]+$/) > -1
|
|
|
|
return parseInt(symbol, 8)
|
|
|
|
if symbol.search(/^[0-9]+$/) > -1
|
|
|
|
return parseInt(symbol, 10)
|
|
|
|
if symbol.search(/^nil$/) > -1
|
|
|
|
return nil
|
|
|
|
undefined
|
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
# (Delim, TypeName) -> IO -> (IO, Node) | Errorfor
|
2015-08-18 14:09:47 +00:00
|
|
|
makeReadPair = (delim, type) ->
|
|
|
|
# IO -> (IO, Node) | Error
|
|
|
|
(inStream) ->
|
|
|
|
inStream.next()
|
|
|
|
skipWS inStream
|
|
|
|
if inStream.peek() == delim
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
inStream.next() unless inStream.done()
|
|
|
|
return if type then cons((new Symbol type), nil) else nil
|
2015-08-18 14:09:47 +00:00
|
|
|
|
|
|
|
# IO -> (IO, Node) | Error
|
|
|
|
dotted = false
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
readEachPair = (inStream) =>
|
|
|
|
obj = @read inStream, true, null, true
|
2015-08-18 14:09:47 +00:00
|
|
|
if inStream.peek() == delim
|
|
|
|
if dotted then return obj
|
|
|
|
return cons obj, nil
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
return obj if obj instanceof ReadError
|
|
|
|
if inStream.done() then return new ReadError "Unexpected end of input"
|
|
|
|
if dotted then return new ReadError "More than one symbol after dot in list"
|
2015-08-26 05:01:21 +00:00
|
|
|
if @acc(obj) instanceof Symbol and @acc(obj).name == '.'
|
2015-08-18 14:09:47 +00:00
|
|
|
dotted = true
|
|
|
|
return readEachPair inStream
|
|
|
|
cons obj, readEachPair inStream
|
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
obj = readEachPair(inStream)
|
2015-08-26 05:01:21 +00:00
|
|
|
inStream.next()
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
if type then cons((new Symbol type), obj) else obj
|
2015-08-18 14:09:47 +00:00
|
|
|
|
|
|
|
# Type -> IO -> IO, Node
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
|
|
|
|
class Reader
|
2015-08-26 05:01:21 +00:00
|
|
|
prefixReader = (type) ->
|
|
|
|
# IO -> IO, Node
|
|
|
|
(inStream) ->
|
|
|
|
inStream.next()
|
|
|
|
obj = @read inStream, true, null, true
|
|
|
|
return obj if obj instanceof ReadError
|
|
|
|
cons((new Symbol type), obj)
|
|
|
|
|
|
|
|
"acc": (obj) -> obj
|
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
"symbol": (inStream) ->
|
|
|
|
symbol = (until (inStream.done() or @[inStream.peek()]? or inStream.peek() in WHITESPACE)
|
|
|
|
inStream.next()).join ''
|
|
|
|
number = readMaybeNumber symbol
|
|
|
|
if number?
|
|
|
|
return number
|
|
|
|
new Symbol symbol
|
|
|
|
|
|
|
|
"read": (inStream, eofErrorP = false, eofError = EOF, recursiveP = false, keepComments = false) ->
|
|
|
|
inStream = if inStream instanceof Source then inStream else new Source inStream
|
2015-08-26 05:01:21 +00:00
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
c = inStream.peek()
|
2015-08-26 05:01:21 +00:00
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
# (IO, Char) -> (IO, Node) | Error
|
|
|
|
matcher = (inStream, c) =>
|
|
|
|
if inStream.done()
|
|
|
|
return if recursiveP then (new ReadError 'EOF while processing nested object') else nil
|
|
|
|
if c in WHITESPACE
|
|
|
|
inStream.next()
|
|
|
|
return nil
|
|
|
|
if c == ';'
|
|
|
|
return readComment(inStream)
|
|
|
|
ret = if @[c]? then @[c](inStream) else @symbol(inStream)
|
|
|
|
skipWS inStream
|
|
|
|
ret
|
2015-08-26 05:01:21 +00:00
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
while true
|
|
|
|
form = matcher inStream, c
|
|
|
|
skip = (not nilp form) and (form instanceof Comment) and not keepComments
|
|
|
|
break if (not skip and not nilp form) or inStream.done()
|
|
|
|
c = inStream.peek()
|
|
|
|
null
|
|
|
|
form
|
|
|
|
|
|
|
|
'(': makeReadPair ')', null
|
2015-08-18 14:09:47 +00:00
|
|
|
|
|
|
|
'[': makeReadPair ']', 'vector'
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
|
2015-08-18 14:09:47 +00:00
|
|
|
'{': makeReadPair('}', 'record', (res) ->
|
|
|
|
res.length % 2 == 0 and true or mkerr "record key without value")
|
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
'"': (inStream) ->
|
|
|
|
inStream.next()
|
|
|
|
s = until inStream.peek() == '"' or inStream.done()
|
|
|
|
if inStream.peek() == '\\'
|
|
|
|
inStream.next()
|
|
|
|
inStream.next()
|
|
|
|
return (new ReadError "end of file seen before end of string") if inStream.done()
|
|
|
|
inStream.next()
|
|
|
|
s.join ''
|
2015-08-18 14:09:47 +00:00
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
')': (inStream) -> new ReadError "Closing paren encountered"
|
2015-08-18 14:09:47 +00:00
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
']': (inStream) -> new ReadError "Closing bracket encountered"
|
2015-08-18 14:09:47 +00:00
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
'}': (inStream) -> new ReadError "Closing curly without corresponding opening."
|
2015-08-18 14:09:47 +00:00
|
|
|
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
"`": prefixReader 'back-quote'
|
|
|
|
|
|
|
|
"'": prefixReader 'quote'
|
|
|
|
|
|
|
|
",": prefixReader 'unquote'
|
|
|
|
|
|
|
|
";": (inStream) ->
|
|
|
|
r = (while inStream.peek() != "\n" and not inStream.done()
|
|
|
|
inStream.next()).join("")
|
|
|
|
inStream.next() if not inStream.done()
|
|
|
|
new Comment r
|
|
|
|
|
|
|
|
exports.Source = Source
|
2015-08-26 05:01:21 +00:00
|
|
|
exports.ReadError = ReadError
|
[refactor] Is this the functor/applicative/monadic life?
This is a big change. For chapter 5, I ripped out all line/column
tracking and most error handling from the parser; it's now a plain
ol' Lisp parser, and if it's not close to CL 22.1.1, it's a hell of
a lot closer than it used to be.
In doing so, I reduced the size of the parser by about 40 lines.
TrackingReader takes every function in a Reader and puts that
debugging information *back*. It turns out that all that information
was prelude and postlude to the act of parsing; by wrapping each
function in a decorator I was able to restore all that information,
and I only had to get it right exactly *once*.
In functional programming terms, this lifts:
IO -> (atom | list)
to:
IO with tracking -> Node (atom | list) with tracking
It's a totally free win without having to do much extra work.
Now, this check-in isn't perfect. The tracking reader is still
tossing on some things, and because I don't have a robust type
system (it is Coffeescript, after all), I'm having to do the
decorating and wrapping by hand. But I'm definitely on my way
to understanding the issues, and having a grasp on functors and
monoids.
2015-08-20 15:50:52 +00:00
|
|
|
exports.Reader = Reader
|
|
|
|
reader = new Reader()
|
|
|
|
exports.read = -> reader.read.apply(reader, arguments)
|