git » jacl.git » commit 1a385cc

we have let!

author Alan Dipert
2019-10-23 15:04:27 UTC
committer Alan Dipert
2019-10-23 15:04:27 UTC
parent cc7d304763bc04bdff4d8612ae119ca732edb96b

we have let!

jacl.js +55 -14

diff --git a/jacl.js b/jacl.js
index cc33b44..0542de6 100644
--- a/jacl.js
+++ b/jacl.js
@@ -291,6 +291,8 @@ const CLPKG = Package.makePackage('COMMON-LISP', 'CL');
 Package.makePackage('COMMON-LISP-USER', 'CL-USER');
 Package.makePackage('KEYWORD');
 
+JACLPKG.intern('!LOG').fvalue = console.log;
+
 // CL package constants
 // TODO update this, look into constants
 const CLCONSTS = new Map([
@@ -617,6 +619,15 @@ const munge = s => {
   return munged;
 };
 
+const mungeSym = (sym, prefix = '') => {
+  prefix = prefix !== '' ? (prefix + '_') : '';
+  if (PACKAGE.val().name === sym.packageName) {
+    return prefix + munge(sym.name);
+  } else {
+    return prefix + munge(sym.packageName) + '$' + munge(sym.name);
+  }
+};
+
 class Token {
   constructor(initial = '') {
     this.str = initial;
@@ -822,7 +833,7 @@ const analyzeBlock = (env, parent, forms) => {
                .map(x => analyze(env.withContext('statement'), parent, x)),
       ret;
   if (forms.length <= 1) {
-    ret = analyze(env, parent, forms[0]);
+    ret = analyze(env.withContext(env.context === 'statement' ? 'statement' : 'return'), parent, forms[0]);
   } else {
     ret = analyze(
       env.withContext(env.context === 'statement' ? 'statement' : 'return'),
@@ -856,11 +867,10 @@ const analyzeSpecials = new Map([
     return node;
   }],
   [JACLPKG.intern('%CALL'), (env, parent, form) => {
-    env = env.withContext('sval');
     const [, func, ...args] = form;
     const node = makeNode('call', { env: env, parent: parent, form: form });
-    node.f = analyze(env, node, func);
-    node.args = args.map(analyze.bind(null, env, node))
+    node.f = analyze(env.withContext('sval'), node, func);
+    node.args = args.map(analyze.bind(null, env.withContext('sval'), node))
     return node;
   }],
   // TODO majorly broken because of Env overhaul
@@ -898,7 +908,7 @@ const analyzeSpecials = new Map([
   }],
   [JACLPKG.intern('%LET'), (env, parent, form) => {
     const [, bindings, ...body] = form;
-    const node = makeNode('let', { 
+    const node = makeNode('let', {
       env: env,
       parent: parent,
       form: form
@@ -932,7 +942,7 @@ const analyzeSpecials = new Map([
     const node = makeNode(op, { env: env, parent: parent, form: form });
     node.targetSym = target;
     node.val = valExpr;
-    node.targetSym.parent = node;
+    node.val.parent = node;
 
     return node;
   }],
@@ -1010,11 +1020,14 @@ const parseCall = (env, parent, form) => {
   let node = makeNode('call', { env: env, parent: parent, form: form });
   node.args = args.map(analyze.bind(null, env.withContext('sval'), node));
   if (isLambdaForm(func)) {
-    node.f = analyze(env, parent, func);
-  } else if (func instanceof LispSymbol && env.localFuns.has(func.name)) {
-    node.f = makeNode('local', { env: env, parent: node, form: func });
+    node.f = analyze(env.withContext('sval'), parent, func);
   } else if (func instanceof LispSymbol) {
-    node.f = makeNode('global', { env: env, parent: node, form: func, slot: 'function' });
+    node.f = makeNode('global', {
+      env: env.withContext('sval'),
+      parent: node,
+      form: func,
+      slot: 'function'
+    });
   }
   return node;
 };
@@ -1074,7 +1087,6 @@ class Env {
   withLocals(syms) {
     const newEnv = this.clone();
     newEnv.locals = new Set([...this.locals, ...syms]);
-    console.log(newEnv.locals);
     return newEnv;
   }
   hasLocal(sym) {
@@ -1124,6 +1136,19 @@ const constantCode = val => {
 
 const truth = x => x != null && x !== false;
 
+const emitBlock = (print, statements, ret) => {
+  if (statements.length) {
+    for (const stmt of statements) {
+      print('\t');
+      emitNode(print, stmt);
+    }
+    print('\t');
+    emitNode(print, ret);
+  } else {
+    emitNode(print, ret);
+  }
+};
+
 const emitNode = (print, node) => {
   const { op, env: { context }, parent, form } = node;
   switch (op) {
@@ -1150,7 +1175,7 @@ const emitNode = (print, node) => {
       break;
     case 'local':
       if (context === 'return') print('return ');
-      print(munge(form.name));
+      print(mungeSym(form, 'local'));
       if (context !== 'sval') print(';\n');
       break;
     case 'global':
@@ -1176,13 +1201,29 @@ const emitNode = (print, node) => {
       if (context !== 'sval') print(';\n');
       break;
       break;
-    case 'set':
+    case 'set-local':
       if (context === 'return') print('return ');
-      emitNode(print, node.target);
+      print(mungeSym(node.targetSym, 'local'))
       print('=');
       emitNode(print, node.val);
       if (context !== 'sval') print(';\n');
       break;
+    case 'let':
+      if (context === 'sval') print('(function()');
+      print('{');
+      if (node.bindings.length) print('var ');
+      for (let i = 0; i < node.bindings.length; i++) {
+        const [name, val] = node.bindings[i];
+        print(mungeSym(name, 'local'))
+        print('=');
+        emitNode(print, val);
+        if (i < node.bindings.length-1) print(',');
+      }
+      if (node.bindings.length) print(';');
+      emitBlock(print, node.statements, node.ret);
+      print('}');
+      if (context === 'sval') print(')()');
+      break;
     case 'call':
       if (context === 'return') print('return ');
       emitNode(print, node.f);