From 1c4975067d51ed69fdc9723255f8c4d4e92208b5 Mon Sep 17 00:00:00 2001 From: Ken Elf Mathieu Sternberg Date: Fri, 3 Jul 2015 15:47:04 -0700 Subject: [PATCH] TEST: Add tests for the reader (!), which I had forgotten. This also adds a number of accesory functions necessary for rationalizing the record structure of an object in the lex/parse phase into something more lisp-like. There's a metadata issue here that I'm not quite wrapping my head around. --- chapter1/astAccessors.coffee | 10 +++++++ chapter1/astToList.coffee | 51 ++++++++++++++++++++++++++++++++++++ test/test_reader.coffee | 34 ++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 chapter1/astAccessors.coffee create mode 100644 chapter1/astToList.coffee create mode 100644 test/test_reader.coffee diff --git a/chapter1/astAccessors.coffee b/chapter1/astAccessors.coffee new file mode 100644 index 0000000..413461c --- /dev/null +++ b/chapter1/astAccessors.coffee @@ -0,0 +1,10 @@ +{car, cdr} = require 'cons-lists/lists' + +symbol = (form) -> (car form) + +module.exports = + aSymbol: symbol + aValue: (form) -> (car cdr form) + isAList: (form) -> (symbol form) == 'list' + isARecord: (form) -> (symbol form) == 'record' + isAVector: (form) -> (symbol form) == 'vector' diff --git a/chapter1/astToList.coffee b/chapter1/astToList.coffee new file mode 100644 index 0000000..2a0010e --- /dev/null +++ b/chapter1/astToList.coffee @@ -0,0 +1,51 @@ +{car, cdr, cons, listp, nilp, nil, list, listToString} = require 'cons-lists/lists' +{aSymbol, aValue} = require './astAccessors' + +# RICH_AST -> LISP_AST +normalizeForm = (form) -> + + listToRecord1 = (l) -> + o = Object.create(null) + while(l != nil) + o[normalizeForm(car l)] = normalizeForm(car cdr l) + l = cdr cdr l + null + o + + listToVector1 = (l) -> + while(l != nil) then p = normalizeForm(car l); l = cdr l; p + + id = (a) -> a + + methods = + 'list': normalizeForms + 'vector': (atom) -> listToVector1(atom) + 'record': (atom) -> listToRecord1(atom) + + # Basic native types. Meh. + 'symbol': id + 'number': id + 'string': (atom) -> atom + 'nil': (atom) -> nil + + # Values inherited from the VM. + 'true': (atom) -> true + 'false': (atom) -> false + 'null': (atom) -> null + 'undefined': (atom) -> undefined + + methods[(car form)](car cdr form) + + +normalizeForms = (forms) -> + # Yes, this reifies the expectation than an empty list and 'nil' are + # the same. + return nil if nilp forms + cons(normalizeForm(car forms), normalizeForms(cdr forms)) + +module.exports = + normalizeForm: normalizeForm + normalizeForms: normalizeForms + + + diff --git a/test/test_reader.coffee b/test/test_reader.coffee new file mode 100644 index 0000000..43dabe9 --- /dev/null +++ b/test/test_reader.coffee @@ -0,0 +1,34 @@ +chai = require 'chai' +chai.should() +expect = chai.expect + +{cons, nil, nilp} = require "cons-lists/lists" +{read, readForms} = require '../chapter1/reader' +{normalizeForm} = require '../chapter1/astToList' + +describe "Core reader functions", -> + samples = [ + ['nil', nil] + ['0', 0] + ['1', 1] + ['500', 500] + ['0xdeadbeef', 3735928559] + ['"Foo"', 'Foo'] + ['(1)', cons(1)] + ['(1 2)', cons(1, (cons 2))] + ['(1 2 )', cons(1, (cons 2))] + ['( 1 2 )', cons(1, (cons 2))] + ['( 1 2 )', cons(1, (cons 2))] + ['("a" "b")', cons("a", (cons "b"))] + ['("a" . "b")', cons("a", "b")] + ['[]', []] + ['{}', {}] + ['[1 2 3]', [1, 2, 3]] + ['{foo "bar"}', {foo: "bar"}] + ] + + for [t, v] in samples + do (t, v) -> + it "should interpret #{t} as #{v}", -> + res = normalizeForm read t + expect(res).to.deep.equal(v)