Reverting back to working version.

This commit is contained in:
Elf M. Sternberg 2015-07-23 16:21:28 -07:00
parent e6b4a73559
commit bb0c06b073
1 changed files with 30 additions and 54 deletions

View File

@ -1,19 +1,13 @@
{car, cdr, cons, nil, nilp, pairp, vectorToList, list} = require 'cons-lists/lists'
{length} = require 'cons-lists/reduce'
{inspect} = require "util"
NEWLINES = ["\n", "\r", "\x0B", "\x0C"]
WHITESPACE = [" ", "\t"].concat(NEWLINES)
EOF = new (class Eof)()
EOO = new (class Eoo)()
stringp = (o) -> o?.__type == 'string'
errorp = (o) -> (pairp o) and (car o) == 'error'
streq = (s, t) -> String(s) == String(t)
class Source
constructor: (@inStream) ->
@index = 0
@ -38,24 +32,13 @@ class Source
skipWS = (inStream) ->
while inStream.peek() in WHITESPACE then inStream.next()
invisibleProperty = (obj, name, value) ->
Object.defineProperty obj, name,
value: value
configurable: false
enumerable: false
writable: false
obj
lineInfo = (obj, line, column) ->
invisibleProperty obj, '__position', {line: line, column: column}
# (type, value, line, column) -> (node {type, value, line, column)}
makeObj = (value, type, line, column) ->
lineInfo (invisibleProperty value, '__type', type), line, column
makeObj = (type, value, line, column) ->
list(type, value, line, column)
# msg -> (IO -> Node => Error)
handleError = (message) ->
(line, column) -> lineInfo (cons "error", message), line, column
(line, column) -> makeObj('error', message, line, column)
# IO -> Node => Comment
readComment = (inStream) ->
@ -64,26 +47,26 @@ readComment = (inStream) ->
inStream.next()).join("")
if not inStream.done()
inStream.next()
makeObj (new String r), 'comment', line, column
makeObj 'comment', r, line, column
# IO -> (Node => Literal => String) | Error
readString = (inStream) ->
[line, column] = inStream.position()
inStream.next()
string = until streq(inStream.peek(), '"') or inStream.done()
if (streq inStream.peek(), '\\')
string = until inStream.peek() == '"' or inStream.done()
if inStream.peek() == '\\'
inStream.next()
inStream.next()
if inStream.done()
return handleError("end of file seen before end of string.")(line, column)
inStream.next()
makeObj (new String (string.join '')), 'string', line, column
makeObj 'string', (string.join ''), line, column
# (String) -> (Node => Literal => Number) | Nothing
readMaybeNumber = (symbol) ->
if streq(symbol[0], '+')
if symbol[0] == '+'
return readMaybeNumber symbol.substr(1)
if streq(symbol[0], '-')
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
@ -102,48 +85,43 @@ readSymbol = (inStream, tableKeys) ->
symbol = (until (inStream.done() or inStream.peek() in tableKeys or inStream.peek() in WHITESPACE)
inStream.next()).join ''
number = readMaybeNumber symbol
if nilp number
return nil
if number?
return makeObj (new Number number), 'number', line, column
makeObj (new String symbol), 'symbol', line, column
return makeObj 'number', number, line, column
makeObj 'symbol', symbol, line, column
# (Delim, TypeName) -> IO -> (IO, node) | Error
makeReadContainer = (delim, constructor) ->
makeReadPair = (delim, type) ->
# IO -> (IO, Node) | Error
(inStream) ->
inStream.next()
skipWS inStream
[line, column] = inStream.position()
if streq(inStream.peek(), delim)
if inStream.peek() == delim
inStream.next()
return constructor(nil, line, column)
return makeObj(type, nil, line, column)
# IO -> (IO, Node) | Error
dotted = false
readInContainer = (inStream) ->
readEachPair = (inStream) ->
[line, column] = inStream.position()
obj = read inStream, true, null, true
if streq(inStream.peek(), delim)
if inStream.peek() == delim
if dotted then return obj
return lineInfo (cons obj, nil), line, column
return cons obj, nil
if inStream.done() then return handleError("Unexpected end of input")(line, column)
if dotted then return handleError("More than one symbol after dot")
return obj if (errorp obj)
if streq(obj, ".")
return obj if (car obj) == 'error'
if (car obj) == 'symbol' and (car cdr obj) == '.'
dotted = true
return readInContainer inStream
cons obj, readInContainer inStream
return readEachPair inStream
cons obj, readEachPair inStream
ret = readInContainer(inStream)
ret = makeObj type, readEachPair(inStream), line, column
inStream.next()
ret
# Type -> (IO -> (IO, Node))
#
# Handles the quoted symbol things.
#
prefixReader = (type) ->
# IO -> (IO, Node)
(inStream) ->
@ -152,7 +130,7 @@ prefixReader = (type) ->
[line1, column1] = inStream.position()
obj = read inStream, true, null, true
return obj if (car obj) == 'error'
cons (makeObj (new String type), 'symbol', line1, column1), obj
makeObj "list", cons((makeObj("symbol", type, line1, column1)), cons(obj)), line, column
# I really wanted to make anything more complex than a list (like an
# object or a vector) something handled by a read macro. Maybe in a
@ -160,14 +138,12 @@ prefixReader = (type) ->
readMacros =
'"': readString
'(': makeReadContainer ')', (o, l, c) -> lineInfo o, l, c
'(': makeReadPair ')', 'list'
')': handleError "Closing paren encountered"
'[': makeReadContainer ']', (o, l, c) -> cons("vector", lineinfo o, l, c)
'[': makeReadPair ']', 'vector'
']': handleError "Closing bracket encountered"
'{': makeReadContainer '}', (o, l, c) ->
if length(o) % 2 != 0
return handleError "Records require an even number of items."
cons('record', lineinfo o, l, c)
'{': makeReadPair('}', 'record', (res) ->
res.length % 2 == 0 and true or mkerr "record key without value")
'}': handleError "Closing curly without corresponding opening."
"`": prefixReader 'back-quote'
"'": prefixReader 'quote'
@ -177,9 +153,9 @@ readMacros =
# Given a stream, reads from the stream until a single complete lisp
# object has been found and returns the object
# IO -> Form
read = (inStream, eofErrorP = false, eofError = EOF,
recursiveP = false, inReadMacros = null, keepComments = false) ->
read = (inStream, eofErrorP = false, eofError = EOF, recursiveP = false, inReadMacros = null, keepComments = false) ->
inStream = if inStream instanceof Source then inStream else new Source inStream
inReadMacros = if InReadMacros? then inReadMacros else readMacros
inReadMacroKeys = (i for i of inReadMacros)