- [v] car - 240403
- [v] cdr and cons
- [v] concat string (++)
- - [ ] create pdf
+ - [v] set!
+ - [v] list ref by index
+ - [ ] dict ref by id
+ - [v] map 20240410
+ - [v] add pdf page 240410 (addPDFPages)
+ - [v] create pdf 240410
- [ ] close pdf
- [ ] add character
- [ ] add path
"version": "0.0.1",
"license": "MIT",
"dependencies": {
+ "pdf-lib": "^1.17.1",
"typescript-parsec": "^0.3.4"
},
"devDependencies": {
"node": ">= 8"
}
},
+ "node_modules/@pdf-lib/standard-fonts": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz",
+ "integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==",
+ "dependencies": {
+ "pako": "^1.0.6"
+ }
+ },
+ "node_modules/@pdf-lib/upng": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz",
+ "integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==",
+ "dependencies": {
+ "pako": "^1.0.10"
+ }
+ },
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"node": ">=8"
}
},
+ "node_modules/pdf-lib": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz",
+ "integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==",
+ "dependencies": {
+ "@pdf-lib/standard-fonts": "^1.0.0",
+ "@pdf-lib/upng": "^1.0.1",
+ "pako": "^1.0.11",
+ "tslib": "^1.11.1"
+ }
+ },
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"typescript": ">=4.2.0"
}
},
+ "node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
"fastq": "^1.6.0"
}
},
+ "@pdf-lib/standard-fonts": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz",
+ "integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==",
+ "requires": {
+ "pako": "^1.0.6"
+ }
+ },
+ "@pdf-lib/upng": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz",
+ "integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==",
+ "requires": {
+ "pako": "^1.0.10"
+ }
+ },
"@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"p-limit": "^3.0.2"
}
},
+ "pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+ },
"parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
},
+ "pdf-lib": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz",
+ "integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==",
+ "requires": {
+ "@pdf-lib/standard-fonts": "^1.0.0",
+ "@pdf-lib/upng": "^1.0.1",
+ "pako": "^1.0.11",
+ "tslib": "^1.11.1"
+ }
+ },
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"dev": true,
"requires": {}
},
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ },
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
"author": "Tan Kian-ting",
"license": "MIT",
"dependencies": {
+ "pdf-lib": "^1.17.1",
"typescript-parsec": "^0.3.4"
},
"devDependencies": {
"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
Object.defineProperty(exports, "__esModule", { value: true });
+const fs = __importStar(require("fs"));
+const pdf_lib_1 = require("pdf-lib");
const typescript_parsec_1 = require("typescript-parsec");
const typescript_parsec_2 = require("typescript-parsec");
+/** input lisp file */
+const filename = "./text.lisp";
+let pdfDoc;
var TokenKind;
(function (TokenKind) {
TokenKind[TokenKind["Id"] = 0] = "Id";
ItemType[ItemType["Bool"] = 4] = "Bool";
ItemType[ItemType["Clos"] = 5] = "Clos";
ItemType[ItemType["Ls"] = 6] = "Ls";
+ ItemType[ItemType["Unit"] = 7] = "Unit";
})(ItemType || (ItemType = {}));
const tokenizer = (0, typescript_parsec_1.buildLexer)([
- [true, /^\d+/g, TokenKind.Int],
- [true, /^\d+\.\d+/g, TokenKind.Flo],
+ [true, /^-?\d+/g, TokenKind.Int],
+ [true, /^-?\d+\.\d+/g, TokenKind.Flo],
[true, /^true/g, TokenKind.Bool],
[true, /^false/g, TokenKind.Bool],
- [true, /^([+\-*/a-zA-Z_][0-9+\-*/a-zA-Z_]*|[<>]=?|!?=)/g, TokenKind.Id],
+ [true, /^([+\-*/a-zA-Z_][0-9+\-*/a-zA-Z_]*!?|[<>]=?|!?=)/g, TokenKind.Id],
[true, /^\"([^\"]|\\\")+\"/g, TokenKind.Str],
[true, /^[(]/g, TokenKind.LParen],
[true, /^[)]/g, TokenKind.RParen],
else if (ast.type === ItemType.Bool) {
return ast.bool.toString();
}
+ else if (ast.type === ItemType.Unit) {
+ return "#unit"; // mark for unit
+ }
else if (ast.type === ItemType.Clos) {
const binding = astToString(ast.vars);
const body = astToString(ast.body);
};
}
else {
- throw new Error("the type of add should be (int, int) or (flo, flo)");
+ throw new Error(`the type of ${op.toString()} should be (int, int) or (flo, flo)`);
}
}
else {
};
}
else {
- throw new Error("the type of add should be (int, int) or (flo, flo)");
+ throw new Error(`the type of ${op.toString()} should be (int, int) or (flo, flo)`);
}
}
else {
function ge(x, y) {
return x >= y;
}
+function otherNe(x, y) {
+ return astToString(x) !== astToString(y);
+}
+function otherEq(x, y) {
+ return astToString(x) === astToString(y);
+}
+// string manipulations
function concatString(l, r) {
const rtn = {
type: ItemType.Str,
};
return rtn;
}
+/**
+ * get string `s`'s substring from ith-char to (j-1)th-char.
+ * @param s the string
+ * @param i beginning index
+ * @param j ending index (excluded)
+ * @returns the substring
+ */
+function subString(s, i, j) {
+ const realI = i.int;
+ const realStr = s.str;
+ if (realI >= realStr.length || realI < 0) {
+ throw new Error("the 2nd argument of `listRef` should between 0..(length of string `s` - 1)");
+ }
+ else if (j === undefined) {
+ const rtn = {
+ type: ItemType.Str,
+ str: realStr.substring(realI)
+ };
+ return rtn;
+ }
+ else {
+ const realJ = j.int;
+ if (realJ >= realStr.length || realJ < 0) {
+ throw new Error("the 3rd argument of `listRef` should between 0..(length of string `s` - 1)");
+ }
+ else if (realI > realJ) {
+ throw new Error("the 2nd argument should not larger than the 3rd arg.");
+ }
+ else {
+ const rtn = {
+ type: ItemType.Str,
+ str: realStr.substring(realI, realJ),
+ };
+ return rtn;
+ }
+ }
+}
/** list manipulation */
function car(x) {
const fst = x.list[0];
};
return rtnList;
}
+function listRef(l, i) {
+ const realI = i.int;
+ if (realI >= l.list.length || realI < 0) {
+ throw new Error("the argument of `listRef` should between 0..(length of l - 1)");
+ }
+ else {
+ const rtn = l.list[realI];
+ return rtn;
+ }
+}
function extendEnv(env, vari, isRec, data) {
// add var
if (!(vari in env)) {
return interpBinaryBool(le, argsMapped);
}
else if (op.id === "=") {
- return interpBinaryBool(eq, argsMapped);
+ if (argsMapped[1].type === ItemType.Flo ||
+ argsMapped[1].type === ItemType.Int) {
+ return interpBinaryBool(eq, argsMapped);
+ }
+ else {
+ if (prog.length !== 3) {
+ throw invalidLengthException('=', 2);
+ }
+ else if (!isItem(argsMapped[0])
+ || !isItem(argsMapped[1])) {
+ throw new Error("Either 1st or 2nd arg of '=' is not a item.");
+ }
+ else {
+ return {
+ type: ItemType.Bool,
+ bool: otherEq(argsMapped[0], argsMapped[1]),
+ };
+ }
+ }
}
else if (op.id === "!=") {
- return interpBinaryBool(ne, argsMapped);
+ if ((argsMapped[0].type === ItemType.Flo &&
+ argsMapped[0].type === argsMapped[1].type) ||
+ (argsMapped[0].type === ItemType.Int) &&
+ (argsMapped[0].type === argsMapped[1].type)) {
+ return interpBinaryBool(ne, argsMapped);
+ }
+ else {
+ if (prog.length !== 3) {
+ throw invalidLengthException('!=', 2);
+ }
+ else if (!isItem(argsMapped[1])
+ || !isItem(argsMapped[2])) {
+ throw new Error("Either 1st or 2nd arg of '!=' is not a item.");
+ }
+ else {
+ return {
+ type: ItemType.Bool,
+ bool: otherNe(argsMapped[0], argsMapped[1]),
+ };
+ }
+ }
}
else if (op.id === "car") {
const arg = argsMapped[0];
else {
return cons(arg[0], arg[1]);
}
- } // string manipulations
+ }
+ else if (op.id === "listRef") {
+ const arg = argsMapped;
+ if (prog.length !== 3) {
+ throw invalidLengthException('listRef', 2);
+ }
+ else if (!arg[0].hasOwnProperty('type') || arg[0].type !== ItemType.Ls) {
+ throw new Error("the 1st arg of 'listRef' is not a list.");
+ }
+ else if (!arg[1].hasOwnProperty('type') || arg[1].type !== ItemType.Int) {
+ throw new Error("the 2nd arg of 'listRef' is not a number.");
+ }
+ else {
+ return listRef(arg[0], arg[1]);
+ }
+ }
+ // string manipulations
else if (op.id === "++") {
const lhs = prog[1];
const rhs = prog[2];
return concatString(lhs, rhs);
}
}
+ else if (op.id === "subString") {
+ const str = prog[1];
+ const i = prog[2];
+ if (prog.length !== 3 && prog.length !== 4) {
+ throw new Error(`the number of args for 'subString' should be 2 or 3.`);
+ }
+ else if (!isItem(str) || str.type != ItemType.Str) {
+ throw new Error("the 1st item of the arg for 'subString' should be a string.");
+ }
+ else {
+ if (prog.length == 3) {
+ // str.substring(i)
+ return subString(str, i);
+ }
+ else {
+ // str.substring(i,j)
+ return subString(str, i, prog[3]);
+ }
+ }
+ }
+ // set manipulations
+ else if (op.id === "set!") {
+ const vari = prog[1];
+ const replacer = prog[2];
+ if (prog.length !== 3) {
+ throw invalidLengthException('set!', 2);
+ }
+ else if (!isItem(vari) || !isItem(replacer)
+ || env[vari.id][0].value.type != replacer.type) {
+ throw new Error("the type of replace and variable should be the same.");
+ }
+ else {
+ env[vari.id][0].value = prog[2];
+ return { type: ItemType.Unit };
+ }
+ }
+ else if (op.id === "addPDFPage") {
+ if (prog.length !== 2) {
+ throw invalidLengthException('addPDFPage', 1);
+ }
+ else if (astToString(argsMapped[0]) !== "'()") {
+ throw new Error("the arg of addPdfPage should be a empty string '()");
+ }
+ else {
+ const page = pdfDoc.addPage();
+ return {
+ type: ItemType.Unit,
+ };
+ }
+ const rtn = argsMapped[argsMapped.length - 1];
+ return rtn;
+ }
+ // procedures returning the last called command
+ else if (op.id === "begin") {
+ const rtn = argsMapped[argsMapped.length - 1];
+ return rtn;
+ }
// other named function call
else {
const caller = interp(prog[0], env);
const varArgLen = varArgs.length;
const argsMappedLen = argsMapped.length;
if (argsMappedLen !== varArgLen) {
- throw new Error("the number of the arguments is"
+ throw new Error("the number of the arguments of the caller is"
+ " not the same of that of the input vars.");
}
else {
// evaluate("@(let (a 17) (+ a 10))@")
// eval print loop
const readline = require("node:readline");
+const node_process_1 = require("node:process");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
-rl.question(`What's your program?`, (prog) => {
+async function run() {
+ pdfDoc = await pdf_lib_1.PDFDocument.create();
+ const prog = fs.readFileSync(filename, { encoding: 'utf8' });
console.log(evaluate(prog));
- rl.close();
-});
+ const pdfBytes = await pdfDoc.save();
+ fs.writeFileSync(filename + '.pdf', pdfBytes, 'binary');
+ (0, node_process_1.exit)(0);
+}
+run();
-import { validateHeaderName } from "http";
+import * as fs from 'fs';
+import { PDFDocument } from 'pdf-lib'
import { Token } from "typescript-parsec";
import {
buildLexer,
opt,
} from "typescript-parsec";
+
+
+/** input lisp file */
+const filename = "./text.lisp";
+let pdfDoc : PDFDocument;
+
enum TokenKind {
Id,
Int,
Bool,
Clos,
Ls,
+ Unit,
}
-type Item = ItemStr | ItemInt | ItemId | ItemFlo | ItemBool | Closure | List;
+type Item = ItemStr | ItemInt | ItemId | ItemFlo | ItemBool | ItemUnit | Closure | List;
interface ItemStr {
type: ItemType.Str;
str: string;
}
+// returned type for input or print, etc. #unit for representation
+interface ItemUnit {
+ type: ItemType.Unit;
+}
+
interface ItemInt {
type: ItemType.Int;
int: number;
type AST = Item | AST[];
const tokenizer = buildLexer([
- [true, /^\d+/g, TokenKind.Int],
- [true, /^\d+\.\d+/g, TokenKind.Flo],
+ [true, /^-?\d+/g, TokenKind.Int],
+ [true, /^-?\d+\.\d+/g, TokenKind.Flo],
[true, /^true/g, TokenKind.Bool],
[true, /^false/g, TokenKind.Bool],
- [true, /^([+\-*/a-zA-Z_][0-9+\-*/a-zA-Z_]*|[<>]=?|!?=)/g, TokenKind.Id],
+ [true, /^([+\-*/a-zA-Z_][0-9+\-*/a-zA-Z_]*!?|[<>]=?|!?=)/g, TokenKind.Id],
[true, /^\"([^\"]|\\\")+\"/g, TokenKind.Str],
[true, /^[(]/g, TokenKind.LParen],
[true, /^[)]/g, TokenKind.RParen],
return ast.flo.toString();
} else if (ast.type === ItemType.Bool) {
return ast.bool.toString();
+ }else if (ast.type === ItemType.Unit) {
+ return "#unit"; // mark for unit
}else if (ast.type === ItemType.Clos){
const binding = astToString(ast.vars);
const body = astToString(ast.body);
int: op(fst.int, snd.int),
};
} else {
- throw new Error("the type of add should be (int, int) or (flo, flo)");
+
+ throw new Error(`the type of ${op.toString()} should be (int, int) or (flo, flo)`);
}
} else {
throw new Error(`the number of args of ${op} should be 2, but it's ${argsMapped}`);
bool: op(fst.int, snd.int) as boolean,
};
} else {
- throw new Error("the type of add should be (int, int) or (flo, flo)");
+ throw new Error(`the type of ${op.toString()} should be (int, int) or (flo, flo)`);
}
} else {
throw new Error("the number of args should be 2.");
function ge(x: number, y: number): boolean {
return x >= y;
}
+
+function otherNe(x: any, y: any): boolean {
+ return astToString(x) !== astToString(y);
+}
+function otherEq(x: any, y: any): boolean {
+ return astToString(x) === astToString(y);
+}
+
+
+// string manipulations
function concatString(l: ItemStr, r : ItemStr) : ItemStr {
const rtn : ItemStr = {
type: ItemType.Str,
}
return rtn;
}
+/**
+ * get string `s`'s substring from ith-char to (j-1)th-char.
+ * @param s the string
+ * @param i beginning index
+ * @param j ending index (excluded)
+ * @returns the substring
+ */
+function subString(s: ItemStr, i: ItemInt, j? : ItemInt): ItemStr {
+ const realI = i.int;
+ const realStr = s.str;
+ if (realI >= realStr.length || realI < 0){
+ throw new Error("the 2nd argument of `listRef` should between 0..(length of string `s` - 1)");
+ }
+ else if(j === undefined){
+ const rtn : ItemStr = {
+ type:ItemType.Str,
+ str:realStr.substring(realI)
+ };
+ return rtn;
+ }
+ else{
+
+ const realJ = j.int;
+ if (realJ >= realStr.length || realJ < 0){
+ throw new Error("the 3rd argument of `listRef` should between 0..(length of string `s` - 1)");
+ }else if (realI > realJ){
+ throw new Error("the 2nd argument should not larger than the 3rd arg.");
+ }else{
+ const rtn : ItemStr = {
+ type:ItemType.Str,
+ str:realStr.substring(realI,realJ),
+ };
+ return rtn;
+ }}
+}
/** list manipulation */
return rtnList;
}
+function listRef(l: List, i: ItemInt): AST {
+ const realI = i.int;
+ if (realI >= l.list.length || realI < 0){
+ throw new Error("the argument of `listRef` should between 0..(length of l - 1)");
+ }else{
+ const rtn = l.list[realI];
+ return rtn;
+ }
+}
+
+
function extendEnv(env : Env, vari : string, isRec: boolean, data : AST) : Env{
// add var
return x.hasOwnProperty('type') && x.hasOwnProperty('vars');
}
-
function interp(prog: AST, env: Env): AST {
if (Array.isArray(prog)) {
if (!Array.isArray(prog[0])) {
} else if (op.id === "<=") {
return interpBinaryBool(le, argsMapped);
} else if (op.id === "=") {
- return interpBinaryBool(eq, argsMapped);
+ if ((argsMapped[1] as Item).type === ItemType.Flo ||
+ (argsMapped[1] as Item).type === ItemType.Int){
+ return interpBinaryBool(eq, argsMapped);
+ }else{
+ if (prog.length !== 3){
+ throw invalidLengthException('=', 2);
+ }else if(!isItem(argsMapped[0])
+ ||!isItem(argsMapped[1])){
+ throw new Error("Either 1st or 2nd arg of '=' is not a item.")
+ }else{
+ return {
+ type:ItemType.Bool,
+ bool:otherEq(argsMapped[0], argsMapped[1]),
+ };
+ }
+ }
} else if (op.id === "!=") {
+ if (
+ ((argsMapped[0] as Item).type === ItemType.Flo &&
+ (argsMapped[0] as Item).type === (argsMapped[1] as Item).type)||
+ ((argsMapped[0] as Item).type === ItemType.Int) &&
+ ((argsMapped[0] as Item).type === (argsMapped[1] as Item).type)){
return interpBinaryBool(ne, argsMapped);
+ }else{
+ if (prog.length !== 3){
+ throw invalidLengthException('!=', 2);
+ }else if(!isItem(argsMapped[1])
+ ||!isItem(argsMapped[2])){
+ throw new Error("Either 1st or 2nd arg of '!=' is not a item.")
+ }else{
+ return {
+ type:ItemType.Bool,
+ bool:otherNe(argsMapped[0], argsMapped[1]),
+ };
+ }
+ }
} else if (op.id === "car") {
const arg = argsMapped[0];
if (prog.length !== 2){
}else{
return cons(arg[0], (arg[1] as List));
}
- } // string manipulations
+ }
+ else if (op.id === "listRef"){
+ const arg = argsMapped;
+ if (prog.length !== 3){
+ throw invalidLengthException('listRef', 2);
+ }else if (!arg[0].hasOwnProperty('type') || (arg[0] as Item).type !== ItemType.Ls){
+ throw new Error("the 1st arg of 'listRef' is not a list.")
+ }else if (!arg[1].hasOwnProperty('type') || (arg[1] as Item).type !== ItemType.Int){
+ throw new Error("the 2nd arg of 'listRef' is not a number.")
+ }else{
+ return listRef(arg[0] as List, arg[1] as ItemInt);
+ }
+ }
+
+
+
+ // string manipulations
else if (op.id === "++") {
const lhs = prog[1];
const rhs = prog[2];
}else{
return concatString(lhs, rhs);
}}
+ else if (op.id === "subString") {
+ const str = prog[1];
+ const i = prog[2];
+ if (prog.length !== 3 && prog.length !== 4){
+ throw new Error(`the number of args for 'subString' should be 2 or 3.`);
+ }else if (!isItem(str) || str.type != ItemType.Str ){
+ throw new Error("the 1st item of the arg for 'subString' should be a string.")
+ }else{
+ if (prog.length == 3){
+ // str.substring(i)
+ return subString(str, i as ItemInt);}
+ else{
+ // str.substring(i,j)
+ return subString(str, i as ItemInt, prog[3] as ItemInt);}
+ }
+ }
+ // set manipulations
+ else if (op.id === "set!") {
+ const vari : ItemId = prog[1] as ItemId;
+ const replacer = prog[2];
+ if (prog.length !== 3){
+ throw invalidLengthException('set!', 2);
+ }else if (!isItem(vari) || !isItem(replacer)
+ || (env[vari.id][0].value as Item).type != replacer.type ){
+ throw new Error("the type of replace and variable should be the same.")
+ }else{
+ env[vari.id][0].value = prog[2];
+ return {type:ItemType.Unit};
+ }
+ }
+ else if (op.id === "addPDFPage"){
+ if (prog.length !== 2){
+ throw invalidLengthException('addPDFPage', 1);
+ }else if(astToString(argsMapped[0]) !== "'()"){
+ throw new Error("the arg of addPdfPage should be a empty string '()")
+ }else{
+ const page = pdfDoc.addPage();
+ return {
+ type:ItemType.Unit,
+ }
+ }
+
+ const rtn = argsMapped[argsMapped.length-1];
+ return rtn;
+ }
+ // procedures returning the last called command
+ else if (op.id === "begin"){
+ const rtn = argsMapped[argsMapped.length-1];
+ return rtn;
+ }
// other named function call
else {
const varArgLen = varArgs.length;
const argsMappedLen = argsMapped.length;
if (argsMappedLen !== varArgLen){
- throw new Error("the number of the arguments is"
+ throw new Error("the number of the arguments of the caller is"
+" not the same of that of the input vars.");
}else{
let newEnv = structuredClone((caller as Closure).env);
// eval print loop
import readline = require("node:readline");
+import { exit } from "node:process";
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
-rl.question(`What's your program?`, (prog: string) => {
+
+async function run(){
+ pdfDoc = await PDFDocument.create();
+
+
+ const prog = fs.readFileSync(filename, { encoding: 'utf8' });
+
console.log(evaluate(prog));
- rl.close();
-});
+
+ const pdfBytes = await pdfDoc.save();
+ fs.writeFileSync(filename+'.pdf', pdfBytes, 'binary');
+ exit(0);
+}
+
+run();
\ No newline at end of file
--- /dev/null
+(letrec ((
+ map (lambda (f l)
+ (if (!= l '())
+ (cons (f (car l)) (map f (cdr l)))
+ '()))
+))
+(begin
+(addPDFPage '())
+(addPDFPage '())
+(map (lambda (x) (+ x 2)) '(8 9 10))
+
+))
\ No newline at end of file
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
- "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ "target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */