From bb0c06b073b4f3a53e7c464c76190cc1df381d3d Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Thu, 23 Jul 2015 16:21:28 -0700 Subject: [PATCH] Reverting back to working version. --- chapter1/reader.coffee | 84 +++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 54 deletions(-) diff --git a/chapter1/reader.coffee b/chapter1/reader.coffee index db5694d..b4be16e 100644 --- a/chapter1/reader.coffee +++ b/chapter1/reader.coffee @@ -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)