]> git.kianting.info Git - anotherTypesetter/commitdiff
add closure
authorTan Kian-ting <chenjt30@gmail.com>
Sun, 31 Mar 2024 13:23:38 +0000 (21:23 +0800)
committerTan Kian-ting <chenjt30@gmail.com>
Sun, 31 Mar 2024 13:23:38 +0000 (21:23 +0800)
README.md [new file with mode: 0644]
src/index.js
src/index.ts

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..a122d82
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+## Just another interpretation of typesetting
+## TODO
+ - [ ] apply
+ - [ ] letrec 
+ - [ ] concat string
+ - [ ] basic typesetting format
\ No newline at end of file
index 54f2775798587525b3f253f3d3e1091dc555db9f..024076028a571f4166bd05ad22a9ad0d24b5a501 100644 (file)
@@ -25,6 +25,7 @@ var ItemType;
     ItemType[ItemType["Id"] = 2] = "Id";
     ItemType[ItemType["Str"] = 3] = "Str";
     ItemType[ItemType["Bool"] = 4] = "Bool";
+    ItemType[ItemType["Clos"] = 5] = "Clos";
 })(ItemType || (ItemType = {}));
 const tokenizer = (0, typescript_parsec_1.buildLexer)([
     [true, /^\d+/g, TokenKind.Int],
@@ -126,9 +127,9 @@ SINGLE.setPattern((0, typescript_parsec_2.alt)((0, typescript_parsec_2.apply)((0
 LISPS.setPattern((0, typescript_parsec_2.alt)((0, typescript_parsec_2.apply)((0, typescript_parsec_2.kmid)((0, typescript_parsec_2.seq)((0, typescript_parsec_2.str)("("), __), (0, typescript_parsec_2.rep_sc)(LISP), (0, typescript_parsec_2.str)(")")), applyList), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.kright)((0, typescript_parsec_2.str)("'"), (0, typescript_parsec_2.kmid)((0, typescript_parsec_2.seq)((0, typescript_parsec_2.str)("("), __), (0, typescript_parsec_2.rep_sc)(LISP), (0, typescript_parsec_2.str)(")"))), applyQuoted)));
 CON_STR_INNER.setPattern((0, typescript_parsec_2.alt)((0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.Id), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.Int), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.Flo), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.Str), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.Other), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.tok)(TokenKind.SpaceNL), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.kright)((0, typescript_parsec_2.tok)(TokenKind.BSlash), (0, typescript_parsec_2.tok)(TokenKind.LParen)), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.kright)((0, typescript_parsec_2.tok)(TokenKind.BSlash), (0, typescript_parsec_2.tok)(TokenKind.RParen)), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.kright)((0, typescript_parsec_2.tok)(TokenKind.BSlash), (0, typescript_parsec_2.tok)(TokenKind.LBrack)), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.kright)((0, typescript_parsec_2.tok)(TokenKind.BSlash), (0, typescript_parsec_2.tok)(TokenKind.RBrack)), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.kright)((0, typescript_parsec_2.tok)(TokenKind.BSlash), (0, typescript_parsec_2.tok)(TokenKind.Apos)), tokenToStr), (0, typescript_parsec_2.apply)((0, typescript_parsec_2.kright)((0, typescript_parsec_2.tok)(TokenKind.BSlash), (0, typescript_parsec_2.tok)(TokenKind.BSlash)), bSlashTokenToStr), LISPS));
 CON_STR.setPattern((0, typescript_parsec_2.apply)((0, typescript_parsec_2.kmid)((0, typescript_parsec_2.str)("["), (0, typescript_parsec_2.rep_sc)(CON_STR_INNER), (0, typescript_parsec_2.str)("]")), applyStrings));
