idris-lang / Idris2

A purely functional programming language with first class types
https://idris-lang.org/
Other
2.53k stars 376 forks source link

Generate only es6 #3400

Open srghma opened 4 weeks ago

srghma commented 4 weeks ago

Summary

Let's allow to generate only es6 code

Motivation

The purescript team moved from common cjs to es6, now purescript can generate only es6. And then they use tools like esbuild or vite to transform es6 to whatever

Why? Because require is not pure, but import export is, thus es6 allows to remove dead code

srghma commented 2 weeks ago

The proposal

Lets add optional field in node:lambda:....:code

this field can be any of

// will generate `import defaultExport_xxx from "module-name"`
// 
// in lambda all mentions of `defaultExport` will be
// `code.replace(/\bdefaultExport\b/g, "defaultExport_xxx")` replaced with defaultExport_xxx 
// (so, be careful to not write `let defaultExport = ...`, though it will not lead to any errors)
import defaultExport from "module-name";

import * as name from "module-name";  // will be replaced with variable name_xxx
import { export1 } from "module-name";  // will be replaced with variable export1_xxx
import { export1 as alias1 } from "module-name"; // will be replaced with variable alias1_xxx
import { default as alias } from "module-name"; // will be replaced with variable alias_xxx
import { export1, export2 } from "module-name"; // will be replaced with variables export1_xxx and export2_xxx
import { export1, export2 as alias2, /* … */ } from "module-name"; // will be replaced with variables export1_xxx and alias2_xxx
import { "string name" as alias } from "module-name"; // will be replaced with variable alias_xxx
import defaultExport, { export1, /* … */ } from "module-name"; // will be replaced with variables export1_xxx
import defaultExport, * as name from "module-name"; // will be replaced with variable name_xxx
// import "module-name"; disallow, should be only in support.js?
import styles from "https://example.com/styles.css" with { type: "css" }; // will be replaced with variable styles_xxx

to import multiple - separate them with ;

Examples

Right now we write

%foreign "C:idris2_readBufferData, libidris2_support, idris_file.h"
         "RefC:readBufferData"
         "node:lambda:(f,b,l,m) => require('fs').readSync(f.fd,b,l,m)"
prim__readBufferData : FilePtr -> Buffer -> Int -> Int -> PrimIO Int

After

%foreign "C:idris2_readBufferData, libidris2_support, idris_file.h"
         "RefC:readBufferData"
         "node:lambda:import { readSync } from 'node:fs':(f,b,l,m) => readSync(f.fd,b,l,m)"
prim__readBufferData : FilePtr -> Buffer -> Int -> Int -> PrimIO Int

Proposal 2

lambdas should not have imports at all?

Be like purescript? Write

module My.Module

%foreign "C:idris2_readBufferData, libidris2_support, idris_file.h"
         "RefC:readBufferData"
         "node:import:readBufferData"
prim__readBufferData : FilePtr -> Buffer -> Int -> Int -> PrimIO Int

and in ./support/My/Module.js

import fs from 'node:fs'

export readBufferData = (f,b,l,m) => fs.readSync(f.fd,b,l,m)

so idris --build $output will generate output dir with

./output/My.Module/index.js -- generated idris code
./output/My.Module/index.js.map -- maybe add? 🤨
./output/My.Module/support.js -- this is just `mv ./support/My/Module.js ./output/My.Module/support.js` (actually, why even do mv?)

./output/cache-db.json -- { "MyModule": { "path-to-module" ... }

./output/entrypoint.js -- contains `import { main } from './output/Main'; main()' IF type == executable

2024-10-27-02pm-50-04-screenshot 2024-10-27_14-49-22 2024-10-27_14-49-30

Conclusion

Proposal 2 allows more optimizations? faster code generation?