Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

homework 5 part one - all previous unit tests passing with new enviro…

…nment structure!
  • Loading branch information...
commit 2ce86a97297f547842b9db7b004bd8870b0ecfc0 1 parent 6b73496
@ajb authored
View
BIN  .DS_Store
Binary file not shown
View
605 Homework5/parser.js
@@ -0,0 +1,605 @@
+parseScheme = (function(){
+ /*
+ * Generated by PEG.js 0.7.0.
+ *
+ * http://pegjs.majda.cz/
+ */
+
+ function quote(s) {
+ /*
+ * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a
+ * string literal except for the closing quote character, backslash,
+ * carriage return, line separator, paragraph separator, and line feed.
+ * Any character may appear in the form of an escape sequence.
+ *
+ * For portability, we also escape escape all control and non-ASCII
+ * characters. Note that "\0" and "\v" escape sequences are not used
+ * because JSHint does not like the first and IE the second.
+ */
+ return '"' + s
+ .replace(/\\/g, '\\\\') // backslash
+ .replace(/"/g, '\\"') // closing quote character
+ .replace(/\x08/g, '\\b') // backspace
+ .replace(/\t/g, '\\t') // horizontal tab
+ .replace(/\n/g, '\\n') // line feed
+ .replace(/\f/g, '\\f') // form feed
+ .replace(/\r/g, '\\r') // carriage return
+ .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape)
+ + '"';
+ }
+
+ var result = {
+ /*
+ * Parses the input with a generated parser. If the parsing is successfull,
+ * returns a value explicitly or implicitly specified by the grammar from
+ * which the parser was generated (see |PEG.buildParser|). If the parsing is
+ * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.
+ */
+ parse: function(input, startRule) {
+ var parseFunctions = {
+ "expression": parse_expression,
+ "atom": parse_atom,
+ "string": parse_string,
+ "num": parse_num,
+ "whitespace": parse_whitespace,
+ "validchar": parse_validchar,
+ "validnum": parse_validnum,
+ "inlinechar": parse_inlinechar,
+ "newlinechar": parse_newlinechar
+ };
+
+ if (startRule !== undefined) {
+ if (parseFunctions[startRule] === undefined) {
+ throw new Error("Invalid rule name: " + quote(startRule) + ".");
+ }
+ } else {
+ startRule = "expression";
+ }
+
+ var pos = 0;
+ var reportFailures = 0;
+ var rightmostFailuresPos = 0;
+ var rightmostFailuresExpected = [];
+
+ function padLeft(input, padding, length) {
+ var result = input;
+
+ var padLength = length - input.length;
+ for (var i = 0; i < padLength; i++) {
+ result = padding + result;
+ }
+
+ return result;
+ }
+
+ function escape(ch) {
+ var charCode = ch.charCodeAt(0);
+ var escapeChar;
+ var length;
+
+ if (charCode <= 0xFF) {
+ escapeChar = 'x';
+ length = 2;
+ } else {
+ escapeChar = 'u';
+ length = 4;
+ }
+
+ return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
+ }
+
+ function matchFailed(failure) {
+ if (pos < rightmostFailuresPos) {
+ return;
+ }
+
+ if (pos > rightmostFailuresPos) {
+ rightmostFailuresPos = pos;
+ rightmostFailuresExpected = [];
+ }
+
+ rightmostFailuresExpected.push(failure);
+ }
+
+ function parse_expression() {
+ var result0, result1, result2, result3, result4, result5;
+ var pos0, pos1;
+
+ result0 = parse_atom();
+ if (result0 === null) {
+ pos0 = pos;
+ pos1 = pos;
+ result0 = parse_whitespace();
+ if (result0 !== null) {
+ if (/^[']/.test(input.charAt(pos))) {
+ result1 = input.charAt(pos);
+ pos++;
+ } else {
+ result1 = null;
+ if (reportFailures === 0) {
+ matchFailed("[']");
+ }
+ }
+ if (result1 !== null) {
+ if (input.charCodeAt(pos) === 40) {
+ result2 = "(";
+ pos++;
+ } else {
+ result2 = null;
+ if (reportFailures === 0) {
+ matchFailed("\"(\"");
+ }
+ }
+ if (result2 !== null) {
+ result3 = [];
+ result4 = parse_expression();
+ while (result4 !== null) {
+ result3.push(result4);
+ result4 = parse_expression();
+ }
+ if (result3 !== null) {
+ if (input.charCodeAt(pos) === 41) {
+ result4 = ")";
+ pos++;
+ } else {
+ result4 = null;
+ if (reportFailures === 0) {
+ matchFailed("\")\"");
+ }
+ }
+ if (result4 !== null) {
+ result5 = parse_whitespace();
+ if (result5 !== null) {
+ result0 = [result0, result1, result2, result3, result4, result5];
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ if (result0 !== null) {
+ result0 = (function(offset, a) {return ["quote", a]})(pos0, result0[3]);
+ }
+ if (result0 === null) {
+ pos = pos0;
+ }
+ if (result0 === null) {
+ pos0 = pos;
+ pos1 = pos;
+ result0 = parse_whitespace();
+ if (result0 !== null) {
+ if (input.charCodeAt(pos) === 40) {
+ result1 = "(";
+ pos++;
+ } else {
+ result1 = null;
+ if (reportFailures === 0) {
+ matchFailed("\"(\"");
+ }
+ }
+ if (result1 !== null) {
+ result2 = [];
+ result3 = parse_expression();
+ while (result3 !== null) {
+ result2.push(result3);
+ result3 = parse_expression();
+ }
+ if (result2 !== null) {
+ if (input.charCodeAt(pos) === 41) {
+ result3 = ")";
+ pos++;
+ } else {
+ result3 = null;
+ if (reportFailures === 0) {
+ matchFailed("\")\"");
+ }
+ }
+ if (result3 !== null) {
+ result4 = parse_whitespace();
+ if (result4 !== null) {
+ result0 = [result0, result1, result2, result3, result4];
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ if (result0 !== null) {
+ result0 = (function(offset, a) {return [].concat(a)})(pos0, result0[2]);
+ }
+ if (result0 === null) {
+ pos = pos0;
+ }
+ }
+ }
+ return result0;
+ }
+
+ function parse_atom() {
+ var result0;
+
+ result0 = parse_num();
+ if (result0 === null) {
+ result0 = parse_string();
+ }
+ return result0;
+ }
+
+ function parse_string() {
+ var result0, result1, result2;
+ var pos0, pos1;
+
+ pos0 = pos;
+ pos1 = pos;
+ result0 = parse_whitespace();
+ if (result0 !== null) {
+ result2 = parse_validchar();
+ if (result2 !== null) {
+ result1 = [];
+ while (result2 !== null) {
+ result1.push(result2);
+ result2 = parse_validchar();
+ }
+ } else {
+ result1 = null;
+ }
+ if (result1 !== null) {
+ result2 = parse_whitespace();
+ if (result2 !== null) {
+ result0 = [result0, result1, result2];
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ if (result0 !== null) {
+ result0 = (function(offset, chars) { return chars.join(""); })(pos0, result0[1]);
+ }
+ if (result0 === null) {
+ pos = pos0;
+ }
+ return result0;
+ }
+
+ function parse_num() {
+ var result0, result1, result2;
+ var pos0, pos1;
+
+ pos0 = pos;
+ pos1 = pos;
+ result0 = parse_whitespace();
+ if (result0 !== null) {
+ result2 = parse_validnum();
+ if (result2 !== null) {
+ result1 = [];
+ while (result2 !== null) {
+ result1.push(result2);
+ result2 = parse_validnum();
+ }
+ } else {
+ result1 = null;
+ }
+ if (result1 !== null) {
+ result2 = parse_whitespace();
+ if (result2 !== null) {
+ result0 = [result0, result1, result2];
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ } else {
+ result0 = null;
+ pos = pos1;
+ }
+ if (result0 !== null) {
+ result0 = (function(offset, numerals) { return parseInt(numerals.join("")); })(pos0, result0[1]);
+ }
+ if (result0 === null) {
+ pos = pos0;
+ }
+ return result0;
+ }
+
+ function parse_whitespace() {
+ var result0, result1, result2, result3;
+ var pos0;
+
+ pos0 = pos;
+ if (input.substr(pos, 2) === ";;") {
+ result0 = ";;";
+ pos += 2;
+ } else {
+ result0 = null;
+ if (reportFailures === 0) {
+ matchFailed("\";;\"");
+ }
+ }
+ if (result0 !== null) {
+ result1 = [];
+ result2 = parse_inlinechar();
+ while (result2 !== null) {
+ result1.push(result2);
+ result2 = parse_inlinechar();
+ }
+ if (result1 !== null) {
+ result2 = [];
+ result3 = parse_newlinechar();
+ while (result3 !== null) {
+ result2.push(result3);
+ result3 = parse_newlinechar();
+ }
+ if (result2 !== null) {
+ result0 = [result0, result1, result2];
+ } else {
+ result0 = null;
+ pos = pos0;
+ }
+ } else {
+ result0 = null;
+ pos = pos0;
+ }
+ } else {
+ result0 = null;
+ pos = pos0;
+ }
+ if (result0 === null) {
+ result0 = [];
+ if (/^[ \t\r\n]/.test(input.charAt(pos))) {
+ result1 = input.charAt(pos);
+ pos++;
+ } else {
+ result1 = null;
+ if (reportFailures === 0) {
+ matchFailed("[ \\t\\r\\n]");
+ }
+ }
+ while (result1 !== null) {
+ result0.push(result1);
+ if (/^[ \t\r\n]/.test(input.charAt(pos))) {
+ result1 = input.charAt(pos);
+ pos++;
+ } else {
+ result1 = null;
+ if (reportFailures === 0) {
+ matchFailed("[ \\t\\r\\n]");
+ }
+ }
+ }
+ }
+ return result0;
+ }
+
+ function parse_validchar() {
+ var result0;
+
+ if (/^[0-9a-zA-Z_?!+-=@#$%^&*\/.]/.test(input.charAt(pos))) {
+ result0 = input.charAt(pos);
+ pos++;
+ } else {
+ result0 = null;
+ if (reportFailures === 0) {
+ matchFailed("[0-9a-zA-Z_?!+-=@#$%^&*\\/.]");
+ }
+ }
+ return result0;
+ }
+
+ function parse_validnum() {
+ var result0;
+
+ if (/^[0-9]/.test(input.charAt(pos))) {
+ result0 = input.charAt(pos);
+ pos++;
+ } else {
+ result0 = null;
+ if (reportFailures === 0) {
+ matchFailed("[0-9]");
+ }
+ }
+ return result0;
+ }
+
+ function parse_inlinechar() {
+ var result0;
+
+ if (/^[^\n]/.test(input.charAt(pos))) {
+ result0 = input.charAt(pos);
+ pos++;
+ } else {
+ result0 = null;
+ if (reportFailures === 0) {
+ matchFailed("[^\\n]");
+ }
+ }
+ return result0;
+ }
+
+ function parse_newlinechar() {
+ var result0;
+
+ if (/^[ \n\r]/.test(input.charAt(pos))) {
+ result0 = input.charAt(pos);
+ pos++;
+ } else {
+ result0 = null;
+ if (reportFailures === 0) {
+ matchFailed("[ \\n\\r]");
+ }
+ }
+ return result0;
+ }
+
+
+ function cleanupExpected(expected) {
+ expected.sort();
+
+ var lastExpected = null;
+ var cleanExpected = [];
+ for (var i = 0; i < expected.length; i++) {
+ if (expected[i] !== lastExpected) {
+ cleanExpected.push(expected[i]);
+ lastExpected = expected[i];
+ }
+ }
+ return cleanExpected;
+ }
+
+ function computeErrorPosition() {
+ /*
+ * The first idea was to use |String.split| to break the input up to the
+ * error position along newlines and derive the line and column from
+ * there. However IE's |split| implementation is so broken that it was
+ * enough to prevent it.
+ */
+
+ var line = 1;
+ var column = 1;
+ var seenCR = false;
+
+ for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) {
+ var ch = input.charAt(i);
+ if (ch === "\n") {
+ if (!seenCR) { line++; }
+ column = 1;
+ seenCR = false;
+ } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
+ line++;
+ column = 1;
+ seenCR = true;
+ } else {
+ column++;
+ seenCR = false;
+ }
+ }
+
+ return { line: line, column: column };
+ }
+
+
+ var result = parseFunctions[startRule]();
+
+ /*
+ * The parser is now in one of the following three states:
+ *
+ * 1. The parser successfully parsed the whole input.
+ *
+ * - |result !== null|
+ * - |pos === input.length|
+ * - |rightmostFailuresExpected| may or may not contain something
+ *
+ * 2. The parser successfully parsed only a part of the input.
+ *
+ * - |result !== null|
+ * - |pos < input.length|
+ * - |rightmostFailuresExpected| may or may not contain something
+ *
+ * 3. The parser did not successfully parse any part of the input.
+ *
+ * - |result === null|
+ * - |pos === 0|
+ * - |rightmostFailuresExpected| contains at least one failure
+ *
+ * All code following this comment (including called functions) must
+ * handle these states.
+ */
+ if (result === null || pos !== input.length) {
+ var offset = Math.max(pos, rightmostFailuresPos);
+ var found = offset < input.length ? input.charAt(offset) : null;
+ var errorPosition = computeErrorPosition();
+
+ throw new this.SyntaxError(
+ cleanupExpected(rightmostFailuresExpected),
+ found,
+ offset,
+ errorPosition.line,
+ errorPosition.column
+ );
+ }
+
+ return result;
+ },
+
+ /* Returns the parser source code. */
+ toSource: function() { return this._source; }
+ };
+
+ /* Thrown when a parser encounters a syntax error. */
+
+ result.SyntaxError = function(expected, found, offset, line, column) {
+ function buildMessage(expected, found) {
+ var expectedHumanized, foundHumanized;
+
+ switch (expected.length) {
+ case 0:
+ expectedHumanized = "end of input";
+ break;
+ case 1:
+ expectedHumanized = expected[0];
+ break;
+ default:
+ expectedHumanized = expected.slice(0, expected.length - 1).join(", ")
+ + " or "
+ + expected[expected.length - 1];
+ }
+
+ foundHumanized = found ? quote(found) : "end of input";
+
+ return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";
+ }
+
+ this.name = "SyntaxError";
+ this.expected = expected;
+ this.found = found;
+ this.message = buildMessage(expected, found);
+ this.offset = offset;
+ this.line = line;
+ this.column = column;
+ };
+
+ result.SyntaxError.prototype = Error.prototype;
+
+ return result;
+})();
View
28 Homework5/parser.peg
@@ -0,0 +1,28 @@
+start = expression
+
+expression =
+ atom
+ / whitespace ['] "(" a:expression* ")" whitespace
+ {return ["quote", a]}
+ / whitespace "(" a:expression* ")" whitespace
+ {return [].concat(a)}
+
+atom = num / string
+
+string =
+ whitespace chars:validchar+ whitespace
+ { return chars.join(""); }
+
+num =
+ whitespace numerals:validnum+ whitespace
+ { return parseInt(numerals.join("")); }
+
+
+whitespace =
+ ';;' inlinechar* newlinechar*
+ / [ \t\r\n]*
+
+validchar = [0-9a-zA-Z_?!+-=@#$%^&*/.]
+validnum = [0-9]
+inlinechar = [^\n]
+newlinechar = [ \n\r]
View
109 Homework5/scheem.js
@@ -0,0 +1,109 @@
+var lookup = function (env, v) {
+ if (!(env.hasOwnProperty('bindings')))
+ throw new Error(v + " not found");
+ if (env.bindings.hasOwnProperty(v))
+ return env.bindings[v];
+ return lookup(env.outer, v);
+};
+
+var update = function (env, v, val) {
+ // Your code here
+ if (!(env.hasOwnProperty('bindings'))){
+ throw new Error('Trying to set! a variable that is not yet defined.');
+ }else if(env.bindings.hasOwnProperty(v)){
+ env.bindings[v] = val;
+ }else{
+ return update(env.outer, v, val);
+ }
+ return 0;
+};
+
+var add_binding = function (env, v, val) {
+ // Your code here
+ env.bindings[v] = val;
+ return 0;
+};
+
+var evalScheem = function (expr, env) {
+
+ // fix env
+ if(typeof env === 'undefined'){
+ env = {};
+ }
+
+ if(typeof env.bindings === 'undefined'){
+ env.bindings = {};
+ }
+
+ if(typeof env.outer === 'undefined'){
+ env.outer = {};
+ }
+
+ // Numbers evaluate to themselves
+ if (typeof expr === 'number') {
+ return expr;
+ }
+
+ // Strings are variable references
+ if (typeof expr === 'string') {
+ return lookup(env, expr);
+ }
+
+ // Look at head of list for operation
+ switch (expr[0]) {
+ case '+':
+ return evalScheem(expr[1], env) + evalScheem(expr[2], env);
+ case '-':
+ return evalScheem(expr[1], env) - evalScheem(expr[2], env);
+ case '*':
+ return evalScheem(expr[1], env) * evalScheem(expr[2], env);
+ case '/':
+ return evalScheem(expr[1], env) / evalScheem(expr[2], env);
+ case 'define':
+ return add_binding(env, expr[1], evalScheem(expr[2], env));
+ case 'set!':
+ return update(env, expr[1], evalScheem(expr[2], env));
+ case 'quote':
+ if(typeof expr[2] !== 'undefined'){
+ throw new Error('Too many expressions passed to quote.');
+ }
+ return expr[1];
+ case 'begin':
+ var theArgs = expr,
+ returnVar, i;
+ theArgs.splice(0, 1);
+ for (i = 0; i < theArgs.length; ++i) {
+ returnVar = evalScheem(theArgs[i], env);
+ }
+ return returnVar;
+ case '<':
+ var predicate = (evalScheem(expr[1], env) < evalScheem(expr[2], env));
+ if (predicate) return '#t';
+ return '#f';
+ case 'cons':
+ var cons = evalScheem(expr[2], env);
+ cons.unshift(evalScheem(expr[1], env));
+ return cons;
+ case 'car':
+ return evalScheem(expr[1], env)[0];
+ case 'cdr':
+ var cdr = evalScheem(expr[1], env);
+ cdr.splice(0, 1);
+ return cdr;
+ case '=':
+ var eq = (evalScheem(expr[1], env) === evalScheem(expr[2], env));
+ if (eq) return '#t';
+ return '#f';
+ case 'if':
+ if (evalScheem(expr[1], env) == '#t') {
+ return evalScheem(expr[2], env);
+ } else {
+ return evalScheem(expr[3], env);
+ }
+ }
+ };
+
+// If we are used as Node module, export evalScheem
+if (typeof module !== 'undefined') {
+ module.exports.evalScheem = evalScheem;
+}
View
277 Homework5/test/evalScheemTest.js
@@ -0,0 +1,277 @@
+if (typeof module !== 'undefined') {
+ // In Node load required modules
+ var assert = require('chai').assert;
+ var expect = require('chai').expect;
+ var evalScheem = require('../scheem').evalScheem;
+
+ var PEG = require('pegjs');
+ var fs = require('fs'); // for loading files
+
+ // Read file contents
+ var data = fs.readFileSync('parser.peg', 'utf-8');
+
+ // Create my parser
+ var parseScheme = PEG.buildParser(data).parse;
+
+} else {
+ // In browser assume already loaded by <script> tags
+ var assert = chai.assert;
+ var expect = chai.expect;
+ var parseScheme = parseScheme.parse;
+}
+
+var evalSchemeString = function(schemeString, env) {
+ return evalScheem(parseScheme(schemeString), env);
+}
+
+suite('scheem', function(){
+ suite('arithmetic', function () {
+ test('addition', function () {
+ assert.deepEqual(
+ evalScheem(['+', 1, 1], {}), 2);
+ });
+
+ test('subtraction', function () {
+ assert.deepEqual(
+ evalScheem(['-', 3, 1], {}), 2);
+ });
+
+ test('multiplication', function () {
+ assert.deepEqual(
+ evalScheem(['*', 4, 0.5], {}), 2);
+ });
+
+ test('division', function () {
+ assert.deepEqual(
+ evalScheem(['/', 4, 2], {}), 2);
+ });
+ });
+
+ suite('quote', function () {
+ test('a number', function () {
+ assert.deepEqual(
+ evalScheem(['quote', 3], {}), 3);
+ });
+ test('an atom', function () {
+ assert.deepEqual(
+ evalScheem(['quote', 'dog'], {}), 'dog');
+ });
+ test('a list', function () {
+ assert.deepEqual(
+ evalScheem(['quote', [1, 2, 3]], {}), [1, 2, 3]);
+ });
+ });
+
+ suite('definitions', function () {
+ test('define returns 0', function () {
+ assert.deepEqual(
+ evalScheem(['define', 'c', 4], {}), 0);
+ });
+
+ test('set! returns 0', function () {
+ assert.deepEqual(
+ evalScheem(['set!', 'a', 1], {bindings: {a: 0}}), 0);
+ });
+
+ test('begin', function () {
+ assert.deepEqual(
+ evalScheem(['begin', 'x', 'y', 'x'], {bindings: {
+ x: 1,
+ y: 2
+ }}), 1);
+ });
+
+ test('begin and set', function () {
+ assert.deepEqual(
+ evalScheem(['begin', ['set!', 'x', 5],
+ ['set!', 'x', ['+', 'y', 'x']], 'x'], {bindings: {
+ x: 1,
+ y: 2
+ }}), 7);
+ });
+ });
+
+ suite('if', function () {
+ test('basic predicate', function () {
+ assert.deepEqual(
+ evalScheem(['<', 1, 2]), '#t');
+
+ assert.deepEqual(
+ evalScheem(['<', 2, 1]), '#f');
+ });
+
+ test('if statement with predicate', function () {
+ assert.deepEqual(
+ evalScheem(['if', ['<', 1, 2], 5, 6], {}), 5);
+
+ assert.deepEqual(
+ evalScheem(['if', ['<', 2, 1], 5, 6], {}), 6);
+ })
+
+ test('if statement with equals', function () {
+ assert.deepEqual(
+ evalScheem(['if', ['=', 1, 1], 5, 6], {}), 5);
+
+ assert.deepEqual(
+ evalScheem(['if', ['=', 2, 1], 5, 6], {}), 6);
+ })
+ });
+
+ suite('list values', function () {
+ test('cons', function () {
+ assert.deepEqual(
+ evalScheem(['cons', 1, ['quote', [2, 3]]]), [1, 2, 3]);
+ });
+
+ test('car', function () {
+ assert.deepEqual(
+ evalScheem(['car', ['quote', [1, 2, 3]]]), 1);
+ });
+
+ test('cdr', function () {
+ assert.deepEqual(
+ evalScheem(['cdr', ['quote', [1, 2, 3]]]), [2, 3]);
+ });
+ });
+
+ suite('error checking', function() {
+ test('undefined set!', function() {
+ expect(function () {
+ evalScheem(['set!', 'c', 4], {});
+ }).to.throw(Error, 'Trying to set! a variable that is not yet defined.');
+ });
+
+ test('multiple expressions to quote', function () {
+ expect(function () {
+ evalScheem(['quote', 'a', 'b'], {});
+ }).to.throw(Error, 'Too many expressions passed to quote.');
+ });
+ });
+});
+
+suite('scheme', function(){
+ suite('arithmetic', function () {
+ test('addition', function () {
+ assert.deepEqual(
+ evalSchemeString('(+ 2 1)', {}), 3);
+ });
+
+ test('subtraction', function () {
+ assert.deepEqual(
+ evalSchemeString('(- 2 1)', {}), 1);
+ });
+
+ test('multiplication', function () {
+ assert.deepEqual(
+ evalSchemeString('(* 2 1)', {}), 2);
+ });
+
+ test('division', function () {
+ assert.deepEqual(
+ evalSchemeString('(/ 2 1)', {}), 2);
+ });
+ });
+
+ suite('quote', function () {
+ test('a number', function () {
+ assert.deepEqual(
+ evalSchemeString("(quote 3)", {}), 3);
+ });
+ test('an atom', function () {
+ assert.deepEqual(
+ evalSchemeString('(quote dog)', {}), 'dog');
+ });
+ test('a list', function () {
+ assert.deepEqual(
+ evalSchemeString('(quote (1 2 3))', {}), [1, 2, 3]);
+ });
+ });
+
+ suite('definitions', function () {
+ test('define returns 0', function () {
+ assert.deepEqual(
+ evalSchemeString('(define c 4)', {}), 0);
+ });
+
+ test('set! returns 0', function () {
+ assert.deepEqual(
+ evalSchemeString('(set! c 4)', {bindings: {c: 1}}), 0);
+ });
+
+ test('begin', function () {
+ assert.deepEqual(
+ evalSchemeString('(begin x y x)', {bindings: {
+ x: 1,
+ y: 2
+ }}), 1);
+ });
+
+ test('begin and set', function () {
+ assert.deepEqual(
+ evalSchemeString('(begin (set! x 5) (set! x (+ y x)) x)', {bindings: {
+ x: 1,
+ y: 2
+ }}), 7);
+ });
+ });
+
+ suite('if', function () {
+ test('basic predicate', function () {
+ assert.deepEqual(
+ evalSchemeString('(< 1 2)'), '#t');
+
+ assert.deepEqual(
+ evalSchemeString('(< 2 1)'), '#f');
+ });
+
+ test('if statement with predicate', function () {
+ assert.deepEqual(
+ evalSchemeString('(if (< 1 2) 5 6)', {}), 5);
+
+ assert.deepEqual(
+ evalSchemeString('(if (< 2 1) 5 6)', {}), 6);
+ })
+
+ test('if statement with equals', function () {
+ assert.deepEqual(
+ evalSchemeString('(if (= 1 1) 5 6)', {}), 5);
+
+ assert.deepEqual(
+ evalSchemeString('(if (= 2 1) 5 6)', {}), 6);
+ })
+ });
+ suite('list values', function () {
+ test('cons', function () {
+ assert.deepEqual(
+ evalSchemeString('(cons 1 (quote (2 3)))'), [1, 2, 3]);
+
+ });
+
+ test('car', function () {
+ assert.deepEqual(
+ evalSchemeString('(car (quote (1 2 3)))'), 1);
+
+ });
+
+ test('cdr', function () {
+ assert.deepEqual(
+ evalSchemeString('(cdr (quote (1 2 3)))'), [2, 3]);
+ });
+ });
+
+ suite('error checking', function() {
+ test('undefined set!', function() {
+ expect(function () {
+ evalSchemeString('(set! c 4)', {});
+ }).to.throw(Error, 'Trying to set! a variable that is not yet defined.');
+ });
+
+ test('multiple expressions to quote', function () {
+ expect(function () {
+ evalSchemeString('(quote a b)', {});
+ }).to.throw(Error, 'Too many expressions passed to quote.');
+ });
+ });
+
+});
+
View
76 Homework5/test/livetest.html
@@ -0,0 +1,76 @@
+<!doctype html>
+<html>
+<head>
+ <title></title>
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
+ <script src="../scheem.js"></script>
+ <script src="../parser.js"></script>
+ <script>
+ // Utility function to log messages
+ var log_console = function(msg) {
+ $('#output').append(msg);
+ };
+ // After page load
+ $(function() {
+ $('#submit-btn').click(function() {
+ var user_text = $('#input').val();
+ $('#output').html(''); // clear console
+ log_console('Your input was: "' + user_text + '"<br />');
+ try {
+ var parsed = parseScheme.parse(user_text);
+ log_console('Parsed: ' + JSON.stringify(parsed) + '<br />');
+ try {
+ var result = evalScheem(parsed, {});
+ log_console('Result: ' + JSON.stringify(result));
+ }
+ catch(e) {
+ log_console('Eval Error: ' + e);
+ }
+ }
+ catch(e) {
+ log_console('Parse Error: ' + e);
+ }
+ });
+ });
+ </script>
+ <style type="text/css">
+ body {
+ background-color: #222;
+ color: #fff;
+ }
+
+ #container {
+ width: 500px;
+ margin: 0 auto;
+ }
+
+ textarea {
+ display: block;
+ width: 500px;
+ height: 100px;
+ }
+
+ input[type=button] {
+ cursor: pointer;
+ width: 506px;
+ background-color: #0045cc;
+ border: 0;
+ line-height: 25px;
+ font-weight: bold;
+ margin-top: 5px;
+ }
+
+ input[type=button]:hover {
+ background-color: #0340b2;
+ }
+ </style>
+</head>
+<body>
+ <div id="container">
+ <h1>Scheem Parser <small>by <a href="http://ada.mbecker.cc" target="_blank">adamjacobbecker</a></small></h1>
+ <textarea id="input">(+ 1 2)</textarea>
+ <input type="button" id="submit-btn" value="Run" />
+ <div id="output"></div>
+ </div>
+</body>
+</html>
View
23 Homework5/test/webtest.html
@@ -0,0 +1,23 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Mocha Tests</title>
+ <link rel="stylesheet"
+ href="http://nathansuniversity.com/css/mocha.css" />
+ <script src="http://nathansuniversity.com/js/jquery-1.7.1.min.js"></script>
+ <script src="http://nathansuniversity.com/js/chai.js"></script>
+ <script src="http://nathansuniversity.com/js/mocha.js"></script>
+ <script src="../parser.js"></script>
+ <script>mocha.setup('tdd')</script>
+ <script src="../scheem.js"></script>
+ <script src="evalScheemTest.js"></script>
+ <script>
+ $(function(){
+ mocha.run();
+ });
+ </script>
+</head>
+<body>
+ <div id="mocha"></div>
+</body>
+</html>
Please sign in to comment.
Something went wrong with that request. Please try again.