-function printAST(ast) {
+function astToString(ast) {
     if (Array.isArray(ast)) {
-        let ast2 = ast.map(printAST);
+        let ast2 = ast.map(astToString);
         return "(" + ast2.join(" ") + ")";
     }
     else {
@@ -144,6 +145,11 @@ function printAST(ast) {
         else if (ast.type == ItemType.Bool) {
             return ast.bool.toString();
         }
+        else if (ast.type == ItemType.Clos) {
+            let binding = astToString(ast.vars);
+            let body = astToString(ast.body);
+            return `<closure; binding : ${binding}, body : ${body}>`;
+        }
         else {
             return ast.int.toString();
         }
@@ -201,15 +207,40 @@ function extendEnv(env, vari, data) {
     return env;
 }
 var emptyEnv = {};
+/**
+ * @throws {Error}
+ */
+function invalidLengthException(id, no) {
+    return new Error(`the number of args for ${id} should be ${no}.`);
+}
+function isItemArray(x) {
+    return x[0].hasOwnProperty('type');
+}
 function interp(prog, env) {
     if (Array.isArray(prog)) {
         if (!Array.isArray(prog[0])) {
             let op = prog[0];
             if (op.type == ItemType.Id) {
-                if (op.id == "let") {
+                if (op.id == "lambda") {
+                    let vars = prog[1];
+                    if (prog.length != 3) {
+                        throw invalidLengthException('lambda', 3);
+                    }
+                    else if (!isItemArray(vars)) {
+                        throw new Error("the vars of lambda should be a list of items");
+                    }
+                    else {
+                        return {
+                            type: ItemType.Clos,
+                            vars: vars,
+                            body: prog[2],
+                        };
+                    }
+                }
+                else if (op.id == "let") {
                     let bindings = prog[1];
                     if (prog.length != 3) {
-                        throw new Error("the number of args for 'let' should be 2.");
+                        throw invalidLengthException('let', 3);
                     }
                     else if (!Array.isArray(bindings)) {
                         throw new Error("the bindings should be array");
@@ -220,7 +251,7 @@ function interp(prog, env) {
                             let binding = bindings[i];
                             if (!Array.isArray(binding)
                                 || (binding).length != 2) {
-                                throw new Error("malformed of let.");
+                                throw new Error("malformed of let.");
                             }
                             else {
                                 let vari = binding[0];
@@ -236,7 +267,7 @@ function interp(prog, env) {
                 }
                 else if (op.id == "if") {
                     if (prog.length != 4) {
-                        throw new Error("the args of if should be 2.");
+                        throw invalidLengthException('if', 4);
                     }
                     else {
                         let cond = interp(prog[1], env);
@@ -304,7 +335,7 @@ function interp(prog, env) {
 function evaluate(expr) {
     let a = (0, typescript_parsec_1.expectSingleResult)((0, typescript_parsec_1.expectEOF)(LISP.parse(tokenizer.parse(expr))));
     let interped = interp(a, emptyEnv);
-    console.log(printAST(interped));
+    console.log(astToString(interped));
     return a;
 }
 //evaluate(`(main '((text 12)) [ 快狐跳懶狗\\\\\\\[\\\]\\\(\\\)(italic "fox and dog") (bold [OK])])`)
index 1a61ccd22fada3fde5a9e84d367df3d464b3b72e..37ed8630f5c91c9e9b54e5c6e0fb2c8b92903e65 100644 (file)
@@ -40,9 +40,10 @@ enum ItemType {
   Id,
   Str,
   Bool,
+  Clos,
 }
 
-type Item = ItemStr | ItemInt | ItemId | ItemFlo | ItemBool;
+type Item = ItemStr | ItemInt | ItemId | ItemFlo | ItemBool | Closure;
 
 interface ItemStr {
   type: ItemType.Str;
@@ -74,6 +75,12 @@ interface Env {
   [Key: string]: AST[];
 }
 
+interface Closure{
+    type: ItemType.Clos;
+    vars : Item[];
+    body : AST;
+}
+
 type AST = Item | AST[];
 
 const tokenizer = buildLexer([
@@ -231,9 +238,9 @@ CON_STR.setPattern(
   apply(kmid(str("["), rep_sc(CON_STR_INNER), str("]")), applyStrings)
 );
 
-function printAST(ast: AST): string {
+function astToString(ast: AST): string {
   if (Array.isArray(ast)) {
-    let ast2 = ast.map(printAST);
+    let ast2 = ast.map(astToString);
     return "(" + ast2.join(" ") + ")";
   } else {
     if (ast.type == ItemType.Str) {
@@ -244,7 +251,12 @@ function printAST(ast: AST): string {
       return ast.flo.toString();
     } else if (ast.type == ItemType.Bool) {
         return ast.bool.toString();
-      } else {
+    }else if (ast.type == ItemType.Clos){
+        let binding = astToString(ast.vars);
+        let body = astToString(ast.body);
+        return `<closure; binding : ${binding}, body : ${body}>`;
+    }
+     else {
       return ast.int.toString();
     }
   }
@@ -302,15 +314,42 @@ function extendEnv(env : Env, vari : string, data : AST) : Env{
 }
 var emptyEnv: Env = {};
 
+/** 
+ * @throws {Error}
+ */
+function invalidLengthException( id : string, no : number) : Error{
+    return new Error(`the number of args for ${id} should be ${no}.`);
+}
+
+function isItemArray(x: any): x is Item[] {
+    return x[0].hasOwnProperty('type');
+  }
+
 function interp(prog: AST, env: Env): AST {
   if (Array.isArray(prog)) {
     if (!Array.isArray(prog[0])) {
       let op = prog[0];
       if (op.type == ItemType.Id) {
-        if (op.id == "let"){
+        if (op.id == "lambda"){
+            let vars = prog[1];
+            if (prog.length != 3){
+                throw invalidLengthException('lambda', 3);
+            }
+            else if (!isItemArray(vars)){
+                throw new Error("the vars of lambda should be a list of items");
+            }
+            else{
+                return {
+                    type: ItemType.Clos,
+                    vars: vars,
+                    body: prog[2],
+                }
+            }
+        }
+        else if (op.id == "let"){
             let bindings = prog[1];
             if (prog.length != 3){
-                throw new Error("the number of args for 'let' should be 2.");
+                throw invalidLengthException('let', 3);
             }
             else if (!Array.isArray(bindings)){
                 throw new Error("the bindings should be array");
@@ -322,7 +361,7 @@ function interp(prog: AST, env: Env): AST {
                     let binding = bindings[i];
                     if (!Array.isArray(binding)
                         || (<AST[]>(binding)).length != 2){
-                        throw new Error("malformed of let.")
+                        throw new Error("malformed of let.")
                     }else{
                         let vari = binding[0];
                         if (vari.hasOwnProperty("id")){
@@ -338,7 +377,7 @@ function interp(prog: AST, env: Env): AST {
         }
         else if(op.id == "if"){
             if (prog.length != 4){
-                throw new Error("the args of if should be 2.");
+                throw invalidLengthException('if', 4);
             }else{
                 let cond = interp(prog[1], env);
                 if (Array.isArray(cond)){
@@ -395,7 +434,7 @@ function interp(prog: AST, env: Env): AST {
 function evaluate(expr: string): AST {
   let a = expectSingleResult(expectEOF(LISP.parse(tokenizer.parse(expr))));
   let interped = interp(a, emptyEnv);
-  console.log(printAST(interped));
+  console.log(astToString(interped));
   return a;
 }