summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-03-03 14:20:36 -0700
committerElizabeth Hunt <elizabeth.hunt@simponic.xyz>2024-03-03 14:22:51 -0700
commite2e74df94fcdd2f3165e035fc00c98573f0b40d8 (patch)
tree362943ba180b3ba0298473855e2622f7560c84aa
parent4233aca561b5650924f3cc4232cfd294d706c863 (diff)
downloadthe-abstraction-engine-e2e74df94fcdd2f3165e035fc00c98573f0b40d8.tar.gz
the-abstraction-engine-e2e74df94fcdd2f3165e035fc00c98573f0b40d8.zip
add parser
-rw-r--r--src/interpreter/PeggyParser.js896
-rw-r--r--src/interpreter/grammar.pegjs17
-rw-r--r--src/interpreter/index.ts2
-rw-r--r--src/interpreter/interpreter.ts10
-rw-r--r--src/interpreter/parser.ts35
-rw-r--r--tsconfig.json4
6 files changed, 963 insertions, 1 deletions
diff --git a/src/interpreter/PeggyParser.js b/src/interpreter/PeggyParser.js
new file mode 100644
index 0000000..5671d91
--- /dev/null
+++ b/src/interpreter/PeggyParser.js
@@ -0,0 +1,896 @@
+// @generated by Peggy 4.0.2.
+//
+// https://peggyjs.org/
+export default (function () {
+ "use strict";
+
+ function peg$subclass(child, parent) {
+ function C() {
+ this.constructor = child;
+ }
+ C.prototype = parent.prototype;
+ child.prototype = new C();
+ }
+
+ function peg$SyntaxError(message, expected, found, location) {
+ var self = Error.call(this, message);
+ // istanbul ignore next Check is a necessary evil to support older environments
+ if (Object.setPrototypeOf) {
+ Object.setPrototypeOf(self, peg$SyntaxError.prototype);
+ }
+ self.expected = expected;
+ self.found = found;
+ self.location = location;
+ self.name = "SyntaxError";
+ return self;
+ }
+
+ peg$subclass(peg$SyntaxError, Error);
+
+ function peg$padEnd(str, targetLength, padString) {
+ padString = padString || " ";
+ if (str.length > targetLength) {
+ return str;
+ }
+ targetLength -= str.length;
+ padString += padString.repeat(targetLength);
+ return str + padString.slice(0, targetLength);
+ }
+
+ peg$SyntaxError.prototype.format = function (sources) {
+ var str = "Error: " + this.message;
+ if (this.location) {
+ var src = null;
+ var k;
+ for (k = 0; k < sources.length; k++) {
+ if (sources[k].source === this.location.source) {
+ src = sources[k].text.split(/\r\n|\n|\r/g);
+ break;
+ }
+ }
+ var s = this.location.start;
+ var offset_s =
+ this.location.source &&
+ typeof this.location.source.offset === "function"
+ ? this.location.source.offset(s)
+ : s;
+ var loc =
+ this.location.source + ":" + offset_s.line + ":" + offset_s.column;
+ if (src) {
+ var e = this.location.end;
+ var filler = peg$padEnd("", offset_s.line.toString().length, " ");
+ var line = src[s.line - 1];
+ var last = s.line === e.line ? e.column : line.length + 1;
+ var hatLen = last - s.column || 1;
+ str +=
+ "\n --> " +
+ loc +
+ "\n" +
+ filler +
+ " |\n" +
+ offset_s.line +
+ " | " +
+ line +
+ "\n" +
+ filler +
+ " | " +
+ peg$padEnd("", s.column - 1, " ") +
+ peg$padEnd("", hatLen, "^");
+ } else {
+ str += "\n at " + loc;
+ }
+ }
+ return str;
+ };
+
+ peg$SyntaxError.buildMessage = function (expected, found) {
+ var DESCRIBE_EXPECTATION_FNS = {
+ literal: function (expectation) {
+ return '"' + literalEscape(expectation.text) + '"';
+ },
+
+ class: function (expectation) {
+ var escapedParts = expectation.parts.map(function (part) {
+ return Array.isArray(part)
+ ? classEscape(part[0]) + "-" + classEscape(part[1])
+ : classEscape(part);
+ });
+
+ return (
+ "[" + (expectation.inverted ? "^" : "") + escapedParts.join("") + "]"
+ );
+ },
+
+ any: function () {
+ return "any character";
+ },
+
+ end: function () {
+ return "end of input";
+ },
+
+ other: function (expectation) {
+ return expectation.description;
+ },
+ };
+
+ function hex(ch) {
+ return ch.charCodeAt(0).toString(16).toUpperCase();
+ }
+
+ function literalEscape(s) {
+ return s
+ .replace(/\\/g, "\\\\")
+ .replace(/"/g, '\\"')
+ .replace(/\0/g, "\\0")
+ .replace(/\t/g, "\\t")
+ .replace(/\n/g, "\\n")
+ .replace(/\r/g, "\\r")
+ .replace(/[\x00-\x0F]/g, function (ch) {
+ return "\\x0" + hex(ch);
+ })
+ .replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) {
+ return "\\x" + hex(ch);
+ });
+ }
+
+ function classEscape(s) {
+ return s
+ .replace(/\\/g, "\\\\")
+ .replace(/\]/g, "\\]")
+ .replace(/\^/g, "\\^")
+ .replace(/-/g, "\\-")
+ .replace(/\0/g, "\\0")
+ .replace(/\t/g, "\\t")
+ .replace(/\n/g, "\\n")
+ .replace(/\r/g, "\\r")
+ .replace(/[\x00-\x0F]/g, function (ch) {
+ return "\\x0" + hex(ch);
+ })
+ .replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) {
+ return "\\x" + hex(ch);
+ });
+ }
+
+ function describeExpectation(expectation) {
+ return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
+ }
+
+ function describeExpected(expected) {
+ var descriptions = expected.map(describeExpectation);
+ var i, j;
+
+ descriptions.sort();
+
+ if (descriptions.length > 0) {
+ for (i = 1, j = 1; i < descriptions.length; i++) {
+ if (descriptions[i - 1] !== descriptions[i]) {
+ descriptions[j] = descriptions[i];
+ j++;
+ }
+ }
+ descriptions.length = j;
+ }
+
+ switch (descriptions.length) {
+ case 1:
+ return descriptions[0];
+
+ case 2:
+ return descriptions[0] + " or " + descriptions[1];
+
+ default:
+ return (
+ descriptions.slice(0, -1).join(", ") +
+ ", or " +
+ descriptions[descriptions.length - 1]
+ );
+ }
+ }
+
+ function describeFound(found) {
+ return found ? '"' + literalEscape(found) + '"' : "end of input";
+ }
+
+ return (
+ "Expected " +
+ describeExpected(expected) +
+ " but " +
+ describeFound(found) +
+ " found."
+ );
+ };
+
+ function peg$parse(input, options) {
+ options = options !== undefined ? options : {};
+
+ var peg$FAILED = {};
+ var peg$source = options.grammarSource;
+
+ var peg$startRuleFunctions = { LambdaTerm: peg$parseLambdaTerm };
+ var peg$startRuleFunction = peg$parseLambdaTerm;
+
+ var peg$c0 = "(";
+ var peg$c1 = ")";
+ var peg$c2 = ".";
+ var peg$c3 = "\r\n";
+
+ var peg$r0 = /^[a-zA-Z0-9]/;
+ var peg$r1 = /^[\\\u03BB]/;
+ var peg$r2 = /^[\t-\n ]/;
+
+ var peg$e0 = peg$classExpectation(
+ [
+ ["a", "z"],
+ ["A", "Z"],
+ ["0", "9"],
+ ],
+ false,
+ false,
+ );
+ var peg$e1 = peg$literalExpectation("(", false);
+ var peg$e2 = peg$literalExpectation(")", false);
+ var peg$e3 = peg$literalExpectation(".", false);
+ var peg$e4 = peg$classExpectation(["\\", "\u03BB"], false, false);
+ var peg$e5 = peg$classExpectation([["\t", "\n"], " "], false, false);
+ var peg$e6 = peg$literalExpectation("\r\n", false);
+
+ var peg$f0 = function (left, argList, lastArg) {
+ const args =
+ lastArg || argList.length ? [...argList.map((x) => x[0]), lastArg] : [];
+ return { application: { left, args } };
+ };
+ var peg$f1 = function (param, body) {
+ return { abstraction: { param, body } };
+ };
+ var peg$f2 = function (param) {
+ return param.join("");
+ };
+ var peg$currPos = options.peg$currPos | 0;
+ var peg$savedPos = peg$currPos;
+ var peg$posDetailsCache = [{ line: 1, column: 1 }];
+ var peg$maxFailPos = peg$currPos;
+ var peg$maxFailExpected = options.peg$maxFailExpected || [];
+ var peg$silentFails = options.peg$silentFails | 0;
+
+ var peg$resultsCache = {};
+
+ var peg$result;
+
+ if (options.startRule) {
+ if (!(options.startRule in peg$startRuleFunctions)) {
+ throw new Error(
+ "Can't start parsing from rule \"" + options.startRule + '".',
+ );
+ }
+
+ peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
+ }
+
+ function text() {
+ return input.substring(peg$savedPos, peg$currPos);
+ }
+
+ function offset() {
+ return peg$savedPos;
+ }
+
+ function range() {
+ return {
+ source: peg$source,
+ start: peg$savedPos,
+ end: peg$currPos,
+ };
+ }
+
+ function location() {
+ return peg$computeLocation(peg$savedPos, peg$currPos);
+ }
+
+ function expected(description, location) {
+ location =
+ location !== undefined
+ ? location
+ : peg$computeLocation(peg$savedPos, peg$currPos);
+
+ throw peg$buildStructuredError(
+ [peg$otherExpectation(description)],
+ input.substring(peg$savedPos, peg$currPos),
+ location,
+ );
+ }
+
+ function error(message, location) {
+ location =
+ location !== undefined
+ ? location
+ : peg$computeLocation(peg$savedPos, peg$currPos);
+
+ throw peg$buildSimpleError(message, location);
+ }
+
+ function peg$literalExpectation(text, ignoreCase) {
+ return { type: "literal", text: text, ignoreCase: ignoreCase };
+ }
+
+ function peg$classExpectation(parts, inverted, ignoreCase) {
+ return {
+ type: "class",
+ parts: parts,
+ inverted: inverted,
+ ignoreCase: ignoreCase,
+ };
+ }
+
+ function peg$anyExpectation() {
+ return { type: "any" };
+ }
+
+ function peg$endExpectation() {
+ return { type: "end" };
+ }
+
+ function peg$otherExpectation(description) {
+ return { type: "other", description: description };
+ }
+
+ function peg$computePosDetails(pos) {
+ var details = peg$posDetailsCache[pos];
+ var p;
+
+ if (details) {
+ return details;
+ } else {
+ if (pos >= peg$posDetailsCache.length) {
+ p = peg$posDetailsCache.length - 1;
+ } else {
+ p = pos;
+ while (!peg$posDetailsCache[--p]) {}
+ }
+
+ details = peg$posDetailsCache[p];
+ details = {
+ line: details.line,
+ column: details.column,
+ };
+
+ while (p < pos) {
+ if (input.charCodeAt(p) === 10) {
+ details.line++;
+ details.column = 1;
+ } else {
+ details.column++;
+ }
+
+ p++;
+ }
+
+ peg$posDetailsCache[pos] = details;
+
+ return details;
+ }
+ }
+
+ function peg$computeLocation(startPos, endPos, offset) {
+ var startPosDetails = peg$computePosDetails(startPos);
+ var endPosDetails = peg$computePosDetails(endPos);
+
+ var res = {
+ source: peg$source,
+ start: {
+ offset: startPos,
+ line: startPosDetails.line,
+ column: startPosDetails.column,
+ },
+ end: {
+ offset: endPos,
+ line: endPosDetails.line,
+ column: endPosDetails.column,
+ },
+ };
+ if (offset && peg$source && typeof peg$source.offset === "function") {
+ res.start = peg$source.offset(res.start);
+ res.end = peg$source.offset(res.end);
+ }
+ return res;
+ }
+
+ function peg$fail(expected) {
+ if (peg$currPos < peg$maxFailPos) {
+ return;
+ }
+
+ if (peg$currPos > peg$maxFailPos) {
+ peg$maxFailPos = peg$currPos;
+ peg$maxFailExpected = [];
+ }
+
+ peg$maxFailExpected.push(expected);
+ }
+
+ function peg$buildSimpleError(message, location) {
+ return new peg$SyntaxError(message, null, null, location);
+ }
+
+ function peg$buildStructuredError(expected, found, location) {
+ return new peg$SyntaxError(
+ peg$SyntaxError.buildMessage(expected, found),
+ expected,
+ found,
+ location,
+ );
+ }
+
+ function peg$parseLambdaTerm() {
+ var s0;
+
+ var key = peg$currPos * 9 + 0;
+ var cached = peg$resultsCache[key];
+
+ if (cached) {
+ peg$currPos = cached.nextPos;
+
+ return cached.result;
+ }
+
+ s0 = peg$parseApplication();
+ if (s0 === peg$FAILED) {
+ s0 = peg$parseAbstraction();
+ if (s0 === peg$FAILED) {
+ s0 = peg$parseVariable();
+ }
+ }
+
+ peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
+
+ return s0;
+ }
+
+ function peg$parseApplication() {
+ var s0, s1, s2, s3, s4, s5, s6, s7, s8;
+
+ var key = peg$currPos * 9 + 1;
+ var cached = peg$resultsCache[key];
+
+ if (cached) {
+ peg$currPos = cached.nextPos;
+
+ return cached.result;
+ }
+
+ s0 = peg$currPos;
+ s1 = peg$parseLPAREN();
+ if (s1 !== peg$FAILED) {
+ s2 = peg$parse_();
+ if (s2 === peg$FAILED) {
+ s2 = null;
+ }
+ s3 = peg$parseLambdaTerm();
+ if (s3 !== peg$FAILED) {
+ s4 = peg$parse_();
+ if (s4 !== peg$FAILED) {
+ s5 = [];
+ s6 = peg$currPos;
+ s7 = peg$parseLambdaTerm();
+ if (s7 !== peg$FAILED) {
+ s8 = peg$parse_();
+ if (s8 !== peg$FAILED) {
+ s7 = [s7, s8];
+ s6 = s7;
+ } else {
+ peg$currPos = s6;
+ s6 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s6;
+ s6 = peg$FAILED;
+ }
+ while (s6 !== peg$FAILED) {
+ s5.push(s6);
+ s6 = peg$currPos;
+ s7 = peg$parseLambdaTerm();
+ if (s7 !== peg$FAILED) {
+ s8 = peg$parse_();
+ if (s8 !== peg$FAILED) {
+ s7 = [s7, s8];
+ s6 = s7;
+ } else {
+ peg$currPos = s6;
+ s6 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s6;
+ s6 = peg$FAILED;
+ }
+ }
+ s6 = peg$parseLambdaTerm();
+ if (s6 !== peg$FAILED) {
+ s7 = peg$parse_();
+ if (s7 === peg$FAILED) {
+ s7 = null;
+ }
+ s8 = peg$parseRPAREN();
+ if (s8 !== peg$FAILED) {
+ peg$savedPos = s0;
+ s0 = peg$f0(s3, s5, s6);
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+
+ peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
+
+ return s0;
+ }
+
+ function peg$parseAbstraction() {
+ var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15;
+
+ var key = peg$currPos * 9 + 2;
+ var cached = peg$resultsCache[key];
+
+ if (cached) {
+ peg$currPos = cached.nextPos;
+
+ return cached.result;
+ }
+
+ s0 = peg$currPos;
+ s1 = peg$parseLPAREN();
+ if (s1 !== peg$FAILED) {
+ s2 = peg$parse_();
+ if (s2 === peg$FAILED) {
+ s2 = null;
+ }
+ s3 = peg$parseLAMBDA();
+ if (s3 !== peg$FAILED) {
+ s4 = peg$parse_();
+ if (s4 === peg$FAILED) {
+ s4 = null;
+ }
+ s5 = peg$parseLPAREN();
+ if (s5 !== peg$FAILED) {
+ s6 = peg$parse_();
+ if (s6 === peg$FAILED) {
+ s6 = null;
+ }
+ s7 = peg$parseVariable();
+ if (s7 !== peg$FAILED) {
+ s8 = peg$parse_();
+ if (s8 === peg$FAILED) {
+ s8 = null;
+ }
+ s9 = peg$parseRPAREN();
+ if (s9 !== peg$FAILED) {
+ s10 = peg$parse_();
+ if (s10 === peg$FAILED) {
+ s10 = null;
+ }
+ s11 = peg$parseDOT();
+ if (s11 !== peg$FAILED) {
+ s12 = peg$parse_();
+ if (s12 === peg$FAILED) {
+ s12 = null;
+ }
+ s13 = peg$parseLambdaTerm();
+ if (s13 !== peg$FAILED) {
+ s14 = peg$parse_();
+ if (s14 === peg$FAILED) {
+ s14 = null;
+ }
+ s15 = peg$parseRPAREN();
+ if (s15 !== peg$FAILED) {
+ peg$savedPos = s0;
+ s0 = peg$f1(s7, s13);
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+ } else {
+ peg$currPos = s0;
+ s0 = peg$FAILED;
+ }
+
+ peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
+
+ return s0;
+ }
+
+ function peg$parseVariable() {
+ var s0, s1, s2;
+
+ var key = peg$currPos * 9 + 3;
+ var cached = peg$resultsCache[key];
+
+ if (cached) {
+ peg$currPos = cached.nextPos;
+
+ return cached.result;
+ }
+
+ s0 = peg$currPos;
+ s1 = [];
+ s2 = input.charAt(peg$currPos);
+ if (peg$r0.test(s2)) {
+ peg$currPos++;
+ } else {
+ s2 = peg$FAILED;
+ if (peg$silentFails === 0) {
+ peg$fail(peg$e0);
+ }
+ }
+ if (s2 !== peg$FAILED) {
+ while (s2 !== peg$FAILED) {
+ s1.push(s2);
+ s2 = input.charAt(peg$currPos);
+ if (peg$r0.test(s2)) {
+ peg$currPos++;
+ } else {
+ s2 = peg$FAILED;
+ if (peg$silentFails === 0) {
+ peg$fail(peg$e0);
+ }
+ }
+ }
+ } else {
+ s1 = peg$FAILED;
+ }
+ if (s1 !== peg$FAILED) {
+ peg$savedPos = s0;
+ s1 = peg$f2(s1);
+ }
+ s0 = s1;
+
+ peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
+
+ return s0;
+ }
+
+ function peg$parseLPAREN() {
+ var s0;
+
+ var key = peg$currPos * 9 + 4;
+ var cached = peg$resultsCache[key];
+
+ if (cached) {
+ peg$currPos = cached.nextPos;
+
+ return cached.result;
+ }
+
+ if (input.charCodeAt(peg$currPos) === 40) {
+ s0 = peg$c0;
+ peg$currPos++;
+ } else {
+ s0 = peg$FAILED;
+ if (peg$silentFails === 0) {
+ peg$fail(peg$e1);
+ }
+ }
+
+ peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
+
+ return s0;
+ }
+
+ function peg$parseRPAREN() {
+ var s0;
+
+ var key = peg$currPos * 9 + 5;
+ var cached = peg$resultsCache[key];
+
+ if (cached) {
+ peg$currPos = cached.nextPos;
+
+ return cached.result;
+ }
+
+ if (input.charCodeAt(peg$currPos) === 41) {
+ s0 = peg$c1;
+ peg$currPos++;
+ } else {
+ s0 = peg$FAILED;
+ if (peg$silentFails === 0) {
+ peg$fail(peg$e2);
+ }
+ }
+
+ peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
+
+ return s0;
+ }
+
+ function peg$parseDOT() {
+ var s0;
+
+ var key = peg$currPos * 9 + 6;
+ var cached = peg$resultsCache[key];
+
+ if (cached) {
+ peg$currPos = cached.nextPos;
+
+ return cached.result;
+ }
+
+ if (input.charCodeAt(peg$currPos) === 46) {
+ s0 = peg$c2;
+ peg$currPos++;
+ } else {
+ s0 = peg$FAILED;
+ if (peg$silentFails === 0) {
+ peg$fail(peg$e3);
+ }
+ }
+
+ peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
+
+ return s0;
+ }
+
+ function peg$parseLAMBDA() {
+ var s0;
+
+ var key = peg$currPos * 9 + 7;
+ var cached = peg$resultsCache[key];
+
+ if (cached) {
+ peg$currPos = cached.nextPos;
+
+ return cached.result;
+ }
+
+ s0 = input.charAt(peg$currPos);
+ if (peg$r1.test(s0)) {
+ peg$currPos++;
+ } else {
+ s0 = peg$FAILED;
+ if (peg$silentFails === 0) {
+ peg$fail(peg$e4);
+ }
+ }
+
+ peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
+
+ return s0;
+ }
+
+ function peg$parse_() {
+ var s0, s1;
+
+ var key = peg$currPos * 9 + 8;
+ var cached = peg$resultsCache[key];
+
+ if (cached) {
+ peg$currPos = cached.nextPos;
+
+ return cached.result;
+ }
+
+ s0 = [];
+ s1 = input.charAt(peg$currPos);
+ if (peg$r2.test(s1)) {
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) {
+ peg$fail(peg$e5);
+ }
+ }
+ if (s1 === peg$FAILED) {
+ if (input.substr(peg$currPos, 2) === peg$c3) {
+ s1 = peg$c3;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) {
+ peg$fail(peg$e6);
+ }
+ }
+ }
+ if (s1 !== peg$FAILED) {
+ while (s1 !== peg$FAILED) {
+ s0.push(s1);
+ s1 = input.charAt(peg$currPos);
+ if (peg$r2.test(s1)) {
+ peg$currPos++;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) {
+ peg$fail(peg$e5);
+ }
+ }
+ if (s1 === peg$FAILED) {
+ if (input.substr(peg$currPos, 2) === peg$c3) {
+ s1 = peg$c3;
+ peg$currPos += 2;
+ } else {
+ s1 = peg$FAILED;
+ if (peg$silentFails === 0) {
+ peg$fail(peg$e6);
+ }
+ }
+ }
+ }
+ } else {
+ s0 = peg$FAILED;
+ }
+
+ peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 };
+
+ return s0;
+ }
+
+ peg$result = peg$startRuleFunction();
+
+ if (options.peg$library) {
+ return /** @type {any} */ ({
+ peg$result,
+ peg$currPos,
+ peg$FAILED,
+ peg$maxFailExpected,
+ peg$maxFailPos,
+ });
+ }
+ if (peg$result !== peg$FAILED && peg$currPos === input.length) {
+ return peg$result;
+ } else {
+ if (peg$result !== peg$FAILED && peg$currPos < input.length) {
+ peg$fail(peg$endExpectation());
+ }
+
+ throw peg$buildStructuredError(
+ peg$maxFailExpected,
+ peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
+ peg$maxFailPos < input.length
+ ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
+ : peg$computeLocation(peg$maxFailPos, peg$maxFailPos),
+ );
+ }
+ }
+
+ return {
+ StartRules: ["LambdaTerm"],
+ SyntaxError: peg$SyntaxError,
+ parse: peg$parse,
+ };
+})();
diff --git a/src/interpreter/grammar.pegjs b/src/interpreter/grammar.pegjs
new file mode 100644
index 0000000..520d6c8
--- /dev/null
+++ b/src/interpreter/grammar.pegjs
@@ -0,0 +1,17 @@
+LambdaTerm = Application / Abstraction / Variable
+
+Application = LPAREN _? left:LambdaTerm _ argList:(LambdaTerm _)* lastArg:LambdaTerm _? RPAREN {
+ const args = lastArg || argList.length ? [...argList.map(x => x[0]), lastArg] : [];
+ return { application: { left, args } };
+}
+
+Abstraction = LPAREN _? LAMBDA _? LPAREN _? param:Variable _? RPAREN _? DOT _? body:LambdaTerm _? RPAREN { return { abstraction: { param, body } }; }
+
+Variable = param:[a-zA-Z0-9]+ { return param.join(""); }
+
+LPAREN = "("
+RPAREN = ")"
+DOT = "."
+LAMBDA = "λ" / "\\"
+
+_ = ("\n" / " " / "\t" / "\r\n")+ \ No newline at end of file
diff --git a/src/interpreter/index.ts b/src/interpreter/index.ts
new file mode 100644
index 0000000..20d0327
--- /dev/null
+++ b/src/interpreter/index.ts
@@ -0,0 +1,2 @@
+export * from "./parser";
+export * from "./interpreter";
diff --git a/src/interpreter/interpreter.ts b/src/interpreter/interpreter.ts
new file mode 100644
index 0000000..c16984f
--- /dev/null
+++ b/src/interpreter/interpreter.ts
@@ -0,0 +1,10 @@
+import { parse, type LambdaTerm } from ".";
+
+export const evaluate = (_term: LambdaTerm): LambdaTerm => {
+ return "";
+};
+
+export const interpret = (term: string): LambdaTerm => {
+ const ast = parse(term);
+ return evaluate(ast);
+};
diff --git a/src/interpreter/parser.ts b/src/interpreter/parser.ts
new file mode 100644
index 0000000..ea07796
--- /dev/null
+++ b/src/interpreter/parser.ts
@@ -0,0 +1,35 @@
+import peggyParser from "./PeggyParser.js";
+
+export type Application = {
+ application: {
+ left: LambdaTerm;
+ args: Array<LambdaTerm>;
+ };
+};
+
+export type Abstraction = {
+ abstraction: {
+ param: Variable;
+ body: LambdaTerm;
+ };
+};
+
+export type Variable = string;
+
+export type LambdaTerm = Application | Abstraction | Variable;
+
+export const isApplication = (term: LambdaTerm): term is Application => {
+ return (term as Application).application !== undefined;
+};
+
+export const isAbstraction = (term: LambdaTerm): term is Abstraction => {
+ return (term as Abstraction).abstraction !== undefined;
+};
+
+export const isVariable = (term: LambdaTerm): term is Variable => {
+ return typeof term === "string";
+};
+
+export const parse = (term: string) => {
+ return peggyParser.parse(term, { library: true });
+};
diff --git a/tsconfig.json b/tsconfig.json
index a7fc6fb..45d202f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -18,7 +18,9 @@
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true
+ "noFallthroughCasesInSwitch": true,
+
+ "allowJs": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]