Elm: step 0
authorJos van Bakel <josvanbakel@gmail.com>
Sun, 4 Jun 2017 09:54:24 +0000 (11:54 +0200)
committerJos van Bakel <josvanbakel@gmail.com>
Sun, 4 Jun 2017 09:54:24 +0000 (11:54 +0200)
.gitignore
Makefile
elm/Dockerfile [new file with mode: 0644]
elm/Makefile [new file with mode: 0644]
elm/bootstrap.js [new file with mode: 0644]
elm/elm-package.json [new file with mode: 0644]
elm/node_readline.js [new file with mode: 0644]
elm/package.json [new file with mode: 0644]
elm/run [new file with mode: 0755]
elm/step0_repl.elm [new file with mode: 0644]

index 354278e..b5bfa49 100644 (file)
@@ -127,3 +127,8 @@ common-lisp/hist/*
 livescript/*.js
 !livescript/node_readline.js
 livescript/node_modules
+elm/node_modules
+elm/elm-stuff
+elm/*.js
+!elm/node_readline.js
+!elm/bootstrap.js
index 1ad8c84..7473c11 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -82,7 +82,7 @@ IMPLS = ada awk bash basic c d chuck clojure coffee common-lisp cpp crystal cs d
        haxe io java julia js kotlin logo lua make mal ocaml matlab miniMAL \
        nim objc objpascal perl perl6 php pil plpgsql plsql powershell ps \
        python r racket rpython ruby rust scala skew swift swift3 tcl ts vb vhdl \
-       vimscript livescript
+       vimscript livescript elm
 
 EXTENSION = .mal
 
@@ -216,6 +216,7 @@ vhdl_STEP_TO_PROG =    vhdl/$($(1))
 vimscript_STEP_TO_PROG = vimscript/$($(1)).vim
 guile_STEP_TO_PROG =   guile/$($(1)).scm
 livescript_STEP_TO_PROG = livescript/$($(1)).js
+elm_STEP_TO_PROG =     elm/$($(1)).elm
 
 
 # Needed some argument munging
diff --git a/elm/Dockerfile b/elm/Dockerfile
new file mode 100644 (file)
index 0000000..fbb4b55
--- /dev/null
@@ -0,0 +1,31 @@
+FROM ubuntu:xenial
+MAINTAINER Joel Martin <github@martintribe.org>
+
+##########################################################
+# General requirements for testing or common across many
+# implementations
+##########################################################
+
+RUN apt-get -y update
+
+# Required for running tests
+RUN apt-get -y install make python
+
+# Some typical implementation and test requirements
+RUN apt-get -y install curl libreadline-dev libedit-dev
+
+RUN mkdir -p /mal
+WORKDIR /mal
+
+##########################################################
+# Specific implementation requirements
+##########################################################
+
+# For building node modules
+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 -
+
+# Install nodejs
+RUN apt-get -y install nodejs
\ No newline at end of file
diff --git a/elm/Makefile b/elm/Makefile
new file mode 100644 (file)
index 0000000..e5daf40
--- /dev/null
@@ -0,0 +1,40 @@
+SOURCES_BASE = #reader.ls printer.ls env.ls core.ls utils.ls
+SOURCES_STEPS = step0_repl.elm #step1_read_print.ls step2_eval.ls \
+       step4_if_fn_do.ls step5_tco.ls step6_file.ls step7_quote.ls \
+       step8_macros.ls step9_try.ls stepA_mal.ls
+SOURCES_LISP = #env.ls core.ls stepA_mal.ls
+SOURCES = $(SOURCES_BASE) $(SOURCES_STEPS)
+
+BINS = $(SOURCES:%.elm=%.js)
+
+ELM_MAKE = node_modules/.bin/elm-make
+
+all: node_modules $(BINS)
+
+node_modules:
+       npm install
+
+%.js: %.elm node_modules
+       $(ELM_MAKE) $(@:%.js=%.elm) --output $@
+
+# step1_read_print.js: utils.js reader.js printer.js
+# step2_eval.js: utils.js reader.js printer.js
+# step3_env.js: utils.js reader.js printer.js env.js
+# step4_if_fn_do.js: utils.js reader.js printer.js env.js core.js
+# step5_tco.js: utils.js reader.js printer.js env.js core.js
+# step6_file.js: utils.js reader.js printer.js env.js core.js
+# step7_quote.js: utils.js reader.js printer.js env.js core.js
+# step8_macros.js: utils.js reader.js printer.js env.js core.js
+# step9_try.js: utils.js reader.js printer.js env.js core.js
+# stepA_mal.js: utils.js reader.js printer.js env.js core.js
+
+clean:
+       rm -f $(BINS)
+
+# stats: $(SOURCES)
+#      @wc $^
+#      @printf "%5s %5s %5s %s\n" `egrep "^\w*#|^\w*$$" $^ | wc` "[comments/blanks]"
+
+# stats-lisp: $(SOURCES_LISP)
+#      @wc $^
+#      @printf "%5s %5s %5s %s\n" `egrep "^\w*#|^\w*$$" $^ | wc` "[comments/blanks]"
diff --git a/elm/bootstrap.js b/elm/bootstrap.js
new file mode 100644 (file)
index 0000000..6ec5f30
--- /dev/null
@@ -0,0 +1,20 @@
+var readline = require('./node_readline');
+
+// The first two arguments are: 'node' and 'bootstrap.js'
+// The third argument is the name of the Elm module to load.
+var args = process.argv.slice(2);
+var mod = require('./' + args[0]);
+
+var app = mod.Main.worker({
+    args: args.slice(1)
+});
+
+// Hook up the output and readLine ports of the app.
+app.ports.output.subscribe(function(line) {
+    console.log(line);
+});
+
+app.ports.readLine.subscribe(function(prompt) {
+    var line = readline.readline(prompt);
+    app.ports.input.send(line);
+});
diff --git a/elm/elm-package.json b/elm/elm-package.json
new file mode 100644 (file)
index 0000000..bec8632
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "version": "1.0.0",
+    "summary": "Make-A-Lisp implementation in Elm",
+    "repository": "https://github.com/kanaka/mal.git",
+    "license": "BSD3",
+    "source-directories": [
+        "."
+    ],
+    "exposed-modules": [],
+    "dependencies": {
+        "elm-lang/core": "5.1.1 <= v < 6.0.0"
+    },
+    "elm-version": "0.18.0 <= v < 0.19.0"
+}
diff --git a/elm/node_readline.js b/elm/node_readline.js
new file mode 100644 (file)
index 0000000..e59a62b
--- /dev/null
@@ -0,0 +1,47 @@
+// IMPORTANT: choose one
+var RL_LIB = "libreadline";  // NOTE: libreadline is GPL
+//var RL_LIB = "libedit";
+
+var HISTORY_FILE = require('path').join(process.env.HOME, '.mal-history');
+
+var rlwrap = {}; // namespace for this module in web context
+
+var ffi = require('ffi'),
+    fs = require('fs');
+
+var rllib = ffi.Library(RL_LIB, {
+    'readline':    [ 'string', [ 'string' ] ],
+    'add_history': [ 'int',    [ 'string' ] ]});
+
+var rl_history_loaded = false;
+
+exports.readline = rlwrap.readline = function(prompt) {
+    prompt = typeof prompt !== 'undefined' ? prompt : "user> ";
+
+    if (!rl_history_loaded) {
+        rl_history_loaded = true;
+        var lines = [];
+        if (fs.existsSync(HISTORY_FILE)) {
+            lines = fs.readFileSync(HISTORY_FILE).toString().split("\n");
+        }
+        // Max of 2000 lines
+        lines = lines.slice(Math.max(lines.length - 2000, 0));
+        for (var i=0; i<lines.length; i++) {
+            if (lines[i]) { rllib.add_history(lines[i]); }
+        }
+    }
+
+    var line = rllib.readline(prompt);
+    if (line) {
+        rllib.add_history(line);
+        try {
+            fs.appendFileSync(HISTORY_FILE, line + "\n");
+        } catch (exc) {
+            // ignored
+        }
+    }
+
+    return line;
+};
+var readline = exports;
+
diff --git a/elm/package.json b/elm/package.json
new file mode 100644 (file)
index 0000000..dfbc2c7
--- /dev/null
@@ -0,0 +1,17 @@
+{
+  "name": "mal-elm",
+  "version": "1.0.0",
+  "description": "",
+  "main": "bootstrap.js",
+  "dependencies": {
+    "ffi": "2.0.x"
+  },
+  "devDependencies": {
+    "elm": "^0.18.0"
+  },
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "ISC"
+}
diff --git a/elm/run b/elm/run
new file mode 100755 (executable)
index 0000000..9802b00
--- /dev/null
+++ b/elm/run
@@ -0,0 +1,2 @@
+#!/bin/bash
+exec node $(dirname $0)/bootstrap.js ${STEP:-stepA_mal} "${@}"
diff --git a/elm/step0_repl.elm b/elm/step0_repl.elm
new file mode 100644 (file)
index 0000000..b7960c8
--- /dev/null
@@ -0,0 +1,81 @@
+port module Main exposing (..)
+
+import Platform exposing (programWithFlags)
+import Json.Decode
+
+
+port output : String -> Cmd msg
+
+
+port readLine : String -> Cmd msg
+
+
+port input : (Maybe String -> msg) -> Sub msg
+
+
+main : Program Flags Model Msg
+main =
+    programWithFlags
+        { init = init
+        , update = update
+        , subscriptions = \model -> input Input
+        }
+
+
+type alias Flags =
+    { args : List String
+    }
+
+
+type alias Model =
+    { args : List String
+    }
+
+
+type Msg
+    = Input (Maybe String)
+
+
+init : Flags -> ( Model, Cmd Msg )
+init flags =
+    ( flags, readLine prompt )
+
+
+update : Msg -> Model -> ( Model, Cmd Msg )
+update msg model =
+    case msg of
+        Input (Just line) ->
+            ( model
+            , Cmd.batch
+                [ output (rep line)
+                , readLine prompt
+                ]
+            )
+
+        Input Nothing ->
+            ( model, Cmd.none )
+
+
+prompt : String
+prompt =
+    "user> "
+
+
+read : String -> String
+read ast =
+    ast
+
+
+eval : String -> String
+eval ast =
+    ast
+
+
+print : String -> String
+print ast =
+    ast
+
+
+rep : String -> String
+rep =
+    read >> eval >> print