git » jacl.git » commit 8b216de

stuff

author Alan Dipert
2019-09-28 21:33:27 UTC
committer Alan Dipert
2019-09-28 21:33:27 UTC
parent a4eaac2085c029a5558a5099b7e56e50579f657e

stuff

jacl.js +56 -34

diff --git a/jacl.js b/jacl.js
index 90e9c30..3c15a53 100644
--- a/jacl.js
+++ b/jacl.js
@@ -234,26 +234,40 @@ class Package {
 
 const JACLPKG = Package.makePackage('JACL');
 const JSPKG = Package.makePackage('JS');
-Package.makePackage('COMMON-LISP', 'CL');
+const CLPKG = Package.makePackage('COMMON-LISP', 'CL');
 Package.makePackage('COMMON-LISP-USER', 'CL-USER');
 Package.makePackage('KEYWORD');
 
-const JSVALS = new Map([
-  ['+FALSE+', 'false'],
-  ['+NAN+', 'NaN'],
-  ['+NULL+', 'null'],
-  ['+TRUE+', 'true'],
-  ['+UNDEFINED+', 'undefined']
+// CL package constants
+const CLCONSTS = new Map([
+  ['T', true],
+  ['NIL', null]
 ]);
 
-for (const [k,v] of JSVALS) {
-  JSPKG.intern(k);
+for (const [k,v] of CLCONSTS) {
+  CLPKG.intern(k).value = v;
+  CLPKG.exportSymbol(k);
+}
+
+// JS package constants
+const JSCONSTS = new Map([
+  ['+FALSE+', false],
+  ['+NAN+', NaN],
+  ['+NULL+', null],
+  ['+TRUE+', true],
+  ['+UNDEFINED+', undefined]
+]);
+
+for (const [k,v] of JSCONSTS) {
+  JSPKG.intern(k).value = v;
   JSPKG.exportSymbol(k);
 }
 
 const PACKAGE = Package.intern('CL', '*PACKAGE*');
 PACKAGE.value = Package.get('JACL');
 
+JACLPKG.usePackage(CLPKG);
+
 class BufferedStream {
   constructor() {
     this.buf = [];
@@ -575,9 +589,8 @@ class Reader {
 }
 
 // Special forms related to interop
-for (const s of ['JS', 'DOT']) {
+for (const s of ['%DOT', '%CALL']) {
   JACLPKG.intern(s);
-  JACLPKG.exportSymbol(s);
 }
 
 // Primitive functions related to interop
@@ -594,10 +607,14 @@ JACLPKG.intern('.').setMacro().fvalue = function(topic, ...ops) {
   if (arguments.length < 2) throw new Error(`\. requires at least two arguments`);
   return ops.reduce((prev, op) => {
     if (op instanceof LispSymbol) {
-      return Cons.listOf(JACLPKG.findSymbol('DOT')[0], prev, op);
+      return Cons.listOf(JACLPKG.intern('%DOT'), prev, op);
     } else if (op instanceof Cons) {
       const [method, ...args] = op;
-      return Cons.listOf(Cons.listOf(JACLPKG.findSymbol('DOT')[0], prev, method), ...args);
+      return Cons.listOf(
+        JACLPKG.intern('%CALL'),
+        Cons.listOf(JACLPKG.intern('%DOT'), prev, method), 
+        ...args
+      );
     } else {
       throw new Error(`Invalid \. syntax: ${op}`);
     }
@@ -616,12 +633,6 @@ JACLPKG.intern('ENABLE-JS-SYNTAX').fvalue = () => {
     .val()
     .makeDispatchMacroChar('@', true)
     .setDispatchMacroChar('@', '"', readJsString)
-    .setDispatchMacroChar('@', '|', async stream => {
-      return new Values(Cons.listOf(
-        JACLPKG.intern('JS'),
-        await readMultiEscaped(stream, new Token().sawPipe(), true)
-      ));
-    })
   return null;
 };
 JACLPKG.exportSymbol('ENABLE-JS-SYNTAX');
@@ -633,6 +644,14 @@ const isMacroForm = form => {
     && form.car.isMacro;
 };
 
+const isLambdaForm = form => {
+  return form instanceof Cons
+    && form.car
+    && form.car instanceof LispSymbol
+    && form.car.packageName === 'COMMON-LISP'
+    && form.car.name === 'LAMBDA';
+}
+
 const compile = (form, env) => {
   if (form instanceof Number || typeof form === 'number') {
     return form.toString();
@@ -640,9 +659,13 @@ const compile = (form, env) => {
     return JSON.stringify(form);
   } else if (form instanceof LispString) {
     return `(LispString.fromString("${form}"))`;
-  } else if (form instanceof LispSymbol) {
-    if (form.packageName === 'JS' && JSVALS.has(form.name)) {
-      return JSVALS.get(form.name);
+  } else if (form instanceof LispSymbol && form.packageName !== null) {
+    // TODO handle JS: and COMMON-LISP:{NIL,T} like constants here
+    // (emit directly, no symbol junk)
+    if (form.packageName === 'JS' && !JSCONSTS.has(form.name)) {
+      return form.name;
+    } else {
+      return `LispSymbol.intern(${JSON.stringify(form.packageName)}, ${JSON.stringify(form.name)}).val()`;
     }
   } else if (isMacroForm(form)) {
     while (isMacroForm(form)) {
@@ -651,24 +674,23 @@ const compile = (form, env) => {
     }
     return compile(form, env);
   } else if (form instanceof Cons) {
-    const [op, ...args] = form,
-          [arg1, arg2]  = args;
-    if (JACLPKG.intern('JS') === op) {
-      if (arg1 instanceof LispSymbol) {
-        return arg1.name;
-      } else {
-        return arg1.toString();
-      }
-    } else if (JACLPKG.intern('DOT') === op) {
+    let [op, ...args] = form,
+        [arg1, arg2]  = args;
+    if (JACLPKG.intern('%DOT') === op) {
       return `${compile(arg1, env)}.${arg2.name}`
+    } else if (JACLPKG.intern('%CALL') === op) {
+      let [, func, ...args] = form;
+      return `${compile(func, env)}(` +
+        args.map(x => compile(x, env)).join(',') +
+        `)`;
     } else if (op instanceof LispSymbol) {
       return `LispSymbol.intern('${op.packageName}', '${op.name}').func()(` +
         args.map(x => compile(x, env)).join(',') +
         `)`;
+    } else if (isLambdaForm(op)) {
+      return `${compile(op, env)}(${args.map(x => compile(x, env)).join(',')})`
     } else {
-      return `${compile(op, env)}(`+
-        args.map(x => compile(x, env)).join(',') +
-        `)`
+      throw new Error(`Illegal function call`);
     }
   } else if (form === null) {
     return 'null';