diff --git a/editor/package-lock.json b/editor/package-lock.json index a18bf4384..15d60113b 100644 --- a/editor/package-lock.json +++ b/editor/package-lock.json @@ -12,6 +12,7 @@ }, "devDependencies": { "@rollup/plugin-commonjs": "^17.0.0", + "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^11.0.0", "rollup": "^2.3.4", "rollup-plugin-css-only": "^3.1.0", @@ -82,6 +83,18 @@ "rollup": "^2.30.0" } }, + "node_modules/@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.0.8" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, "node_modules/@rollup/plugin-node-resolve": { "version": "11.2.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", @@ -1087,6 +1100,15 @@ "resolve": "^1.17.0" } }, + "@rollup/plugin-json": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", + "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.0.8" + } + }, "@rollup/plugin-node-resolve": { "version": "11.2.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", diff --git a/editor/package.json b/editor/package.json index 07400ffc7..2ba40ccbd 100644 --- a/editor/package.json +++ b/editor/package.json @@ -9,6 +9,7 @@ }, "devDependencies": { "@rollup/plugin-commonjs": "^17.0.0", + "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^11.0.0", "rollup": "^2.3.4", "rollup-plugin-css-only": "^3.1.0", diff --git a/editor/public/saved.json b/editor/public/saved.json index 901588894..6f5a56563 100644 --- a/editor/public/saved.json +++ b/editor/public/saved.json @@ -2698,17 +2698,12 @@ "value": { "node": "Function", "pattern": { - "node": "Tuple", - "elements": [ - { - "node": "Bind", - "label": "" - } - ] + "node": "Variable", + "label": "state" }, "body": { - "node": "Binary", - "value": "hello" + "node": "Variable", + "label": "state" } }, "then": { @@ -2921,13 +2916,8 @@ "label": "new" }, "value": { - "node": "Tuple", - "elements": [ - { - "node": "Variable", - "label": "old" - } - ] + "node": "Variable", + "label": "old" }, "then": { "node": "Call", @@ -2943,37 +2933,67 @@ } }, "then": { - "node": "Record", - "fields": [ - { - "node": "Field", - "key": "init", - "value": { - "node": "Call", - "function": { - "node": "Variable", - "label": "run" - }, - "with": { - "node": "Tuple", - "elements": [ - { - "node": "Binary", - "value": "" - } - ] + "node": "Let", + "pattern": { + "node": "Variable", + "label": "init" + }, + "value": { + "node": "Record", + "fields": [ + { + "node": "Field", + "key": "page", + "value": { + "node": "Call", + "function": { + "node": "Variable", + "label": "render" + }, + "with": { + "node": "Binary", + "value": "initial state" + } + } + }, + { + "node": "Field", + "key": "interrupt", + "value": { + "node": "Call", + "function": { + "node": "Variable", + "label": "run" + }, + "with": { + "node": "Binary", + "value": "initial state" + } } } - }, - { - "node": "Field", - "key": "release", - "value": { - "node": "Variable", - "label": "release" + ] + }, + "then": { + "node": "Record", + "fields": [ + { + "node": "Field", + "key": "init", + "value": { + "node": "Variable", + "label": "init" + } + }, + { + "node": "Field", + "key": "release", + "value": { + "node": "Variable", + "label": "release" + } } - } - ] + ] + } } } } @@ -2982,533 +3002,106 @@ "node": "Let", "pattern": { "node": "Variable", - "label": "reload" + "label": "web" }, "value": { "node": "Function", "pattern": { - "node": "Tuple", - "elements": [] + "node": "Variable", + "label": "req" }, "body": { - "node": "Let", - "pattern": { - "node": "Variable", - "label": "release" - }, + "node": "Case", "value": { - "node": "Function", - "pattern": { + "node": "Call", + "function": { "node": "Variable", - "label": "old" + "label": "equal" }, - "body": { - "node": "Let", - "pattern": { - "node": "Tuple", - "elements": [] - }, - "value": { - "node": "Variable", - "label": "old" - }, - "then": { - "node": "Let", - "pattern": { - "node": "Variable", - "label": "new" - }, - "value": { - "node": "Tuple", - "elements": [ - { - "node": "Variable", - "label": "old" - } - ] + "with": { + "node": "Tuple", + "elements": [ + { + "node": "Binary", + "value": "/code" }, - "then": { - "node": "Let", - "pattern": { - "node": "Variable", - "label": "run" - }, + { + "node": "Access", "value": { - "node": "Function", - "pattern": { - "node": "Variable", - "label": "state" - }, - "body": { - "node": "Function", - "pattern": { - "node": "Variable", - "label": "interrupt" - }, - "body": { - "node": "Case", - "value": { - "node": "Variable", - "label": "interrupt" - }, - "branches": [ - { - "node": "Branch", - "name": "Click", - "pattern": { - "node": "Variable", - "label": "target" - }, - "then": { - "node": "Let", - "pattern": { - "node": "Variable", - "label": "" - }, - "value": { - "node": "Call", - "function": { - "node": "Variable", - "label": "equal" - }, - "with": { - "node": "Tuple", - "elements": [ - { - "node": "Binary", - "value": "" - }, - { - "node": "Variable", - "label": "target" - } - ] - } - }, - "then": { - "node": "Record", - "fields": [ - { - "node": "Field", - "key": "page", - "value": { - "node": "Binary", - "value": "render" - } - }, - { - "node": "Field", - "key": "interrupt", - "value": { - "node": "Call", - "function": { - "node": "Variable", - "label": "run" - }, - "with": { - "node": "Variable", - "label": "state" - } - } - } - ] - } - } - }, - { - "node": "Branch", - "name": "Code", - "pattern": { - "node": "Variable", - "label": "source" - }, - "then": { - "node": "Case", - "value": { - "node": "Call", - "function": { - "node": "Provider", - "config": "", - "generator": "Loader" - }, - "with": { - "node": "Variable", - "label": "source" - } - }, - "branches": [ - { - "node": "Branch", - "name": "Error", - "pattern": { - "node": "Variable", - "label": "" - }, - "then": { - "node": "Hole" - } - }, - { - "node": "Branch", - "name": "OK", - "pattern": { - "node": "Variable", - "label": "release" - }, - "then": { - "node": "Call", - "function": { - "node": "Variable", - "label": "release" - }, - "with": { - "node": "Variable", - "label": "state" - } - } - } - ] - } - } - ] - } - } + "node": "Variable", + "label": "req" }, - "then": { - "node": "Call", - "function": { - "node": "Variable", - "label": "run" - }, - "with": { - "node": "Variable", - "label": "new" - } - } + "key": "path" } - } + ] } }, - "then": { - "node": "Let", - "pattern": { - "node": "Variable", - "label": "run" - }, - "value": { - "node": "Function", + "branches": [ + { + "node": "Branch", + "name": "False", "pattern": { - "node": "Variable", - "label": "state" + "node": "Tuple", + "elements": [] }, - "body": { - "node": "Function", - "pattern": { - "node": "Variable", - "label": "interupt" - }, - "body": { - "node": "Case", - "value": { - "node": "Variable", - "label": "interupt" - }, - "branches": [ - { - "node": "Branch", - "name": "Click", - "pattern": { - "node": "Variable", - "label": "target" - }, - "then": { - "node": "Let", - "pattern": { - "node": "Variable", - "label": "" - }, - "value": { - "node": "Call", - "function": { - "node": "Variable", - "label": "equal" - }, - "with": { - "node": "Tuple", - "elements": [ - { - "node": "Binary", - "value": "" - }, - { - "node": "Variable", - "label": "target" - } - ] - } - }, - "then": { - "node": "Record", - "fields": [ - { - "node": "Field", - "key": "page", - "value": { - "node": "Binary", - "value": "render" - } - }, - { - "node": "Field", - "key": "interrupt", - "value": { - "node": "Call", - "function": { - "node": "Variable", - "label": "run" - }, - "with": { - "node": "Variable", - "label": "state" - } - } - } - ] - } - } - }, - { - "node": "Branch", - "name": "Code", - "pattern": { - "node": "Variable", - "label": "source" - }, - "then": { - "node": "Case", - "value": { - "node": "Call", - "function": { - "node": "Provider", - "config": "", - "generator": "Loader" - }, - "with": { - "node": "Variable", - "label": "source" - } - }, - "branches": [ - { - "node": "Branch", - "name": "Error", - "pattern": { - "node": "Variable", - "label": "" - }, - "then": { - "node": "Record", - "fields": [ - { - "node": "Field", - "key": "page", - "value": { - "node": "Binary", - "value": "render" - } - }, - { - "node": "Field", - "key": "interrupt", - "value": { - "node": "Call", - "function": { - "node": "Variable", - "label": "run" - }, - "with": { - "node": "Variable", - "label": "state" - } - } - } - ] - } - }, - { - "node": "Branch", - "name": "OK", - "pattern": { - "node": "Variable", - "label": "release" - }, - "then": { - "node": "Call", - "function": { - "node": "Variable", - "label": "release" - }, - "with": { - "node": "Variable", - "label": "state" - } - } - } - ] - } - } - ] - } + "then": { + "node": "Binary", + "value": "" } }, - "then": { - "node": "Let", + { + "node": "Branch", + "name": "True", "pattern": { - "node": "Variable", - "label": "handle" + "node": "Tuple", + "elements": [] }, - "value": { - "node": "Function", - "pattern": { - "node": "Tuple", - "elements": [ - { - "node": "Bind", - "label": "interrupt" - }, - { - "node": "Bind", - "label": "state" - } - ] - }, - "body": { - "node": "Let", - "pattern": { - "node": "Variable", - "label": "" - }, + "then": { + "node": "Call", + "function": { + "node": "Access", "value": { - "node": "Case", - "value": { - "node": "Hole" - }, - "branches": [ - { - "node": "Branch", - "name": "Update", - "pattern": { - "node": "Variable", - "label": "source" - }, - "then": { - "node": "Hole" - } - } - ] + "node": "Variable", + "label": "builtin" }, - "then": { - "node": "Let", - "pattern": { - "node": "Variable", - "label": "" - }, - "value": { - "node": "Tuple", - "elements": [] - }, - "then": { - "node": "Variable", - "label": "state" - } - } - } - }, - "then": { - "node": "Let", - "pattern": { - "node": "Variable", - "label": "update" + "key": "serialize" }, - "value": { + "with": { "node": "Function", "pattern": { "node": "Variable", - "label": "state" + "label": "" }, "body": { - "node": "Let", - "pattern": { - "node": "Variable", - "label": "page" - }, - "value": { - "node": "Binary", - "value": "render" - }, - "then": { - "node": "Record", - "fields": [ - { - "node": "Field", - "key": "interrupt", - "value": { - "node": "Function", - "pattern": { - "node": "Variable", - "label": "i" - }, - "body": { - "node": "Call", - "function": { - "node": "Variable", - "label": "update" - }, - "with": { - "node": "Call", - "function": { - "node": "Variable", - "label": "handle" - }, - "with": { - "node": "Tuple", - "elements": [ - { - "node": "Variable", - "label": "i" - }, - { - "node": "Variable", - "label": "state" - } - ] - } - } - } - } - } - ] - } - } - }, - "then": { - "node": "Call", - "function": { - "node": "Variable", - "label": "update" - }, - "with": { - "node": "Binary", - "value": "0" + "node": "Tuple", + "elements": [] } } } } - } + ] } }, "then": { - "node": "Hole" + "node": "Record", + "fields": [ + { + "node": "Field", + "key": "counter", + "value": { + "node": "Variable", + "label": "counter" + } + }, + { + "node": "Field", + "key": "web", + "value": { + "node": "Variable", + "label": "web" + } + } + ] } } } @@ -4459,11 +4052,15 @@ "elements": [ { "node": "Binary", - "value": "localhost:5003" + "value": "localhost:5004" }, { - "node": "Variable", - "label": "counter" + "node": "Access", + "value": { + "node": "Variable", + "label": "reload" + }, + "key": "web" } ] }, @@ -4491,7 +4088,7 @@ "elements": [ { "node": "Binary", - "value": "counter.web.petersaxton.uk" + "value": "localhost:5003" }, { "node": "Variable", @@ -4523,11 +4120,11 @@ "elements": [ { "node": "Binary", - "value": "localhost:5002" + "value": "counter.web.petersaxton.uk" }, { "node": "Variable", - "label": "cluster" + "label": "counter" } ] }, @@ -4555,7 +4152,7 @@ "elements": [ { "node": "Binary", - "value": "cluster.web.petersaxton.uk" + "value": "localhost:5002" }, { "node": "Variable", @@ -4587,11 +4184,11 @@ "elements": [ { "node": "Binary", - "value": "localhost:5001" + "value": "cluster.web.petersaxton.uk" }, { "node": "Variable", - "label": "dashboard" + "label": "cluster" } ] }, @@ -4619,7 +4216,7 @@ "elements": [ { "node": "Binary", - "value": "dashboard.web.petersaxton.uk" + "value": "localhost:5001" }, { "node": "Variable", @@ -4638,92 +4235,125 @@ "node": "Let", "pattern": { "node": "Variable", - "label": "route" + "label": "routes" }, "value": { - "node": "Call", - "function": { - "node": "Access", - "value": { - "node": "Access", - "value": { - "node": "Variable", - "label": "lib" - }, - "key": "list" - }, - "key": "key_find" - }, - "with": { + "node": "Tagged", + "tag": "Cons", + "value": { "node": "Tuple", "elements": [ { - "node": "Variable", - "label": "routes" + "node": "Tuple", + "elements": [ + { + "node": "Binary", + "value": "dashboard.web.petersaxton.uk" + }, + { + "node": "Variable", + "label": "dashboard" + } + ] }, { - "node": "Access", - "value": { - "node": "Variable", - "label": "request" - }, - "key": "origin" + "node": "Variable", + "label": "routes" } ] } }, "then": { - "node": "Case", - "value": { + "node": "Let", + "pattern": { "node": "Variable", "label": "route" }, - "branches": [ - { - "node": "Branch", - "name": "Error", - "pattern": { - "node": "Tuple", - "elements": [] - }, - "then": { + "value": { + "node": "Call", + "function": { + "node": "Access", + "value": { "node": "Access", "value": { "node": "Variable", - "label": "request" + "label": "lib" }, - "key": "origin" - } + "key": "list" + }, + "key": "key_find" }, - { - "node": "Branch", - "name": "Ok", - "pattern": { - "node": "Tuple", - "elements": [ - { - "node": "Bind", - "label": "" + "with": { + "node": "Tuple", + "elements": [ + { + "node": "Variable", + "label": "routes" + }, + { + "node": "Access", + "value": { + "node": "Variable", + "label": "request" }, - { - "node": "Bind", - "label": "page" - } - ] + "key": "origin" + } + ] + } + }, + "then": { + "node": "Case", + "value": { + "node": "Variable", + "label": "route" + }, + "branches": [ + { + "node": "Branch", + "name": "Error", + "pattern": { + "node": "Tuple", + "elements": [] + }, + "then": { + "node": "Access", + "value": { + "node": "Variable", + "label": "request" + }, + "key": "origin" + } }, - "then": { - "node": "Call", - "function": { - "node": "Variable", - "label": "page" + { + "node": "Branch", + "name": "Ok", + "pattern": { + "node": "Tuple", + "elements": [ + { + "node": "Bind", + "label": "" + }, + { + "node": "Bind", + "label": "page" + } + ] }, - "with": { - "node": "Variable", - "label": "request" + "then": { + "node": "Call", + "function": { + "node": "Variable", + "label": "page" + }, + "with": { + "node": "Variable", + "label": "request" + } } } - } - ] + ] + } } } } @@ -4735,25 +4365,89 @@ } }, "then": { - "node": "Record", - "fields": [ - { - "node": "Field", - "key": "proxy", - "value": { - "node": "Variable", - "label": "web" + "node": "Let", + "pattern": { + "node": "Variable", + "label": "counter_init" + }, + "value": { + "node": "Tuple", + "elements": [ + { + "node": "Access", + "value": { + "node": "Access", + "value": { + "node": "Access", + "value": { + "node": "Variable", + "label": "reload" + }, + "key": "counter" + }, + "key": "init" + }, + "key": "page" + }, + { + "node": "Access", + "value": { + "node": "Access", + "value": { + "node": "Access", + "value": { + "node": "Variable", + "label": "reload" + }, + "key": "counter" + }, + "key": "init" + }, + "key": "interrupt" } - }, - { - "node": "Field", - "key": "web", - "value": { - "node": "Variable", - "label": "web" + ] + }, + "then": { + "node": "Record", + "fields": [ + { + "node": "Field", + "key": "proxy", + "value": { + "node": "Variable", + "label": "web" + } + }, + { + "node": "Field", + "key": "web", + "value": { + "node": "Variable", + "label": "web" + } + }, + { + "node": "Field", + "key": "counter_init", + "value": { + "node": "Variable", + "label": "counter_init" + } + }, + { + "node": "Field", + "key": "counter", + "value": { + "node": "Access", + "value": { + "node": "Variable", + "label": "reload" + }, + "key": "counter" + } } - } - ] + ] + } } } } diff --git a/editor/rollup.config.js b/editor/rollup.config.js index e8965ec8d..4fd6acd31 100644 --- a/editor/rollup.config.js +++ b/editor/rollup.config.js @@ -1,76 +1,93 @@ -import svelte from 'rollup-plugin-svelte'; -import commonjs from '@rollup/plugin-commonjs'; -import resolve from '@rollup/plugin-node-resolve'; -import livereload from 'rollup-plugin-livereload'; -import { terser } from 'rollup-plugin-terser'; -import css from 'rollup-plugin-css-only'; +import svelte from "rollup-plugin-svelte"; +import commonjs from "@rollup/plugin-commonjs"; +import resolve from "@rollup/plugin-node-resolve"; +import livereload from "rollup-plugin-livereload"; +import { terser } from "rollup-plugin-terser"; +import css from "rollup-plugin-css-only"; +import json from "@rollup/plugin-json"; const production = !process.env.ROLLUP_WATCH; function serve() { - let server; + let server; - function toExit() { - if (server) server.kill(0); - } + function toExit() { + if (server) server.kill(0); + } - return { - writeBundle() { - if (server) return; - server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], { - stdio: ['ignore', 'inherit', 'inherit'], - shell: true - }); + return { + writeBundle() { + if (server) return; + server = require("child_process").spawn( + "npm", + ["run", "start", "--", "--dev"], + { + stdio: ["ignore", "inherit", "inherit"], + shell: true, + } + ); - process.on('SIGTERM', toExit); - process.on('exit', toExit); - } - }; + process.on("SIGTERM", toExit); + process.on("exit", toExit); + }, + }; } -export default { - input: 'src/main.js', - output: { - sourcemap: true, - format: 'iife', - name: 'app', - file: 'public/build/bundle.js' - }, - plugins: [ - svelte({ - compilerOptions: { - // enable run-time checks when not in production - dev: !production - } - }), - // we'll extract any component CSS out into - // a separate file - better for performance - css({ output: 'bundle.css' }), +export default [ + { + input: "src/other.js", + output: { + sourcemap: true, + format: "iife", + name: "app", + file: "public/build/other.js", + }, + plugins: [json()], + }, + { + input: "src/main.js", + output: { + sourcemap: true, + format: "iife", + name: "app", + file: "public/build/bundle.js", + }, + plugins: [ + svelte({ + compilerOptions: { + // enable run-time checks when not in production + dev: !production, + }, + }), + // we'll extract any component CSS out into + // a separate file - better for performance + css({ output: "bundle.css" }), - // If you have external dependencies installed from - // npm, you'll most likely need these plugins. In - // some cases you'll need additional configuration - - // consult the documentation for details: - // https://github.com/rollup/plugins/tree/master/packages/commonjs - resolve({ - browser: true, - dedupe: ['svelte'] - }), - commonjs(), + // If you have external dependencies installed from + // npm, you'll most likely need these plugins. In + // some cases you'll need additional configuration - + // consult the documentation for details: + // https://github.com/rollup/plugins/tree/master/packages/commonjs + resolve({ + browser: true, + dedupe: ["svelte"], + }), + commonjs(), - // In dev mode, call `npm run start` once - // the bundle has been generated - !production && serve(), + // In dev mode, call `npm run start` once + // the bundle has been generated + !production && serve(), - // Watch the `public` directory and refresh the - // browser on changes when not in production - !production && livereload('public'), + // Watch the `public` directory and refresh the + // browser on changes when not in production + !production && livereload("public"), - // If we're building for production (npm run build - // instead of npm run dev), minify - production && terser() - ], - watch: { - clearScreen: false - } -}; + // If we're building for production (npm run build + // instead of npm run dev), minify + production && terser(), + ], + watch: { + clearScreen: false, + }, + }, +]; diff --git a/editor/src/main.js b/editor/src/main.js index fdc47ab57..e382ae50f 100644 --- a/editor/src/main.js +++ b/editor/src/main.js @@ -1,4 +1,5 @@ // import { main } from "../../eyg/build/dev/javascript/eyg/dist/eyg/workspace/main"; +// TODO remove deploy import { deploy } from "../../eyg/build/dev/javascript/eyg/dist/eyg/workspace/ui.mjs"; import * as Spreasheet from "../../eyg/build/dev/javascript/eyg/dist/spreadsheet/main.mjs"; diff --git a/editor/src/other.js b/editor/src/other.js new file mode 100644 index 000000000..382cbe7e0 --- /dev/null +++ b/editor/src/other.js @@ -0,0 +1,22 @@ +import * as Entry from "../../eyg/build/dev/javascript/eyg/dist/eyg/entry.mjs"; +import * as Encode from "../../eyg/build/dev/javascript/eyg/dist/eyg/ast/encode.mjs"; + +// Roll up adds a default object that breaks matchings +import data from "../public/saved.json"; +// This is not generic has because we have the server or maybe not. this is the arbitrary script pull +// let target = new URL(document.currentScript.src).hash.slice(1); +// console.log(target, Analysis); + +async function GoGoGo() { + const source = Encode.from_json(data); + const initial = Entry.interpret_client(source, "counter"); + console.log(initial); + const { default: next } = await import("../public/saved.json"); + console.log(Encode.from_json(next)); +} + +console.log(window, GoGoGo); +window.GoGoGo = GoGoGo; +GoGoGo(); +// Started doing this because the code gen was troublesome, also in code gen we will nee to pull in the loader +// here we have can use the already existing gleam .run diff --git a/eyg/src/eyg/analysis.gleam b/eyg/src/eyg/analysis.gleam index d267fb7d7..b1fe51926 100644 --- a/eyg/src/eyg/analysis.gleam +++ b/eyg/src/eyg/analysis.gleam @@ -16,6 +16,10 @@ pub fn infer(untyped, type_, variables) { typer.infer(untyped, type_, t.empty, state) } +pub fn infer_unbound(untyped) { + infer(untyped, t.Unbound(-1), []) +} + pub fn infer_effectful(untyped, type_, effects, variables) { let checker = typer.init() let scope = typer.root_scope(variables) diff --git a/eyg/src/eyg/ast/encode.gleam b/eyg/src/eyg/ast/encode.gleam index 7172175e7..98eb02df3 100644 --- a/eyg/src/eyg/ast/encode.gleam +++ b/eyg/src/eyg/ast/encode.gleam @@ -164,6 +164,9 @@ external fn from_array(value: JSON) -> List(JSON) = pub fn from_json(json: JSON) { assert Ok(#(node, rest)) = list.key_pop(entries(json), "node") + + // TODO need to load out properly + // TODO make this robust no asserts or assumption of order use key pop // find node and order rest case assert_string(node) { "Binary" -> { @@ -203,7 +206,6 @@ pub fn from_json(json: JSON) { let [#("label", label)] = rest ast.variable(assert_string(label)) } - "Let" -> { let [#("pattern", pattern), #("value", value), #("then", then)] = rest let pattern = pattern_from_json(pattern) diff --git a/eyg/src/eyg/codegen/javascript.gleam b/eyg/src/eyg/codegen/javascript.gleam index 7c783cf50..85fad8299 100644 --- a/eyg/src/eyg/codegen/javascript.gleam +++ b/eyg/src/eyg/codegen/javascript.gleam @@ -173,8 +173,7 @@ pub fn escape_string(raw) { |> string.replace("\\", "\\\\") |> string.replace("'", "\\'") |> string.replace("\"", "\\\"") - -// Not js but browser + // Not js but browser |> string.replace("<", "\\<") |> string.replace(">", "\\>") } diff --git a/eyg/src/eyg/entry.gleam b/eyg/src/eyg/entry.gleam new file mode 100644 index 000000000..776974bbe --- /dev/null +++ b/eyg/src/eyg/entry.gleam @@ -0,0 +1,59 @@ +import gleam/io +import gleam/map +import gleam/option.{None} +import gleam/string +import eyg/ast/encode +import eyg/ast/expression as e +import eyg/interpreter/effectful +// TODO need an effectful version that allows us to access stuff here +import eyg/interpreter/tail_call +import gleam/javascript/array +import eyg/interpreter/interpreter as r +import eyg/ast/pattern as p +import eyg/analysis +import eyg/typer +import eyg/typer/monotype as t +import eyg/editor/editor + +fn update(page, interrupt, display, on_click) { + io.debug(page) + display(page) +} + +fn b(args) { + Ok(args) +} + +fn tree() { + r.Function( + p.Variable("x"), + e.tuple_([e.variable("x"), e.variable("x")]), + map.new(), + None, + ) +} + +// uses default builtin that need moving out of effectful +// has an entry point key should eventually be a hash +// maybe rename interpret standard +// builtin is always the same but env things are passed in +// All the runtime stuff is in gleam terms +// TODO are there any gleam helpers to turn tuples into things +pub fn interpret_client(source, key, display, on_click) { + io.debug("hooo") + let init = e.access(e.access(source, key), "init") + io.debug(init) + let #(typed, typer) = analysis.infer(init, t.Unbound(-1), []) + io.debug("---- typed") + let #(xtyped, typer) = + typer.expand_providers(typed, typer, []) + // Running the interpreter kills the client + // assert Ok(term) = effectful.eval(editor.untype(xtyped)) + // io.debug(term) + |> io.debug + io.debug("expanded") + effectful.eval_call(tree(), r.Binary("nothing exciting"), effectful.real_log) + |> io.debug + // // TODO make an AST the requires rendering + // term +} diff --git a/eyg/src/eyg/interpreter/effectful.gleam b/eyg/src/eyg/interpreter/effectful.gleam index 87a302b4b..f91854a65 100644 --- a/eyg/src/eyg/interpreter/effectful.gleam +++ b/eyg/src/eyg/interpreter/effectful.gleam @@ -81,8 +81,23 @@ fn term_serialize(term) { "({ on_click: (f) => { document.onclick = () => f() }, display: (value) => document.body.innerHTML = value, + // TODO does with work can we have outside poller + on_code: (f) => { document.oncode = f } });", ) + // This didn't work because of rendering captured variables for a fn within some scope. + // We need a whole review of rendering or use interpreter + // "(({init}) => { + // console.log(init, 'initial state') + // const update = ({page, interrupt}) => { + // document.body.innerHTML = page + // document.onclick = () => update(interrupt({Click: 'key'})) + // document.oncode = (code) => update(interrupt({Code: code})) + // TODO this needs the codegen part of loader + // } + // update(init) + // // TODO set interval + // })" let page = string.concat([""]) // assert r.Function() = term diff --git a/eyg/src/eyg/interpreter/interpreter.gleam b/eyg/src/eyg/interpreter/interpreter.gleam index 70bda68d1..a10abcf18 100644 --- a/eyg/src/eyg/interpreter/interpreter.gleam +++ b/eyg/src/eyg/interpreter/interpreter.gleam @@ -12,7 +12,6 @@ import eyg/analysis import eyg/typer import eyg/typer/monotype as t - pub type Object { Binary(String) Pid(Int) @@ -64,6 +63,7 @@ pub fn render_var(assignment) { #("equal", _) -> "let equal = ([a, b]) => a == b;" // TODO remove duplication of this builtincode // can i import * as builtin from /gleam/version + // TODO builtin needs to include render #("builtin", _) -> "let builtin = {append: ([a, b]) => a + b}" // TODO have a standard builtin to lookup table #("send", BuiltinFn(_)) -> @@ -117,12 +117,15 @@ pub fn render_object(object) { string.concat(["{", tag, ":", render_object(value), "}"]) // Builtins should never be included, I need to check variables used in a previous step // Function(_,_,_,_) -> todo("this needs compile again but I need a way to do this without another type check") - Function(pattern, body, _, _) -> { - let #(typed, typer) = analysis.infer(e.function(pattern, body), t.Unbound(-1), []) - let #(typed, typer) = typer.expand_providers(typed, typer, []) - javascript.render_to_string(typed, typer) + Function(pattern, body, captured, _) -> { + // TODO this needs to render captured to be useful + let #(typed, typer) = + analysis.infer(e.function(pattern, body), t.Unbound(-1), []) + let #(typed, typer) = typer.expand_providers(typed, typer, []) + javascript.render_to_string(typed, typer) } - BuiltinFn(_) -> "null /* we aren't using builtin here should be part of env */" + BuiltinFn(_) -> + "null /* we aren't using builtin here should be part of env */" // TODO remove Coroutine/ready there where and old experiment Coroutine(_) -> "null" Ready(_, _) -> "null" diff --git a/eyg/src/eyg/typer/monotype.gleam b/eyg/src/eyg/typer/monotype.gleam index 53c8d7c17..0e1ae6aeb 100644 --- a/eyg/src/eyg/typer/monotype.gleam +++ b/eyg/src/eyg/typer/monotype.gleam @@ -76,8 +76,15 @@ pub fn literal(monotype) { // need to add effects string.concat(["new T.Function(", literal(from), ",", literal(to), ")"]) Unbound(i) -> string.concat(["new T.Unbound(", int.to_string(i), ")"]) - Recursive(i, rest) -> string.concat(["new T.Recursive(", int.to_string(i), ", ", literal(rest), ")"]) - Native(_, _) -> { + Recursive(i, rest) -> + string.concat([ + "new T.Recursive(", + int.to_string(i), + ", ", + literal(rest), + ")", + ]) + Native(_, _) -> { io.debug(monotype) todo("ss literal") } diff --git a/eyg/src/platform/browser.gleam b/eyg/src/platform/browser.gleam index a92e1d4ca..3a08250d0 100644 --- a/eyg/src/platform/browser.gleam +++ b/eyg/src/platform/browser.gleam @@ -36,13 +36,13 @@ fn builtins() { ) |> add_field("serialize", t.Function(t.Unbound(0), t.Binary, t.empty)) |> add_field( - "compile", - t.Function( - t.Tuple([t.Binary, t.Binary]), - t.Union([#("OK", t.Unbound(0)), #("Error", t.Binary)], Some(1)), - t.empty, - ), - ) + "compile", + t.Function( + t.Tuple([t.Binary, t.Binary]), + t.Union([#("OK", t.Unbound(0)), #("Error", t.Binary)], Some(1)), + t.empty, + ), + ) } fn add_field(state, key, type_) { diff --git a/eyg/test/eyg/analysis_test.gleam b/eyg/test/eyg/analysis_test.gleam new file mode 100644 index 000000000..456f0ebed --- /dev/null +++ b/eyg/test/eyg/analysis_test.gleam @@ -0,0 +1,130 @@ +import gleam/io +import gleam/option.{Some} +import gleam/list +import gleam/string +import eyg/ast/expression as e +import eyg/ast/pattern as p +import eyg/typer/monotype as t +import eyg/analysis +import eyg/typer + +fn variables_needed(source) { + do_variables_needed(source) + |> list.unique + |> list.sort(string.compare) +} + +fn do_variables_needed(tree) { + let #(_, exp) = tree + case exp { + e.Binary(_) | e.Hole -> [] + e.Variable(label) -> [label] + e.Tuple(elems) -> + list.fold( + elems, + [], + fn(acc, e) { list.append(acc, do_variables_needed(e)) }, + ) + e.Record(fields) -> + list.fold( + fields, + [], + fn(acc, f) { + let #(_, e) = f + list.append(acc, do_variables_needed(e)) + }, + ) + e.Access(e, _) | e.Tagged(_, e) -> do_variables_needed(e) + e.Call(f, arg) -> + list.append(do_variables_needed(f), do_variables_needed(arg)) + e.Let(_p, value, then) -> + list.append(do_variables_needed(value), do_variables_needed(then)) + // TODO pattern + e.Function(_p, body) -> do_variables_needed(body) + e.Case(value, branches) -> + list.fold( + branches, + do_variables_needed(value), + fn(acc, b) { + // TODO remove pattern + let #(_, _, then) = b + list.append(acc, do_variables_needed(then)) + }, + ) + // TODO these shouldn't add anything new or we will change them to be eval'd functions + e.Provider(_, _, _) -> [] + } + // _ -> todo +} + +fn by_type(tree, scope) { + assert Ok(typer) = do_type(tree, scope, typer.init()) + t.resolve(scope, typer.substitutions) +} + +fn do_type(tree, scope, state) -> Result(typer.Typer, _) { + let #(_, exp) = tree + case exp { + e.Variable(label) -> { + let #(row, state) = typer.next_unbound(state) + let #(type_, state) = typer.next_unbound(state) + typer.unify( + t.Record([#(label, t.Unbound(type_))], Some(row)), + scope, + state, + ) + } + e.Let(_, value, then) -> do_type(value, scope, state) + e.Access(term, key) -> + // This is on the type of the term does nothing to scope. I think need to run through checking the typer + todo + _ -> { + io.debug(exp) + todo + } + } +} + +pub fn slim_records_test() -> Nil { + // e.let_(p.Record([]), e.record([]), e.hole()) + + let source = e.variable("x") + assert _ = + by_type(source, t.Unbound(-1)) + |> io.debug + + let source = + e.let_( + p.Variable(""), + e.access(e.variable("x"), "foo"), + e.let_(p.Variable(""), e.access(e.variable("x"), "foo"), e.hole()), + ) + + assert _ = + by_type(source, t.Unbound(-1)) + |> io.debug + todo("slim") +} + +pub fn capturing_all_type_variables_test() { + // If there is a function from string -> string could be a -> b a -> string b -> string + // how do providers work over this + let source = e.variable("x") + assert ["x"] = variables_needed(source) + + let source = e.binary("hello") + assert [] = variables_needed(source) + + let source = e.call(e.variable("x"), e.variable("y")) + assert ["x", "y"] = variables_needed(source) + + let source = e.tuple_([e.variable("x"), e.variable("y")]) + assert ["x", "y"] = variables_needed(source) + + let source = e.access(e.variable("x"), "y") + assert ["x"] = variables_needed(source) + + let source = e.tagged("Y", e.variable("x")) + assert ["x"] = variables_needed(source) + // todo("test") +}