config/emacs.d/swank-js/lisp-tests.js
2011-06-26 15:55:20 -07:00

273 lines
12 KiB
JavaScript

// -*- mode: js2; js-run: t -*-
//
// Copyright (c) 2010 Ivan Shvedunov. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
var lisp = require("./lisp");
var assert = require("assert");
var S = lisp.S, cons = lisp.cons, consp = lisp.consp, car = lisp.car, cdr = lisp.cdr,
nil = lisp.nil, nullp = lisp.nullp, listp = lisp.listp, list = lisp.list,
reverse = lisp.reverse, append = lisp.append, repr = lisp.repr,
StringInputStream = lisp.StringInputStream,
readFromString = lisp.readFromString,
fromLisp = lisp.fromLisp,
toLisp = lisp.toLisp;
assert.equal(S("zzz"), S("zzz"));
assert.deepEqual(cons(1, cons(2, cons(3, nil))), list(1, 2, 3));
assert.equal("abc", car(cons("abc", "def")));
assert.equal("def", cdr(cons("abc", "def")));
assert.equal(nil, list());
assert.ok(consp(cons(1, 2)));
assert.ok(!consp(nil));
assert.ok(listp(cons(1, 2)));
assert.ok(listp(list(1, 2)));
assert.ok(listp(nil));
assert.ok(nullp(nil));
assert.ok(!nullp(cons(1, 2)));
assert.ok(!nullp(1));
assert.deepEqual(list(), reverse(list()));
assert.deepEqual(list(1), reverse(list(1)));
assert.deepEqual(list(3, 2, 1), reverse(list(1, 2, 3)));
assert.deepEqual(nil, append(nil, nil));
assert.deepEqual(list(1), append(list(1), nil));
assert.deepEqual(list(1), append(nil, list(1)));
assert.deepEqual(list(1, 2, 3), append(list(1, 2), list(3)));
assert.deepEqual(list(1, 2, 3, 4), append(list(1, 2), list(3, 4)));
var s = new StringInputStream("abc");
assert.equal(0, s.pos());
assert.equal("a", s.getc());
assert.equal(1, s.pos());
assert.equal("b", s.readchar());
assert.equal(2, s.pos());
assert.equal("c", s.readchar());
assert.equal(3, s.pos());
assert.equal(null, s.getc());
assert.equal(3, s.pos());
assert["throws"](function () { s.readchar(); });
assert.equal(3, s.pos());
s.ungetc("c");
assert.equal(2, s.pos());
assert.equal("c", s.getc());
assert.equal(3, s.pos());
assert["throws"](function () { s.ungetc("z"); });
assert.equal(3, s.pos());
s.ungetc("c");
s.ungetc("b");
assert.equal(1, s.pos());
assert.equal("b", s.getc());
assert.equal("c", s.getc());
assert.equal(3, s.pos());
s.ungetc("c");
s.ungetc("b");
s.ungetc("a");
assert.equal(0, s.pos());
assert["throws"](function () { s.ungetc("z"); });
assert["throws"](function () { s.ungetc(""); });
assert.equal(0, s.pos());
assert.equal("a", s.readchar());
assert.equal("b", s.readchar());
assert.equal("c", s.readchar());
assert.equal(3, s.pos());
s = new StringInputStream("");
assert.equal(0, s.pos());
assert["throws"](function () { s.ungetc("z"); });
assert["throws"](function () { s.ungetc(""); });
assert.equal(null, s.getc());
assert["throws"](function () { s.readchar(); });
assert.equal(0, s.pos());
function test_read (str, o) {
assert.equal(str, repr(o));
var rs = readFromString(str);
assert.deepEqual(o, rs);
assert.equal(str, repr(rs));
};
test_read("zzz", S("zzz"));
test_read("'zzz", list(S("quote"), S("zzz")));
test_read('"zzz"', "zzz");
test_read('"zz\nz"', "zz\nz");
test_read('\'"zzz"', list(S("quote"), "zzz"));
test_read('"z\\"z\\\\z"', "z\"z\\z");
test_read("nil", nil);
test_read("(1)", list(1));
test_read("(1 2)", list(1, 2));
test_read("(1 2 4.25)", list(1, 2, 4.25));
test_read("(1 2 eprst)", list(1, 2, S("eprst")));
test_read('(1 2 eprst ("abra" "kodabra"))',
list(1, 2, S("eprst"), list("abra", "kodabra")));
test_read('(1 2 eprst ("abra" . "kodabra"))',
list(1, 2, S("eprst"), cons("abra", "kodabra")));
test_read('(1 2 eprst ("abra" "kodabra" .schwabbra))',
list(1, 2, S("eprst"), list("abra", "kodabra", S(".schwabbra"))));
test_read('(1 2 eprst ("abra" "kodabra" .schwabbra . QQQ))',
list(1, 2, S("eprst"),
cons("abra",cons("kodabra", cons(S(".schwabbra"), S("QQQ"))))));
test_read('(1 2 eprst \'("abra" "kodabra" .schwabbra . QQQ))',
list(1, 2, S("eprst"),
list(S("quote"),
cons("abra", cons("kodabra", cons(S(".schwabbra"), S("QQQ")))))));
test_read("(1 2 3)", list(1, 2, 3));
test_read("(1 2 3 (4 5 6))", list(1, 2, 3, list(4, 5, 6)));
test_read("((4 5 6) . 7)", cons(list(4, 5, 6), 7));
test_read("((4 5 6) 7 8 . :eprst)",
cons(list(4, 5, 6), cons(7, cons(8, S(":eprst")))));
test_read("((4 5 6) 7 8 . swank:connection-info)",
cons(list(4, 5, 6), cons(7, cons(8, S("swank:connection-info")))));
var CONV_ERROR = {};
function test_conversion(spec, source, expectedResult, reconverted) {
var r, l = readFromString(source);
try {
r = spec === null ? fromLisp(l) : fromLisp(l, spec);
} catch (e) {
if (e instanceof TypeError && /^error converting/.test(e.message))
r = CONV_ERROR;
else
throw e;
}
assert.deepEqual(expectedResult, r);
if (r !== CONV_ERROR)
assert.equal(reconverted || source, repr(spec === null ? toLisp(r) : toLisp(r, spec)));
}
test_conversion("N", "1", 1);
test_conversion("K", ":abc", "abc");
test_conversion("K", "nil", null);
test_conversion("B", "t", true);
test_conversion("B", "nil", false);
test_conversion("B", "123", true, "t");
test_conversion("B", ":zzz", true, "t");
test_conversion("@", '(test nil () 123 "456" :zzz (1 2 3) (4 . 5))',
["test", null, null, 123, "456", ":zzz", [1, 2, 3], [4, 5]],
'("test" nil nil 123 "456" ":zzz" (1 2 3) (4 5))');
test_conversion(null, '(test nil () 123 "456" :zzz (1 2 3) (4 . 5))',
["test", null, null, 123, "456", ":zzz", [1, 2, 3], [4, 5]],
'("test" nil nil 123 "456" ":zzz" (1 2 3) (4 5))');
test_conversion(["N:one"], "(1)", { one: 1 });
test_conversion(["N:one", "N:two", "N:three"], "(1 2 3)", { one: 1, two: 2, three: 3 });
test_conversion(["N:one", "N:two", "N:three"], "(1 2)", CONV_ERROR);
test_conversion(["N:one", "N:two", "s:zzz"], '(1 2 "qqqq")', { one: 1, two: 2, zzz: "qqqq" });
test_conversion(["N:one", "N:two", "s:zzz"], '(1 2 3)', CONV_ERROR);
test_conversion(["N:one", "N:two", "s:zzz"], '(1 2 :RRR)', CONV_ERROR);
test_conversion(["S:op", "_:form", "_:packageName", "_:threadId", "N:id"],
'(:emacs-rex (swank:connection-info) "COMMON-LISP-USER" t 1)',
{ op: ":emacs-rex",
form: list(S("swank:connection-info")),
packageName: "COMMON-LISP-USER",
threadId: S("t"),
id: 1 });
test_conversion(["@:x"], "(test)", { x: "test" }, '("test")');
test_conversion(["@:x"], '((test 123 "456" :zzz (1 2 3) (4 . 5)))',
{ x: ["test", 123, "456", ":zzz", [1, 2, 3], [4, 5]] },
'(("test" 123 "456" ":zzz" (1 2 3) (4 5)))');
test_conversion(["S:name", "R:args"], '(test)',
{ name: "test",
args: [] });
test_conversion(["S:name", "R:args"], '(test :abc :def "QQQ" 123)',
{ name: "test",
args: [":abc", ":def", "QQQ", 123] },
'(test ":abc" ":def" "QQQ" 123)');
test_conversion(["S:name", "R*:args"], '(test)',
{ name: "test",
args: [] });
test_conversion(["S:name", "R*:args"], '(test :abc :def (123 . 456))',
{ name: "test",
args: [S(":abc"), S(":def"), cons(123, 456)] });
test_conversion(["N:n", "D:dict"], '(42.25 ())',
{ n: 42.25, dict: {} },
'(42.25 nil)');
test_conversion(["N:n", "D:dict"], '(42.25 (:x 3))',
{ n: 42.25, dict: { x: 3 } });
test_conversion(["N:n", "D:dict"], '(42.25 (:x))', CONV_ERROR);
test_conversion(["N:n", "D:dict"], '(42.25 (:x :y :z))', CONV_ERROR);
test_conversion(["N:n", "D:dict"], '(42.25 (:x 3 :abc "fff" :zzz qwerty))',
{ n: 42.25, dict: { x: 3, abc: "fff", zzz: "qwerty" }},
'(42.25 (:abc "fff" :x 3 :zzz "qwerty"))');
test_conversion(["N:n", "D*:dict"], '(42.25 ())',
{ n: 42.25, dict: {} },
'(42.25 nil)');
test_conversion(["N:n", "D*:dict"], '(42.25 (:x 3))',
{ n: 42.25, dict: { x: 3 } });
test_conversion(["N:n", "D*:dict"], '(42.25 (:x))', CONV_ERROR);
test_conversion(["N:n", "D*:dict"], '(42.25 (:x :y :z))', CONV_ERROR);
test_conversion(["N:n", "D*:dict"], '(42.25 (:x 3 :abc "fff" :zzz qwerty))',
{ n: 42.25, dict: { x: 3, abc: "fff", zzz: S("qwerty") } },
'(42.25 (:abc "fff" :x 3 :zzz qwerty))');
test_conversion(["N:n", "RD:dict"], '(42.25)',
{ n: 42.25, dict: {} });
test_conversion(["N:n", "RD:dict"], '(42.25 :x 3)',
{ n: 42.25, dict: { x: 3 } });
test_conversion(["N:n", "RD:dict"], '(42.25 :x)', CONV_ERROR);
test_conversion(["N:n", "RD:dict"], '(42.25 :x 3 :abc "fff" :zzz qwerty)',
{ n: 42.25, dict: { x: 3, abc: "fff", zzz: "qwerty" }},
'(42.25 :abc "fff" :x 3 :zzz "qwerty")');
test_conversion(["N:n", "RD*:dict"], '(42.25)',
{ n: 42.25, dict: {} });
test_conversion(["N:n", "RD*:dict"], '(42.25 :x 3)',
{ n: 42.25, dict: { x: 3 } });
test_conversion(["N:n", "RD*:dict"], '(42.25 :x)', CONV_ERROR);
test_conversion(["N:n", "RD*:dict"], '(42.25 :x 3 :abc "fff" :zzz qwerty)',
{ n: 42.25, dict: { x: 3, abc: "fff", zzz: S("qwerty") } },
'(42.25 :abc "fff" :x 3 :zzz qwerty)');
test_conversion({ x: "N", "abc-def": "D:abcDef", name: "S", rrr: "_:r1", qqq: "_" },
'(:abc-def (:x 3 :y 9) :x 42 :name :abcd :rrr "whatever" :unused 99)',
{ x: 42, abcDef: { x: 3, y: 9 }, name: ":abcd", r1: "whatever" },
'(:abc-def (:x 3 :y 9) :name :abcd :rrr "whatever" :x 42)');
// > and >* tell arrayValue to consume the next argument as type value
test_conversion(["S:name", ">:dict", { x: "N", y: "S" }],
'(:somename (:x 32 :y :zzz))',
{ name: ":somename", dict: { x: 32, y: ":zzz" } });
test_conversion(["S:name", ">*:dict", { x: "N", y: "S" }],
'(:somename :x 32 :y :zzz)',
{ name: ":somename", dict: { x: 32, y: ":zzz" } });
test_conversion({ x: "N", l: { name: "theList", spec: ["S:name", "N:n", "K:keyword"] },
d: { name: "dict1", spec: { a: "N", b: "N" } },
d2: { spec: { a: "N", b: "N" } }},
'(:x 99 :l (zzz 42 :eprst) :d (:a 11 :b 12) :d2 (:a 1 :b 2))',
{ x: 99,
theList: { name: "zzz", n: 42, keyword: "eprst" },
dict1: { a: 11, b: 12 },
d2: { a: 1, b : 2 } },
'(:d (:a 11 :b 12) :d2 (:a 1 :b 2) :l (zzz 42 :eprst) :x 99)');
assert.equal("(:abc 12 :def 4242)", repr(toLisp({ abc: 12, def: 4242 }, "@")));
assert.equal("(:abc 19)", repr(toLisp({ x: 19 }, [S(":abc"), "N:x"])));
assert.equal("(abc 19 :def)", repr(toLisp({ x: 19 }, [S("abc"), "N:x", S(":def")])));
assert.equal("nil", repr(toLisp(null, "@")));
assert.equal("nil", repr(toLisp(null, "_")));
// TBD: toLisp should use "@" as spec by default