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