From a11a023558c5a660d4d1b1d7d85ff3129d81d828 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Wed, 27 Sep 2017 22:10:24 -0500 Subject: [PATCH] ES6: Use ES6 modules. Update node. --- .gitignore | 2 +- Makefile | 2 +- es6/Dockerfile | 7 +-- es6/Makefile | 52 +++++-------------- es6/{core.js => core.mjs} | 18 +++---- es6/{env.js => env.mjs} | 0 es6/node_readline.js | 5 +- es6/package.json | 9 ++-- es6/{printer.js => printer.mjs} | 4 +- es6/{reader.js => reader.mjs} | 4 +- es6/run | 2 +- es6/{step0_repl.js => step0_repl.mjs} | 0 ...ep1_read_print.js => step1_read_print.mjs} | 0 es6/{step2_eval.js => step2_eval.mjs} | 0 es6/{step3_env.js => step3_env.mjs} | 0 es6/{step4_if_fn_do.js => step4_if_fn_do.mjs} | 0 es6/{step5_tco.js => step5_tco.mjs} | 0 es6/{step6_file.js => step6_file.mjs} | 0 es6/{step7_quote.js => step7_quote.mjs} | 0 es6/{step8_macros.js => step8_macros.mjs} | 0 es6/{step9_try.js => step9_try.mjs} | 0 es6/{stepA_mal.js => stepA_mal.mjs} | 0 es6/{types.js => types.mjs} | 34 ++++++------ 23 files changed, 55 insertions(+), 84 deletions(-) rename es6/{core.js => core.mjs} (86%) rename es6/{env.js => env.mjs} (100%) rename es6/{printer.js => printer.mjs} (92%) rename es6/{reader.js => reader.mjs} (96%) rename es6/{step0_repl.js => step0_repl.mjs} (100%) rename es6/{step1_read_print.js => step1_read_print.mjs} (100%) rename es6/{step2_eval.js => step2_eval.mjs} (100%) rename es6/{step3_env.js => step3_env.mjs} (100%) rename es6/{step4_if_fn_do.js => step4_if_fn_do.mjs} (100%) rename es6/{step5_tco.js => step5_tco.mjs} (100%) rename es6/{step6_file.js => step6_file.mjs} (100%) rename es6/{step7_quote.js => step7_quote.mjs} (100%) rename es6/{step8_macros.js => step8_macros.mjs} (100%) rename es6/{step9_try.js => step9_try.mjs} (100%) rename es6/{stepA_mal.js => stepA_mal.mjs} (100%) rename es6/{types.js => types.mjs} (62%) diff --git a/.gitignore b/.gitignore index a1651f2bf9..5ecac391f2 100644 --- a/.gitignore +++ b/.gitignore @@ -52,7 +52,7 @@ erlang/ebin erlang/.rebar erlang/src/*.beam es6/mal.js -es6/build +es6/.esm-cache factor/mal.factor forth/mal.fs fsharp/*.exe diff --git a/Makefile b/Makefile index 4a7b236a6e..8bf6a66f3f 100644 --- a/Makefile +++ b/Makefile @@ -189,7 +189,7 @@ elisp_STEP_TO_PROG = elisp/$($(1)).el elixir_STEP_TO_PROG = elixir/lib/mix/tasks/$($(1)).ex elm_STEP_TO_PROG = elm/$($(1)).js erlang_STEP_TO_PROG = erlang/$($(1)) -es6_STEP_TO_PROG = es6/build/$($(1)).js +es6_STEP_TO_PROG = es6/$($(1)).mjs factor_STEP_TO_PROG = factor/$($(1))/$($(1)).factor forth_STEP_TO_PROG = forth/$($(1)).fs fsharp_STEP_TO_PROG = fsharp/$($(1)).exe diff --git a/es6/Dockerfile b/es6/Dockerfile index 208e7f660e..ddcadb5b86 100644 --- a/es6/Dockerfile +++ b/es6/Dockerfile @@ -25,15 +25,10 @@ WORKDIR /mal RUN apt-get -y install g++ # Add nodesource apt repo config for 7.X -RUN curl -sL https://deb.nodesource.com/setup_7.x | bash - +RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - # Install nodejs RUN apt-get -y install nodejs # Link common name -RUN ln -sf nodejs /usr/bin/node - ENV NPM_CONFIG_CACHE /mal/.npm - -# ES6 -RUN npm install -g babel-cli babel-plugin-transform-es2015-modules-commonjs diff --git a/es6/Makefile b/es6/Makefile index 775b814f26..b88fd2a0d1 100644 --- a/es6/Makefile +++ b/es6/Makefile @@ -1,56 +1,32 @@ -export PATH := $(PATH):node_modules/.bin/ - -BABEL_OPTS = --source-maps true \ - --plugins transform-es2015-modules-commonjs - -SOURCES_BASE = node_readline.js types.js reader.js printer.js -SOURCES_LISP = env.js core.js stepA_mal.js +SOURCES_BASE = node_readline.js types.mjs reader.mjs printer.mjs +SOURCES_LISP = env.mjs core.mjs stepA_mal.mjs SOURCES = $(SOURCES_BASE) $(SOURCES_LISP) -STEPS = step0_repl step1_read_print step2_eval step3_env \ - step4_if_fn_do step5_tco step6_file step7_quote \ - step8_macros step9_try stepA_mal +STEPS = step0_repl.mjs step1_read_print.mjs step2_eval.mjs step3_env.mjs \ + step4_if_fn_do.mjs step5_tco.mjs step6_file.mjs \ + step7_quote.mjs step8_macros.mjs step9_try.mjs stepA_mal.mjs -all: node_modules $(foreach s,$(STEPS),build/$(s).js) +all: node_modules dist: mal.js mal -build/%.js: %.js node_modules - @mkdir -p $(dir $@) - babel $(BABEL_OPTS) $< --out-file $@ - @echo >> $@ # workaround node-uglifier bug +node_modules: + npm install + +$(STEPS): node_modules -mal.js: $(foreach s,$(SOURCES),build/$(s)) - node -e 'nu = new (require("node-uglifier"))("./build/stepA_mal.js"); nu.merge().exportToFile("$@")' +mal.js: $(SOURCES) + cat $+ | sed 's/^export //' | grep -v "^import " >> $@ mal: mal.js echo "#!/usr/bin/env node" > $@ cat $< >> $@ chmod +x $@ -STEP0_DEPS = build/node_readline.js -STEP1_DEPS = $(STEP0_DEPS) build/types.js build/reader.js build/printer.js -STEP3_DEPS = $(STEP1_DEPS) build/env.js -STEP4_DEPS = $(STEP3_DEPS) build/core.js - -build/step0_repl.js: $(STEP0_DEPS) -build/step1_read_print.js: $(STEP1_DEPS) -build/step2_eval.js: $(STEP1_DEPS) -build/step3_env.js: $(STEP3_DEPS) -build/step4_if_fn_do.js: $(STEP4_DEPS) -build/step5_tco.js: $(STEP4_DEPS) -build/step6_file.js: $(STEP4_DEPS) -build/step7_quote.js: $(STEP4_DEPS) -build/step8_macros.js: $(STEP4_DEPS) -build/step9_try.js: $(STEP4_DEPS) -build/stepA_mal.js: $(STEP4_DEPS) - - -node_modules: - npm install clean: - rm -f build/* mal.js mal + rm -f mal.js mal + rm -rf node_modules .PHONY: stats tests $(TESTS) diff --git a/es6/core.js b/es6/core.mjs similarity index 86% rename from es6/core.js rename to es6/core.mjs index cd11a8372a..7b9e1f5219 100644 --- a/es6/core.js +++ b/es6/core.mjs @@ -1,5 +1,5 @@ -import { _equal_Q, _clone, _keyword, _keyword_Q, - _list_Q, Vector, _assoc_BANG, _dissoc_BANG, Atom } from './types' +import { _equal_Q, _clone, _keyword, _keyword_Q } from './types' +import { _list_Q, Vector, _assoc_BANG, Atom } from './types' import { pr_str } from './printer' import { readline } from './node_readline' import { read_str } from './reader' @@ -22,16 +22,12 @@ function slurp(f) { } // Sequence functions -function conj(o, ...a) { - return _list_Q(o) ? a.reverse().concat(o) : Vector.from(o.concat(a)) -} - function seq(obj) { if (_list_Q(obj)) { return obj.length > 0 ? obj : null } else if (obj instanceof Vector) { return obj.length > 0 ? Array.from(obj.slice(0)) : null - } else if (typeof obj === "string" && obj[0] !== '\u029e') { + } else if (typeof obj === "string" && !_keyword_Q(obj)) { return obj.length > 0 ? obj.split('') : null } else if (obj === null) { return null @@ -48,7 +44,7 @@ export const core_ns = new Map([ ['nil?', a => a === null], ['true?', a => a === true], ['false?', a => a === false], - ['string?', a => typeof a === "string" && a[0] !== '\u029e'], + ['string?', a => typeof a === "string" && !_keyword_Q(a)], ['symbol', a => Symbol.for(a)], ['symbol?', a => typeof a === 'symbol'], ['keyword', _keyword], @@ -79,7 +75,8 @@ export const core_ns = new Map([ ['hash-map', (...a) => _assoc_BANG(new Map(), ...a)], ['map?', a => a instanceof Map], ['assoc', (m,...a) => _assoc_BANG(_clone(m), ...a)], - ['dissoc', (m,...a) => _dissoc_BANG(_clone(m), ...a)], + ['dissoc', (m,...a) => { let n = _clone(m); a.forEach(k => n.delete(k)); + return n}], ['get', (m,a) => m === null ? null : m.has(a) ? m.get(a) : null], ['contains?', (m,a) => m.has(a)], ['keys', a => Array.from(a.keys())], @@ -96,7 +93,8 @@ export const core_ns = new Map([ ['apply', (f,...a) => f(...a.slice(0, -1).concat(a[a.length-1]))], ['map', (f,a) => Array.from(a.map(x => f(x)))], - ['conj', conj], + ['conj', (s,...a) => _list_Q(s) ? a.reverse().concat(s) + : Vector.from(s.concat(a))], ['seq', seq], ['meta', a => 'meta' in a ? a['meta'] : null], diff --git a/es6/env.js b/es6/env.mjs similarity index 100% rename from es6/env.js rename to es6/env.mjs diff --git a/es6/node_readline.js b/es6/node_readline.js index dd5db0b68e..9e2fb864ba 100644 --- a/es6/node_readline.js +++ b/es6/node_readline.js @@ -13,7 +13,7 @@ var rllib = ffi.Library(RL_LIB, { var rl_history_loaded = false; -export function readline(prompt) { +function readline(prompt) { prompt = prompt || "user> "; if (!rl_history_loaded) { @@ -41,3 +41,6 @@ export function readline(prompt) { return line; }; + +//exports.readline = readline +module.exports = {readline: readline} diff --git a/es6/package.json b/es6/package.json index d836e6d663..627da97fec 100644 --- a/es6/package.json +++ b/es6/package.json @@ -3,11 +3,10 @@ "version": "0.0.1", "description": "Make a Lisp (mal) language implemented in ES6 (ECMAScript 6 / ECMAScript 2015)", "dependencies": { - "ffi": "2.0.x", - "node-uglifier": "0.4.3" + "@std/esm": "^0.11.0", + "ffi": "2.0.x" }, - "devDependencies": { - "babel-cli": "^6.0.0", - "babel-plugin-transform-es2015-modules-commonjs": "*" + "@std/esm": { + "cjs": true } } diff --git a/es6/printer.js b/es6/printer.mjs similarity index 92% rename from es6/printer.js rename to es6/printer.mjs index 18e5d350cb..82230f5d89 100644 --- a/es6/printer.js +++ b/es6/printer.mjs @@ -1,4 +1,4 @@ -import { _symbol, _list_Q, Vector, Atom } from './types' +import { _list_Q, _keyword_Q, Vector, Atom } from './types' export function pr_str(obj, print_readably) { if (typeof print_readably === 'undefined') { print_readably = true } @@ -14,7 +14,7 @@ export function pr_str(obj, print_readably) { } return "{" + ret.join(' ') + "}" } else if (typeof obj === "string") { - if (obj[0] === '\u029e') { + if (_keyword_Q(obj)) { return ':' + obj.slice(1) } else if (_r) { return '"' + obj.replace(/\\/g, "\\\\") diff --git a/es6/reader.js b/es6/reader.mjs similarity index 96% rename from es6/reader.js rename to es6/reader.mjs index fb2c2f2fac..ae23ddf084 100644 --- a/es6/reader.js +++ b/es6/reader.mjs @@ -1,4 +1,4 @@ -import { _keyword, Vector, _assoc_BANG } from './types' +import { _keyword, _assoc_BANG, Vector } from './types'; export class BlankException extends Error {} @@ -66,7 +66,7 @@ function read_list(reader, start, end) { // read vector of tokens function read_vector(reader) { - return Vector.from(read_list(reader, '[', ']')) + return Vector.from(read_list(reader, '[', ']')); } // read hash-map key/value pairs diff --git a/es6/run b/es6/run index 24d7d2b86b..a6c8bf8387 100755 --- a/es6/run +++ b/es6/run @@ -1,2 +1,2 @@ #!/bin/bash -exec node $(dirname $0)/build/${STEP:-stepA_mal}.js "${@}" +exec node -r @std/esm $(dirname $0)/${STEP:-stepA_mal}.mjs "${@}" diff --git a/es6/step0_repl.js b/es6/step0_repl.mjs similarity index 100% rename from es6/step0_repl.js rename to es6/step0_repl.mjs diff --git a/es6/step1_read_print.js b/es6/step1_read_print.mjs similarity index 100% rename from es6/step1_read_print.js rename to es6/step1_read_print.mjs diff --git a/es6/step2_eval.js b/es6/step2_eval.mjs similarity index 100% rename from es6/step2_eval.js rename to es6/step2_eval.mjs diff --git a/es6/step3_env.js b/es6/step3_env.mjs similarity index 100% rename from es6/step3_env.js rename to es6/step3_env.mjs diff --git a/es6/step4_if_fn_do.js b/es6/step4_if_fn_do.mjs similarity index 100% rename from es6/step4_if_fn_do.js rename to es6/step4_if_fn_do.mjs diff --git a/es6/step5_tco.js b/es6/step5_tco.mjs similarity index 100% rename from es6/step5_tco.js rename to es6/step5_tco.mjs diff --git a/es6/step6_file.js b/es6/step6_file.mjs similarity index 100% rename from es6/step6_file.js rename to es6/step6_file.mjs diff --git a/es6/step7_quote.js b/es6/step7_quote.mjs similarity index 100% rename from es6/step7_quote.js rename to es6/step7_quote.mjs diff --git a/es6/step8_macros.js b/es6/step8_macros.mjs similarity index 100% rename from es6/step8_macros.js rename to es6/step8_macros.mjs diff --git a/es6/step9_try.js b/es6/step9_try.mjs similarity index 100% rename from es6/step9_try.js rename to es6/step9_try.mjs diff --git a/es6/stepA_mal.js b/es6/stepA_mal.mjs similarity index 100% rename from es6/stepA_mal.js rename to es6/stepA_mal.mjs diff --git a/es6/types.js b/es6/types.mjs similarity index 62% rename from es6/types.js rename to es6/types.mjs index 458538ff55..d6198b6dce 100644 --- a/es6/types.js +++ b/es6/types.mjs @@ -19,12 +19,19 @@ export function _equal_Q (a, b) { export function _clone(obj, new_meta) { let new_obj = null - if (_list_Q(obj)) { new_obj = obj.slice(0) } - else if (obj instanceof Vector) { new_obj = Vector.from(obj.slice(0)) } - else if (obj instanceof Map) { new_obj = new Map(obj.entries()) } - else if (obj instanceof Function) { new_obj = obj.clone() } - else { throw Error("Invalid clone") } - if (new_meta !== undefined) { new_obj.meta = new_meta } + if (_list_Q(obj)) { + new_obj = obj.slice(0) + } else if (obj instanceof Vector) { + new_obj = Vector.from(obj) + } else if (obj instanceof Map) { + new_obj = new Map(obj.entries()) + } else if (obj instanceof Function) { + let f = (...a) => obj.apply(f, a) // new function instance + new_obj = Object.assign(f, obj) // copy original properties + } else { + throw Error('Unsupported type for clone') + } + if (typeof new_meta !== 'undefined') { new_obj.meta = new_meta } return new_obj } @@ -33,33 +40,26 @@ export function _malfunc(f, ast, env, params, meta=null, ismacro=false) { return Object.assign(f, {ast, env, params, meta, ismacro}) } export const _malfunc_Q = f => f.ast ? true : false -Function.prototype.clone = function() { - let f = (...a) => this.apply(f, a) // new function instance - return Object.assign(f, this) // copy original properties -} // Keywords export const _keyword = obj => _keyword_Q(obj) ? obj : '\u029e' + obj export const _keyword_Q = obj => typeof obj === 'string' && obj[0] === '\u029e' -// Sequence collections +// Lists export const _list_Q = obj => Array.isArray(obj) && !(obj instanceof Vector) -export class Vector extends Array {} +// Vectors +export class Vector extends Array { } +// Maps export function _assoc_BANG(hm, ...args) { if (args.length % 2 === 1) { throw new Error('Odd number of assoc arguments') } - // Use iterator/Array.from when it works for (let i=0; i