Reverting back to working version.
This commit is contained in:
parent
e6b4a73559
commit
bb0c06b073
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue