mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-29 16:02:51 -04:00
start packaging
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
.snowpack
|
||||
build
|
||||
node_modules
|
||||
.DS_Store
|
||||
.parcel-cache
|
||||
oldtunes.ts
|
||||
@@ -1,22 +0,0 @@
|
||||
# Strudel REPL
|
||||
|
||||
## Default Snowpack Readme
|
||||
|
||||
> ✨ Bootstrapped with Create Snowpack App (CSA).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
### npm start
|
||||
|
||||
Runs the app in the development mode.
|
||||
Open http://localhost:8080 to view it in the browser.
|
||||
|
||||
The page will reload if you make edits.
|
||||
You will also see any lint errors in the console.
|
||||
|
||||
### npm run build
|
||||
|
||||
Builds a static copy of your site to the `docs/` folder.
|
||||
Your app is ready to be deployed!
|
||||
|
||||
**For the best production performance:** Add a build bundler plugin like "@snowpack/plugin-webpack" to your `snowpack.config.mjs` config file.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,211 +0,0 @@
|
||||
// Some terminology:
|
||||
// a sequence = a serie of elements placed between quotes
|
||||
// a stack = a serie of vertically aligned slices sharing the same overall length
|
||||
// a slice = a serie of horizontally aligned elements
|
||||
|
||||
|
||||
{
|
||||
var PatternStub = function(source, alignment)
|
||||
{
|
||||
this.type_ = "pattern";
|
||||
this.arguments_ = { alignment : alignment};
|
||||
this.source_ = source;
|
||||
}
|
||||
|
||||
var OperatorStub = function(name, args, source)
|
||||
{
|
||||
this.type_ = name;
|
||||
this.arguments_ = args;
|
||||
this.source_ = source;
|
||||
}
|
||||
|
||||
var ElementStub = function(source, options)
|
||||
{
|
||||
this.type_ = "element";
|
||||
this.source_ = source;
|
||||
this.options_ = options;
|
||||
this.location_ = location();
|
||||
}
|
||||
|
||||
var CommandStub = function(name, options)
|
||||
{
|
||||
this.type_ = "command";
|
||||
this.name_ = name;
|
||||
this.options_ = options;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
start = statement
|
||||
|
||||
// ----- Numbers -----
|
||||
|
||||
number "number"
|
||||
= minus? int frac? exp? { return parseFloat(text()); }
|
||||
|
||||
decimal_point
|
||||
= "."
|
||||
|
||||
digit1_9
|
||||
= [1-9]
|
||||
|
||||
e
|
||||
= [eE]
|
||||
|
||||
exp
|
||||
= e (minus / plus)? DIGIT+
|
||||
|
||||
frac
|
||||
= decimal_point DIGIT+
|
||||
|
||||
int
|
||||
= zero / (digit1_9 DIGIT*)
|
||||
|
||||
minus
|
||||
= "-"
|
||||
|
||||
plus
|
||||
= "+"
|
||||
|
||||
zero
|
||||
= "0"
|
||||
|
||||
DIGIT = [0-9]
|
||||
|
||||
// ------------------ delimiters ---------------------------
|
||||
|
||||
ws "whitespace" = [ \n\r\t]*
|
||||
comma = ws "," ws;
|
||||
quote = '"' / "'"
|
||||
|
||||
// ------------------ steps and cycles ---------------------------
|
||||
|
||||
// single step definition (e.g bd)
|
||||
step_char = [0-9a-zA-Z~] / "-" / "#" / "." / "^" / "_"
|
||||
step = ws chars:step_char+ ws { return chars.join("") }
|
||||
|
||||
// define a sub cycle e.g. [1 2, 3 [4]]
|
||||
sub_cycle = ws "[" ws s:stack ws "]" ws { return s}
|
||||
|
||||
// define a timeline e.g <1 3 [3 5]>. We simply defer to a stack and change the alignement
|
||||
timeline = ws "<" ws sc:single_cycle ws ">" ws
|
||||
{ sc.arguments_.alignment = "t"; return sc;}
|
||||
|
||||
// a slice is either a single step or a sub cycle
|
||||
slice = step / sub_cycle / timeline
|
||||
|
||||
// slice modifier affects the timing/size of a slice (e.g. [a b c]@3)
|
||||
// at this point, we assume we can represent them as regular sequence operators
|
||||
slice_modifier = slice_weight / slice_bjorklund / slice_slow / slice_fast / slice_fixed_step / slice_replicate
|
||||
|
||||
slice_weight = "@" a:number
|
||||
{ return { weight: a} }
|
||||
|
||||
slice_replicate = "!"a:number
|
||||
{ return { replicate: a } }
|
||||
|
||||
slice_bjorklund = "(" ws p:number ws comma ws s:number ws comma? ws r:number? ws ")"
|
||||
{ return { operator : { type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r || 0 } } } }
|
||||
|
||||
slice_slow = "/"a:number
|
||||
{ return { operator : { type_: "stretch", arguments_ :{ amount:a } } } }
|
||||
|
||||
slice_fast = "*"a:number
|
||||
{ return { operator : { type_: "stretch", arguments_ :{ amount:"1/"+a } } } }
|
||||
|
||||
slice_fixed_step = "%"a:number
|
||||
{ return { operator : { type_: "fixed-step", arguments_ :{ amount:a } } } }
|
||||
|
||||
// a slice with an modifier applied i.e [bd@4 sd@3]@2 hh]
|
||||
slice_with_modifier = s:slice o:slice_modifier?
|
||||
{ return new ElementStub(s, o);}
|
||||
|
||||
// a single cycle is a combination of one or more successive slices (as an array). If we
|
||||
// have only one element, we skip the array and return the element itself
|
||||
single_cycle = s:(slice_with_modifier)+
|
||||
{ return new PatternStub(s,"h"); }
|
||||
|
||||
// a stack is a serie of vertically aligned single cycles, separated by a comma
|
||||
// if the stack contains only one element, we don't create a stack but return the
|
||||
// underlying element
|
||||
stack = c:single_cycle cs:(comma v:single_cycle { return v})*
|
||||
{ if (cs.length == 0 && c instanceof Object) { return c;} else { cs.unshift(c); return new PatternStub(cs,"v");} }
|
||||
|
||||
// a sequence is a quoted stack
|
||||
sequence = ws quote s:stack quote
|
||||
{ return s; }
|
||||
|
||||
// ------------------ operators ---------------------------
|
||||
|
||||
operator = scale / slow / fast / target / bjorklund / struct / rotR / rotL
|
||||
|
||||
struct = "struct" ws s:sequence_or_operator
|
||||
{ return { name: "struct", args: { sequence:s }}}
|
||||
|
||||
target = "target" ws quote s:step quote
|
||||
{ return { name: "target", args : { name:s}}}
|
||||
|
||||
bjorklund = "euclid" ws p:int ws s:int ws r:int?
|
||||
{ return { name: "bjorklund", args :{ pulse: parseInt(p), step:parseInt(s) }}}
|
||||
|
||||
slow = "slow" ws a:number
|
||||
{ return { name: "stretch", args :{ amount: a}}}
|
||||
|
||||
rotL = "rotL" ws a:number
|
||||
{ return { name: "shift", args :{ amount: "-"+a}}}
|
||||
|
||||
rotR = "rotR" ws a:number
|
||||
{ return { name: "shift", args :{ amount: a}}}
|
||||
|
||||
fast = "fast" ws a:number
|
||||
{ return { name: "stretch", args :{ amount: "1/"+a}}}
|
||||
|
||||
scale = "scale" ws quote s:(step_char)+ quote
|
||||
{ return { name: "scale", args :{ scale: s.join("")}}}
|
||||
|
||||
comment = '//' p:([^\n]*)
|
||||
|
||||
// ---------------- grouping --------------------------------
|
||||
|
||||
group_operator = cat
|
||||
|
||||
// cat is another form of timeline
|
||||
cat = "cat" ws "[" ws s:sequence_or_operator ss:(comma v:sequence_or_operator { return v})* ws "]"
|
||||
{ ss.unshift(s); return new PatternStub(ss,"t"); }
|
||||
|
||||
// ------------------ high level sequence ---------------------------
|
||||
|
||||
sequence_or_group =
|
||||
group_operator /
|
||||
sequence
|
||||
|
||||
sequence_or_operator =
|
||||
sg:sequence_or_group ws (comment)*
|
||||
{return sg}
|
||||
/ o:operator ws "$" ws soc:sequence_or_operator
|
||||
{ return new OperatorStub(o.name,o.args,soc)}
|
||||
|
||||
sequ_or_operator_or_comment =
|
||||
sc: sequence_or_operator
|
||||
{ return sc }
|
||||
/ comment
|
||||
|
||||
sequence_definition = s:sequ_or_operator_or_comment
|
||||
|
||||
// ---------------------- statements ----------------------------
|
||||
|
||||
command = ws c:(setcps / setbpm / hush) ws
|
||||
{ return c }
|
||||
|
||||
setcps = "setcps" ws v:number
|
||||
{ return new CommandStub("setcps", { value: v})}
|
||||
|
||||
setbpm = "setbpm" ws v:number
|
||||
{ return new CommandStub("setcps", { value: (v/120/2)})}
|
||||
|
||||
hush = "hush"
|
||||
{ return new CommandStub("hush")}
|
||||
|
||||
// ---------------------- statements ----------------------------
|
||||
|
||||
statement = sequence_definition / command
|
||||
Generated
-21647
File diff suppressed because it is too large
Load Diff
@@ -1,61 +0,0 @@
|
||||
{
|
||||
"scripts": {
|
||||
"start": "snowpack dev --polyfill-node",
|
||||
"build": "snowpack build --polyfill-node && cp ./public/.nojekyll ../docs && npm run build-tutorial",
|
||||
"static": "npx serve ../docs",
|
||||
"test": "web-test-runner \"src/**/*.test.tsx\"",
|
||||
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"",
|
||||
"lint": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\"",
|
||||
"peggy": "peggy -o krill-parser.js --format es ./krill.pegjs",
|
||||
"tutorial": "parcel src/tutorial/index.html --no-cache",
|
||||
"build-tutorial": "parcel build src/tutorial/index.html --dist-dir ../docs/tutorial --public-url /tutorial --no-optimize --no-scope-hoist --no-cache"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tonaljs/tonal": "^4.6.5",
|
||||
"@tonejs/piano": "^0.2.1",
|
||||
"bjork": "^0.0.1",
|
||||
"chord-voicings": "^0.0.1",
|
||||
"codemirror": "^5.65.1",
|
||||
"estraverse": "^5.3.0",
|
||||
"events": "^3.3.0",
|
||||
"multimap": "^1.1.0",
|
||||
"ramda": "^0.28.0",
|
||||
"react": "^17.0.2",
|
||||
"react-codemirror2": "^7.2.1",
|
||||
"react-dom": "^17.0.2",
|
||||
"shift-ast": "^6.1.0",
|
||||
"shift-codegen": "^7.0.3",
|
||||
"shift-regexp-acceptor": "^2.0.3",
|
||||
"shift-spec": "^2018.0.2",
|
||||
"tone": "^14.7.77",
|
||||
"tune.js": "^1.0.1",
|
||||
"webmidi": "^2.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"@parcel/transformer-mdx": "^2.3.1",
|
||||
"@snowpack/plugin-dotenv": "^2.1.0",
|
||||
"@snowpack/plugin-postcss": "^1.4.3",
|
||||
"@snowpack/plugin-react-refresh": "^2.5.0",
|
||||
"@snowpack/plugin-typescript": "^1.2.1",
|
||||
"@snowpack/web-test-runner-plugin": "^0.2.2",
|
||||
"@tailwindcss/forms": "^0.4.0",
|
||||
"@tailwindcss/typography": "^0.5.2",
|
||||
"@testing-library/react": "^11.2.6",
|
||||
"@types/chai": "^4.2.17",
|
||||
"@types/mocha": "^8.2.2",
|
||||
"@types/react": "^17.0.4",
|
||||
"@types/react-dom": "^17.0.3",
|
||||
"@types/snowpack-env": "^2.3.3",
|
||||
"@web/test-runner": "^0.13.3",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"chai": "^4.3.4",
|
||||
"parcel": "^2.3.1",
|
||||
"peggy": "^1.2.0",
|
||||
"postcss": "^8.4.6",
|
||||
"prettier": "^2.2.1",
|
||||
"snowpack": "^3.3.7",
|
||||
"tailwindcss": "^3.0.18",
|
||||
"typescript": "^4.2.4"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
// postcss.config.js
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
// other plugins can go here, such as autoprefixer
|
||||
},
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
strudel.tidalcycles.org
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,31 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
background-color: #2a3236;
|
||||
}
|
||||
|
||||
.react-codemirror2,
|
||||
.CodeMirror {
|
||||
height: 100% !important;
|
||||
background-color: transparent !important;
|
||||
font-size: 15px;
|
||||
z-index:20
|
||||
}
|
||||
|
||||
.CodeMirror-line > span {
|
||||
background-color: #2a323699;
|
||||
}
|
||||
|
||||
.darken::before {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: block;
|
||||
background: black;
|
||||
opacity: 0.5;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
// this file can be used to livecode from the comfort of your editor.
|
||||
// just export a pattern from export default
|
||||
// enable hot mode by pressing "toggle hot mode" on the top right of the repl
|
||||
|
||||
import { mini, h } from '../src/parse';
|
||||
import { sequence, pure, reify, slowcat, fastcat, cat, stack, silence } from '../../strudel.mjs';
|
||||
import { gain, filter } from '../src/tone';
|
||||
|
||||
export default stack(
|
||||
sequence(
|
||||
mini(
|
||||
'e5 [b4 c5] d5 [c5 b4]',
|
||||
'a4 [a4 c5] e5 [d5 c5]',
|
||||
'b4 [~ c5] d5 e5',
|
||||
'c5 a4 a4 ~',
|
||||
'[~ d5] [~ f5] a5 [g5 f5]',
|
||||
'e5 [~ c5] e5 [d5 c5]',
|
||||
'b4 [b4 c5] d5 e5',
|
||||
'c5 a4 a4 ~'
|
||||
)
|
||||
.synth({
|
||||
oscillator: { type: 'sine' },
|
||||
envelope: { attack: 0.1 },
|
||||
})
|
||||
.rev()
|
||||
),
|
||||
sequence(
|
||||
mini(
|
||||
'e2 e3 e2 e3 e2 e3 e2 e3',
|
||||
'a2 a3 a2 a3 a2 a3 a2 a3',
|
||||
'g#2 g#3 g#2 g#3 e2 e3 e2 e3',
|
||||
'a2 a3 a2 a3 a2 a3 b1 c2',
|
||||
'd2 d3 d2 d3 d2 d3 d2 d3',
|
||||
'c2 c3 c2 c3 c2 c3 c2 c3',
|
||||
'b1 b2 b1 b2 e2 e3 e2 e3',
|
||||
'a1 a2 a1 a2 a1 a2 a1 a2'
|
||||
)
|
||||
.synth({
|
||||
oscillator: { type: 'sawtooth' },
|
||||
envelope: { attack: 0.1 },
|
||||
})
|
||||
.chain(gain(0.7), filter(2000))
|
||||
.rev()
|
||||
)
|
||||
).slow(16);
|
||||
@@ -1,16 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%/global.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="Strudel REPL" />
|
||||
<title>Strudel REPL</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<script type="module" src="%PUBLIC_URL%/dist/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,41 +0,0 @@
|
||||
/** @type {import("snowpack").SnowpackUserConfig } */
|
||||
export default {
|
||||
workspaceRoot: '..',
|
||||
mount: {
|
||||
public: { url: '/', static: false },
|
||||
src: { url: '/dist' },
|
||||
},
|
||||
plugins: [
|
||||
'@snowpack/plugin-postcss',
|
||||
'@snowpack/plugin-react-refresh',
|
||||
'@snowpack/plugin-dotenv',
|
||||
[
|
||||
'@snowpack/plugin-typescript',
|
||||
{
|
||||
/* Yarn PnP workaround: see https://www.npmjs.com/package/@snowpack/plugin-typescript */
|
||||
...(process.versions.pnp ? { tsc: 'yarn pnpify tsc' } : {}),
|
||||
},
|
||||
],
|
||||
],
|
||||
routes: [
|
||||
/* Enable an SPA Fallback in development: */
|
||||
// {"match": "routes", "src": ".*", "dest": "/index.html"},
|
||||
],
|
||||
exclude: ['**/node_modules/**/*', '**/tutorial/**/*'],
|
||||
optimize: {
|
||||
/* Example: Bundle your final build: */
|
||||
// "bundle": true,
|
||||
},
|
||||
packageOptions: {
|
||||
/* ... */
|
||||
knownEntrypoints: ['fraction.js', 'codemirror', 'shift-ast', 'ramda'],
|
||||
},
|
||||
devOptions: {
|
||||
tailwindConfig: './tailwind.config.js',
|
||||
},
|
||||
buildOptions: {
|
||||
/* ... */
|
||||
out: '../docs',
|
||||
baseUrl: '/',
|
||||
},
|
||||
};
|
||||
@@ -1,179 +0,0 @@
|
||||
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||
import CodeMirror, { markEvent, markParens } from './CodeMirror';
|
||||
import cx from './cx';
|
||||
import { evaluate } from './evaluate';
|
||||
import logo from './logo.svg';
|
||||
import { useWebMidi } from './midi';
|
||||
import playStatic from './static.mjs';
|
||||
import { defaultSynth } from './tone';
|
||||
import * as tunes from './tunes';
|
||||
import useRepl from './useRepl';
|
||||
|
||||
// TODO: use https://www.npmjs.com/package/@monaco-editor/react
|
||||
|
||||
const [_, codeParam] = window.location.href.split('#');
|
||||
let decoded;
|
||||
try {
|
||||
decoded = atob(decodeURIComponent(codeParam || ''));
|
||||
} catch (err) {
|
||||
console.warn('failed to decode', err);
|
||||
}
|
||||
|
||||
function getRandomTune() {
|
||||
const allTunes = Object.values(tunes);
|
||||
const randomItem = (arr: any[]) => arr[Math.floor(Math.random() * arr.length)];
|
||||
return randomItem(allTunes);
|
||||
}
|
||||
|
||||
const randomTune = getRandomTune();
|
||||
|
||||
function App() {
|
||||
const [editor, setEditor] = useState<any>();
|
||||
const { setCode, setPattern, error, code, cycle, dirty, log, togglePlay, activateCode, pattern, pushLog, pending } =
|
||||
useRepl({
|
||||
tune: decoded || randomTune,
|
||||
defaultSynth,
|
||||
onDraw: useCallback(markEvent(editor), [editor]),
|
||||
});
|
||||
const [uiHidden, setUiHidden] = useState(false);
|
||||
const logBox = useRef<any>();
|
||||
// scroll log box to bottom when log changes
|
||||
useLayoutEffect(() => {
|
||||
logBox.current.scrollTop = logBox.current?.scrollHeight;
|
||||
}, [log]);
|
||||
|
||||
// set active pattern on ctrl+enter
|
||||
useLayoutEffect(() => {
|
||||
// TODO: make sure this is only fired when editor has focus
|
||||
const handleKeyPress = async (e: any) => {
|
||||
if (e.ctrlKey || e.altKey) {
|
||||
switch (e.code) {
|
||||
case 'Enter':
|
||||
await activateCode();
|
||||
break;
|
||||
case 'Period':
|
||||
cycle.stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', handleKeyPress);
|
||||
return () => window.removeEventListener('keydown', handleKeyPress);
|
||||
}, [pattern, code]);
|
||||
|
||||
useWebMidi({
|
||||
ready: useCallback(({ outputs }) => {
|
||||
pushLog(`WebMidi ready! Just add .midi(${outputs.map((o) => `'${o.name}'`).join(' | ')}) to the pattern. `);
|
||||
}, []),
|
||||
connected: useCallback(({ outputs }) => {
|
||||
pushLog(`Midi device connected! Available: ${outputs.map((o) => `'${o.name}'`).join(', ')}`);
|
||||
}, []),
|
||||
disconnected: useCallback(({ outputs }) => {
|
||||
pushLog(`Midi device disconnected! Available: ${outputs.map((o) => `'${o.name}'`).join(', ')}`);
|
||||
}, []),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col">
|
||||
<header
|
||||
id="header"
|
||||
className={cx(
|
||||
'flex-none w-full h-14 px-2 flex border-b border-gray-200 justify-between z-[10]',
|
||||
uiHidden ? 'bg-transparent text-white' : 'bg-white',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<img src={logo} className="Tidal-logo w-12 h-12" alt="logo" />
|
||||
<h1 className="text-2xl">Strudel REPL</h1>
|
||||
</div>
|
||||
<div className="flex space-x-4">
|
||||
<button onClick={() => togglePlay()}>
|
||||
{!pending ? (
|
||||
<span className="flex items-center w-16">
|
||||
{cycle.started ? (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
{cycle.started ? 'pause' : 'play'}
|
||||
</span>
|
||||
) : (
|
||||
<>loading...</>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
onClick={async () => {
|
||||
const _code = getRandomTune();
|
||||
console.log('tune', _code); // uncomment this to debug when random code fails
|
||||
setCode(_code);
|
||||
const parsed = await evaluate(_code);
|
||||
setPattern(parsed.pattern);
|
||||
}}
|
||||
>
|
||||
🎲 random
|
||||
</button>
|
||||
<button>
|
||||
<a href="./tutorial">📚 tutorial</a>
|
||||
</button>
|
||||
<button onClick={() => setUiHidden((c) => !c)}>👀 {uiHidden ? 'show ui' : 'hide ui'}</button>
|
||||
</div>
|
||||
</header>
|
||||
<section className="grow flex flex-col text-gray-100">
|
||||
<div className="grow relative" id="code">
|
||||
<div
|
||||
className={cx(
|
||||
'h-full transition-opacity',
|
||||
error ? 'focus:ring-red-500' : 'focus:ring-slate-800',
|
||||
uiHidden ? 'opacity-0' : 'opacity-100',
|
||||
)}
|
||||
>
|
||||
<CodeMirror
|
||||
value={code}
|
||||
editorDidMount={setEditor}
|
||||
options={{
|
||||
mode: 'javascript',
|
||||
theme: 'material',
|
||||
lineNumbers: false,
|
||||
styleSelectedText: true,
|
||||
cursorBlinkRate: 0,
|
||||
}}
|
||||
onCursor={markParens}
|
||||
onChange={(_: any, __: any, value: any) => setCode(value)}
|
||||
/>
|
||||
<span className="p-4 absolute top-0 right-0 text-xs whitespace-pre text-right pointer-events-none">
|
||||
{!cycle.started ? `press ctrl+enter to play\n` : dirty ? `ctrl+enter to update\n` : 'no changes\n'}
|
||||
</span>
|
||||
</div>
|
||||
{error && (
|
||||
<div className={cx('absolute right-2 bottom-2 px-2', 'text-red-500')}>
|
||||
{error?.message || 'unknown error'}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<textarea
|
||||
className="z-[10] h-16 border-0 text-xs bg-[transparent] border-t border-slate-600 resize-none"
|
||||
value={log}
|
||||
readOnly
|
||||
ref={logBox}
|
||||
style={{ fontFamily: 'monospace' }}
|
||||
/>
|
||||
</section>
|
||||
<button className="fixed right-4 bottom-2 z-[11]" onClick={() => playStatic(code)}>
|
||||
static
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -1,121 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Controlled as CodeMirror2 } from 'react-codemirror2';
|
||||
import 'codemirror/mode/javascript/javascript.js';
|
||||
import 'codemirror/mode/pegjs/pegjs.js';
|
||||
// import 'codemirror/theme/material.css';
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
import 'codemirror/theme/material.css';
|
||||
|
||||
export default function CodeMirror({ value, onChange, onCursor, options, editorDidMount }: any) {
|
||||
options = options || {
|
||||
mode: 'javascript',
|
||||
theme: 'material',
|
||||
lineNumbers: true,
|
||||
styleSelectedText: true,
|
||||
cursorBlinkRate: 500,
|
||||
};
|
||||
return (
|
||||
<CodeMirror2
|
||||
value={value}
|
||||
options={options}
|
||||
onBeforeChange={onChange}
|
||||
editorDidMount={editorDidMount}
|
||||
onCursor={(editor, data) => onCursor?.(editor, data)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const markEvent = (editor) => (time, event) => {
|
||||
const locs = event.context.locations;
|
||||
if (!locs || !editor) {
|
||||
return;
|
||||
}
|
||||
const col = event.context?.color || '#FFCA28';
|
||||
// mark active event
|
||||
const marks = locs.map(({ start, end }) =>
|
||||
editor.getDoc().markText(
|
||||
{ line: start.line - 1, ch: start.column },
|
||||
{ line: end.line - 1, ch: end.column },
|
||||
//{ css: 'background-color: #FFCA28; color: black' } // background-color is now used by parent marking
|
||||
{ css: 'outline: 1px solid ' + col + '; box-sizing:border-box' },
|
||||
//{ css: `background-color: ${col};border-radius:5px` },
|
||||
),
|
||||
);
|
||||
//Tone.Transport.schedule(() => { // problem: this can be cleared by scheduler...
|
||||
setTimeout(() => {
|
||||
marks.forEach((mark) => mark.clear());
|
||||
// }, '+' + event.duration * 0.5);
|
||||
}, event.duration /* * 0.9 */ * 1000);
|
||||
};
|
||||
|
||||
let parenMark;
|
||||
export const markParens = (editor, data) => {
|
||||
const v = editor.getDoc().getValue();
|
||||
const marked = getCurrentParenArea(v, data);
|
||||
parenMark?.clear();
|
||||
parenMark = editor.getDoc().markText(...marked, { css: 'background-color: #00007720' }); //
|
||||
};
|
||||
|
||||
// returns { line, ch } from absolute character offset
|
||||
export function offsetToPosition(offset, code) {
|
||||
const lines = code.split('\n');
|
||||
let line = 0;
|
||||
let ch = 0;
|
||||
for (let i = 0; i < offset; i++) {
|
||||
if (ch === lines[line].length) {
|
||||
line++;
|
||||
ch = 0;
|
||||
} else {
|
||||
ch++;
|
||||
}
|
||||
}
|
||||
return { line, ch };
|
||||
}
|
||||
|
||||
// returns absolute character offset from { line, ch }
|
||||
export function positionToOffset(position, code) {
|
||||
const lines = code.split('\n');
|
||||
let offset = 0;
|
||||
for (let i = 0; i < position.line; i++) {
|
||||
offset += lines[i].length + 1;
|
||||
}
|
||||
offset += position.ch;
|
||||
return offset;
|
||||
}
|
||||
|
||||
// given code and caret position, the functions returns the indices of the parens we are in
|
||||
export function getCurrentParenArea(code, caretPosition) {
|
||||
const caret = positionToOffset(caretPosition, code);
|
||||
let open, i, begin, end;
|
||||
// walk left
|
||||
i = caret;
|
||||
open = 0;
|
||||
while (i > 0) {
|
||||
if (code[i - 1] === '(') {
|
||||
open--;
|
||||
} else if (code[i - 1] === ')') {
|
||||
open++;
|
||||
}
|
||||
if (open === -1) {
|
||||
break;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
begin = i;
|
||||
// walk right
|
||||
i = caret;
|
||||
open = 0;
|
||||
while (i < code.length) {
|
||||
if (code[i] === '(') {
|
||||
open--;
|
||||
} else if (code[i] === ')') {
|
||||
open++;
|
||||
}
|
||||
if (open === 1) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
end = i;
|
||||
return [begin, end].map((o) => offsetToPosition(o, code));
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function cx(...classes: Array<string | undefined>) {
|
||||
return classes.filter(Boolean).join(' ');
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import * as Tone from 'tone';
|
||||
import { Pattern } from '../../strudel.mjs';
|
||||
|
||||
export const getDrawContext = (id = 'test-canvas') => {
|
||||
let canvas = document.querySelector('#' + id);
|
||||
if (!canvas) {
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.id = id;
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
canvas.style = 'pointer-events:none;width:100%;height:100%;position:fixed;top:0;left:0;z-index:5';
|
||||
document.body.prepend(canvas);
|
||||
}
|
||||
return canvas.getContext('2d');
|
||||
};
|
||||
|
||||
Pattern.prototype.draw = function (callback, cycleSpan, lookaheadCycles = 1) {
|
||||
if (window.strudelAnimation) {
|
||||
cancelAnimationFrame(window.strudelAnimation);
|
||||
}
|
||||
const ctx = getDrawContext();
|
||||
let cycle,
|
||||
events = [];
|
||||
const animate = (time) => {
|
||||
const t = Tone.getTransport().seconds;
|
||||
if (cycleSpan) {
|
||||
const currentCycle = Math.floor(t / cycleSpan);
|
||||
if (cycle !== currentCycle) {
|
||||
cycle = currentCycle;
|
||||
const begin = currentCycle * cycleSpan;
|
||||
const end = (currentCycle + lookaheadCycles) * cycleSpan;
|
||||
events = this._asNumber(true) // true = silent error
|
||||
.query(new State(new TimeSpan(begin, end)))
|
||||
.filter((event) => event.part.begin.equals(event.whole.begin));
|
||||
}
|
||||
}
|
||||
callback(ctx, events, t, cycleSpan, time);
|
||||
window.strudelAnimation = requestAnimationFrame(animate);
|
||||
};
|
||||
requestAnimationFrame(animate);
|
||||
return this;
|
||||
};
|
||||
|
||||
export const cleanup = () => {
|
||||
const ctx = getDrawContext();
|
||||
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
|
||||
if (window.strudelAnimation) {
|
||||
cancelAnimationFrame(window.strudelAnimation);
|
||||
}
|
||||
if (window.strudelScheduler) {
|
||||
clearInterval(window.strudelScheduler);
|
||||
}
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
import { Pattern, timeCat } from '../../strudel.mjs';
|
||||
import bjork from 'bjork';
|
||||
import { rotate } from '../../util.mjs';
|
||||
import Fraction from '../../fraction.mjs';
|
||||
|
||||
const euclid = (pulses, steps, rotation = 0) => {
|
||||
const b = bjork(steps, pulses);
|
||||
if (rotation) {
|
||||
return rotate(b, -rotation);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
|
||||
Pattern.prototype.euclid = function (pulses, steps, rotation = 0) {
|
||||
return this.struct(euclid(pulses, steps, rotation));
|
||||
};
|
||||
|
||||
Pattern.prototype.euclidLegato = function (pulses, steps, rotation = 0) {
|
||||
const bin_pat = euclid(pulses, steps, rotation);
|
||||
const firstOne = bin_pat.indexOf(1);
|
||||
const gapless = rotate(bin_pat, firstOne)
|
||||
.join('')
|
||||
.split('1')
|
||||
.slice(1)
|
||||
.map((s) => [s.length + 1, true]);
|
||||
return this.struct(timeCat(...gapless)).late(Fraction(firstOne).div(steps));
|
||||
};
|
||||
|
||||
export default euclid;
|
||||
@@ -1,56 +0,0 @@
|
||||
import * as strudel from '../../strudel.mjs';
|
||||
import './tone';
|
||||
import './midi';
|
||||
import './voicings';
|
||||
import './tonal.mjs';
|
||||
import './xen.mjs';
|
||||
import './tune.mjs';
|
||||
import './euclid.mjs';
|
||||
import euclid from './euclid.mjs';
|
||||
import './pianoroll.mjs';
|
||||
import './draw.mjs';
|
||||
import * as uiHelpers from './ui.mjs';
|
||||
import * as drawHelpers from './draw.mjs';
|
||||
import gist from './gist.js';
|
||||
import shapeshifter from './shapeshifter';
|
||||
import { mini } from './parse';
|
||||
import * as Tone from 'tone';
|
||||
import * as toneHelpers from './tone';
|
||||
import * as voicingHelpers from './voicings';
|
||||
|
||||
// this will add all methods from definedMethod to strudel + connect all the partial application stuff
|
||||
const bootstrapped: any = { ...strudel, ...strudel.Pattern.prototype.bootstrap() };
|
||||
// console.log('bootstrapped',bootstrapped.transpose(2).transpose);
|
||||
|
||||
function hackLiteral(literal, names, func) {
|
||||
names.forEach((name) => {
|
||||
Object.defineProperty(literal.prototype, name, {
|
||||
get: function () {
|
||||
return func(String(this));
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// with this, you can do 'c2 [eb2 g2]'.mini.fast(2) or 'c2 [eb2 g2]'.m.fast(2),
|
||||
hackLiteral(String, ['mini', 'm'], bootstrapped.mini); // comment out this line if you panic
|
||||
hackLiteral(String, ['pure', 'p'], bootstrapped.pure); // comment out this line if you panic
|
||||
|
||||
// this will add everything to global scope, which is accessed by eval
|
||||
Object.assign(globalThis, Tone, bootstrapped, toneHelpers, voicingHelpers, drawHelpers, uiHelpers, {
|
||||
gist,
|
||||
euclid,
|
||||
mini,
|
||||
});
|
||||
|
||||
export const evaluate: any = async (code: string) => {
|
||||
const shapeshifted = shapeshifter(code); // transform syntactically correct js code to semantically usable code
|
||||
drawHelpers.cleanup();
|
||||
uiHelpers.cleanup();
|
||||
let evaluated = await eval(shapeshifted);
|
||||
if (evaluated?.constructor?.name !== 'Pattern') {
|
||||
const message = `got "${typeof evaluated}" instead of pattern`;
|
||||
throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.'));
|
||||
}
|
||||
return { mode: 'javascript', pattern: evaluated };
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
// this is a shortcut to eval code from a gist
|
||||
// why? to be able to shorten strudel code + e.g. be able to change instruments after links have been generated
|
||||
export default (route) =>
|
||||
fetch(`https://gist.githubusercontent.com/${route}?cachebust=${Date.now()}`)
|
||||
.then((res) => res.text())
|
||||
.then((code) => eval(code));
|
||||
@@ -1,16 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
||||
// Hot Module Replacement (HMR) - Remove this snippet to remove HMR.
|
||||
// Learn more: https://snowpack.dev/concepts/hot-module-replacement
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept();
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 42 KiB |
@@ -1,108 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { isNote } from 'tone';
|
||||
import _WebMidi from 'webmidi';
|
||||
import { Pattern as _Pattern } from '../../strudel.mjs';
|
||||
import * as Tone from 'tone';
|
||||
|
||||
const WebMidi: any = _WebMidi;
|
||||
const Pattern = _Pattern as any;
|
||||
|
||||
export default function enableWebMidi() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (WebMidi.enabled) {
|
||||
// if already enabled, just resolve WebMidi
|
||||
resolve(WebMidi);
|
||||
return;
|
||||
}
|
||||
WebMidi.enable((err: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(WebMidi);
|
||||
});
|
||||
});
|
||||
}
|
||||
const outputByName = (name: string) => WebMidi.getOutputByName(name);
|
||||
|
||||
Pattern.prototype.midi = function (output: string | number, channel = 1) {
|
||||
if (output?.constructor?.name === 'Pattern') {
|
||||
throw new Error(
|
||||
`.midi does not accept Pattern input. Make sure to pass device name with single quotes. Example: .midi('${
|
||||
WebMidi.outputs?.[0]?.name || 'IAC Driver Bus 1'
|
||||
}')`
|
||||
);
|
||||
}
|
||||
return this._withEvent((event: any) => {
|
||||
const onTrigger = (time: number, event: any) => {
|
||||
let note = event.value;
|
||||
const velocity = event.context?.velocity ?? 0.9;
|
||||
if (!isNote(note)) {
|
||||
throw new Error('not a note: ' + note);
|
||||
}
|
||||
if (!WebMidi.enabled) {
|
||||
throw new Error(`🎹 WebMidi is not enabled. Supported Browsers: https://caniuse.com/?search=webmidi`);
|
||||
}
|
||||
if (!WebMidi.outputs.length) {
|
||||
throw new Error(`🔌 No MIDI devices found. Connect a device or enable IAC Driver.`);
|
||||
}
|
||||
let device;
|
||||
if (typeof output === 'number') {
|
||||
device = WebMidi.outputs[output];
|
||||
} else if (typeof output === 'string') {
|
||||
device = outputByName(output);
|
||||
} else {
|
||||
device = WebMidi.outputs[0];
|
||||
}
|
||||
if (!device) {
|
||||
throw new Error(
|
||||
`🔌 MIDI device '${output ? output : ''}' not found. Use one of ${WebMidi.outputs
|
||||
.map((o: any) => `'${o.name}'`)
|
||||
.join(' | ')}`
|
||||
);
|
||||
}
|
||||
// console.log('midi', value, output);
|
||||
const timingOffset = WebMidi.time - Tone.context.currentTime * 1000;
|
||||
time = time * 1000 + timingOffset;
|
||||
// const inMs = '+' + (time - Tone.context.currentTime) * 1000;
|
||||
// await enableWebMidi()
|
||||
device.playNote(note, channel, {
|
||||
time,
|
||||
duration: event.duration * 1000 - 5,
|
||||
velocity,
|
||||
});
|
||||
};
|
||||
return event.setContext({ ...event.context, onTrigger });
|
||||
});
|
||||
};
|
||||
|
||||
export function useWebMidi(props?: any) {
|
||||
const { ready, connected, disconnected } = props;
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [outputs, setOutputs] = useState<any[]>(WebMidi?.outputs || []);
|
||||
useEffect(() => {
|
||||
enableWebMidi()
|
||||
.then(() => {
|
||||
// Reacting when a new device becomes available
|
||||
WebMidi.addListener('connected', (e: any) => {
|
||||
setOutputs([...WebMidi.outputs]);
|
||||
connected?.(WebMidi, e);
|
||||
});
|
||||
// Reacting when a device becomes unavailable
|
||||
WebMidi.addListener('disconnected', (e: any) => {
|
||||
setOutputs([...WebMidi.outputs]);
|
||||
disconnected?.(WebMidi, e);
|
||||
});
|
||||
ready?.(WebMidi);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
if (err) {
|
||||
//throw new Error("Web Midi could not be enabled...");
|
||||
console.warn('Web Midi could not be enabled..');
|
||||
return;
|
||||
}
|
||||
});
|
||||
}, [ready, connected, disconnected, outputs]);
|
||||
const outputByName = (name: string) => WebMidi.getOutputByName(name);
|
||||
return { loading, outputs, outputByName };
|
||||
}
|
||||
Vendored
-18
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
TODO:
|
||||
export interface Arguments {
|
||||
alignment: string;
|
||||
}
|
||||
|
||||
export interface ElementStub {
|
||||
type_: string;
|
||||
source_: string;
|
||||
options_?: any;
|
||||
}
|
||||
|
||||
export interface PatternStub {
|
||||
type_: string; // pattern
|
||||
arguments_: Arguments;
|
||||
source_: ElementStub[];
|
||||
}
|
||||
*/
|
||||
@@ -1,176 +0,0 @@
|
||||
import * as krill from '../krill-parser';
|
||||
import * as strudel from '../../strudel.mjs';
|
||||
import { Scale, Note, Interval } from '@tonaljs/tonal';
|
||||
import { addMiniLocations } from './shapeshifter';
|
||||
|
||||
const { pure, Pattern, Fraction, stack, slowcat, sequence, timeCat, silence } = strudel;
|
||||
|
||||
const applyOptions = (parent: any) => (pat: any, i: number) => {
|
||||
const ast = parent.source_[i];
|
||||
const options = ast.options_;
|
||||
const operator = options?.operator;
|
||||
if (operator) {
|
||||
switch (operator.type_) {
|
||||
case 'stretch':
|
||||
const speed = Fraction(operator.arguments_.amount).inverse();
|
||||
return reify(pat).fast(speed);
|
||||
case 'bjorklund':
|
||||
return pat.euclid(operator.arguments_.pulse, operator.arguments_.step, operator.arguments_.rotation);
|
||||
// TODO: case 'fixed-step': "%"
|
||||
}
|
||||
console.warn(`operator "${operator.type_}" not implemented`);
|
||||
}
|
||||
if (options?.weight) {
|
||||
// weight is handled by parent
|
||||
return pat;
|
||||
}
|
||||
// TODO: bjorklund e.g. "c3(5,8)"
|
||||
const unimplemented = Object.keys(options || {}).filter((key) => key !== 'operator');
|
||||
if (unimplemented.length) {
|
||||
console.warn(
|
||||
`option${unimplemented.length > 1 ? 's' : ''} ${unimplemented.map((o) => `"${o}"`).join(', ')} not implemented`,
|
||||
);
|
||||
}
|
||||
return pat;
|
||||
};
|
||||
|
||||
function resolveReplications(ast) {
|
||||
// the general idea here: x!3 = [x*3]@3
|
||||
// could this be made easier?!
|
||||
ast.source_ = ast.source_.map((child) => {
|
||||
const { replicate, ...options } = child.options_ || {};
|
||||
if (replicate) {
|
||||
return {
|
||||
...child,
|
||||
options_: { ...options, weight: replicate },
|
||||
source_: {
|
||||
type_: 'pattern',
|
||||
arguments_: {
|
||||
alignment: 'h',
|
||||
},
|
||||
source_: [
|
||||
{
|
||||
type_: 'element',
|
||||
source_: child.source_,
|
||||
location_: child.location_,
|
||||
options_: {
|
||||
operator: {
|
||||
type_: 'stretch',
|
||||
arguments_: { amount: Fraction(replicate).inverse().toString() },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
return child;
|
||||
});
|
||||
}
|
||||
|
||||
export function patternifyAST(ast: any): any {
|
||||
switch (ast.type_) {
|
||||
case 'pattern':
|
||||
resolveReplications(ast);
|
||||
const children = ast.source_.map(patternifyAST).map(applyOptions(ast));
|
||||
const alignment = ast.arguments_.alignment;
|
||||
if (alignment === 'v') {
|
||||
return stack(...children);
|
||||
}
|
||||
const weightedChildren = ast.source_.some((child) => !!child.options_?.weight);
|
||||
if (!weightedChildren && alignment === 't') {
|
||||
return slowcat(...children);
|
||||
}
|
||||
if (weightedChildren) {
|
||||
const pat = timeCat(...ast.source_.map((child, i) => [child.options_?.weight || 1, children[i]]));
|
||||
if (alignment === 't') {
|
||||
const weightSum = ast.source_.reduce((sum, child) => sum + (child.options_?.weight || 1), 0);
|
||||
return pat._slow(weightSum); // timecat + slow
|
||||
}
|
||||
return pat;
|
||||
}
|
||||
return sequence(...children);
|
||||
case 'element':
|
||||
if (ast.source_ === '~') {
|
||||
return silence;
|
||||
}
|
||||
if (typeof ast.source_ !== 'object') {
|
||||
if (!addMiniLocations) {
|
||||
return ast.source_;
|
||||
}
|
||||
if (!ast.location_) {
|
||||
console.warn('no location for', ast);
|
||||
return ast.source_;
|
||||
}
|
||||
const { start, end } = ast.location_;
|
||||
const value = !isNaN(Number(ast.source_)) ? Number(ast.source_) : ast.source_;
|
||||
// the following line expects the shapeshifter append .withMiniLocation
|
||||
// because location_ is only relative to the mini string, but we need it relative to whole code
|
||||
return pure(value).withLocation([start.line, start.column, start.offset], [end.line, end.column, end.offset]);
|
||||
}
|
||||
return patternifyAST(ast.source_);
|
||||
case 'stretch':
|
||||
return patternifyAST(ast.source_).slow(ast.arguments_.amount);
|
||||
case 'scale':
|
||||
let [tonic, scale] = Scale.tokenize(ast.arguments_.scale);
|
||||
const intervals = Scale.get(scale).intervals;
|
||||
const pattern = patternifyAST(ast.source_);
|
||||
tonic = tonic || 'C4';
|
||||
// console.log('scale', ast, pattern, tonic, scale);
|
||||
console.log('tonic', tonic);
|
||||
return pattern.fmap((step: any) => {
|
||||
step = Number(step);
|
||||
if (isNaN(step)) {
|
||||
console.warn(`scale step "${step}" not a number`);
|
||||
return step;
|
||||
}
|
||||
const octaves = Math.floor(step / intervals.length);
|
||||
const mod = (n: number, m: number): number => (n < 0 ? mod(n + m, m) : n % m);
|
||||
const index = mod(step, intervals.length); // % with negative numbers. e.g. -1 % 3 = 2
|
||||
const interval = Interval.add(intervals[index], Interval.fromSemitones(octaves * 12));
|
||||
return Note.transpose(tonic, interval || '1P');
|
||||
});
|
||||
/* case 'struct':
|
||||
// TODO:
|
||||
return silence; */
|
||||
default:
|
||||
console.warn(`node type "${ast.type_}" not implemented -> returning silence`);
|
||||
return silence;
|
||||
}
|
||||
}
|
||||
|
||||
// mini notation only (wraps in "")
|
||||
export const mini = (...strings: string[]) => {
|
||||
const pats = strings.map((str) => {
|
||||
const ast = krill.parse(`"${str}"`);
|
||||
return patternifyAST(ast);
|
||||
});
|
||||
return sequence(...pats);
|
||||
};
|
||||
|
||||
// includes haskell style (raw krill parsing)
|
||||
export const h = (string: string) => {
|
||||
const ast = krill.parse(string);
|
||||
// console.log('ast', ast);
|
||||
return patternifyAST(ast);
|
||||
};
|
||||
|
||||
// shorthand for mini
|
||||
Pattern.prototype.define('mini', mini, { composable: true });
|
||||
Pattern.prototype.define('m', mini, { composable: true });
|
||||
Pattern.prototype.define('h', h, { composable: true });
|
||||
|
||||
// TODO: move this to strudel?
|
||||
export function reify(thing: any) {
|
||||
if (thing?.constructor?.name === 'Pattern') {
|
||||
return thing;
|
||||
}
|
||||
return pure(thing);
|
||||
}
|
||||
|
||||
export function minify(thing: any) {
|
||||
if (typeof thing === 'string') {
|
||||
return mini(thing);
|
||||
}
|
||||
return reify(thing);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { Pattern } from '../../strudel.mjs';
|
||||
|
||||
Pattern.prototype.pianoroll = function ({
|
||||
timeframe = 10,
|
||||
inactive = '#C9E597',
|
||||
active = '#FFCA28',
|
||||
background = '#2A3236',
|
||||
maxMidi = 90,
|
||||
minMidi = 0,
|
||||
} = {}) {
|
||||
const w = window.innerWidth;
|
||||
const h = window.innerHeight;
|
||||
const midiRange = maxMidi - minMidi + 1;
|
||||
const height = h / midiRange;
|
||||
this.draw(
|
||||
(ctx, events, t) => {
|
||||
ctx.fillStyle = background;
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
ctx.fillRect(0, 0, w, h);
|
||||
events.forEach((event) => {
|
||||
const isActive = event.whole.begin <= t && event.whole.end >= t;
|
||||
ctx.fillStyle = event.context?.color || inactive;
|
||||
ctx.strokeStyle = event.context?.color || active;
|
||||
ctx.globalAlpha = event.context.velocity ?? 1;
|
||||
const x = Math.round((event.whole.begin / timeframe) * w);
|
||||
const width = Math.round(((event.whole.end - event.whole.begin) / timeframe) * w);
|
||||
const y = Math.round(h - ((Number(event.value) - minMidi) / midiRange) * h);
|
||||
const offset = (t / timeframe) * w;
|
||||
const margin = 0;
|
||||
const coords = [x - offset + margin + 1, y + 1, width - 2, height - 2];
|
||||
isActive ? ctx.strokeRect(...coords) : ctx.fillRect(...coords);
|
||||
});
|
||||
},
|
||||
timeframe,
|
||||
2, // lookaheadCycles
|
||||
);
|
||||
return this;
|
||||
};
|
||||
@@ -1,261 +0,0 @@
|
||||
import { parseScriptWithLocation } from './shift-parser/index.js'; // npm module does not work in the browser
|
||||
import traverser from './shift-traverser'; // npm module does not work in the browser
|
||||
const { replace } = traverser;
|
||||
import {
|
||||
LiteralStringExpression,
|
||||
IdentifierExpression,
|
||||
CallExpression,
|
||||
StaticMemberExpression,
|
||||
ReturnStatement,
|
||||
ArrayExpression,
|
||||
LiteralNumericExpression,
|
||||
} from 'shift-ast';
|
||||
import codegen from 'shift-codegen';
|
||||
import * as strudel from '../../strudel.mjs';
|
||||
|
||||
const { Pattern } = strudel;
|
||||
|
||||
const isNote = (name) => /^[a-gC-G][bs]?[0-9]$/.test(name);
|
||||
|
||||
const addLocations = true;
|
||||
export const addMiniLocations = true;
|
||||
|
||||
export default (_code) => {
|
||||
const { code, addReturn } = wrapAsync(_code);
|
||||
const ast = parseScriptWithLocation(code);
|
||||
const artificialNodes = [];
|
||||
const parents = [];
|
||||
const shifted = replace(ast.tree, {
|
||||
enter(node, parent) {
|
||||
parents.push(parent);
|
||||
const isSynthetic = parents.some((p) => artificialNodes.includes(p));
|
||||
if (isSynthetic) {
|
||||
return node;
|
||||
}
|
||||
|
||||
// replace template string `xxx` with mini(`xxx`)
|
||||
if (isBackTickString(node)) {
|
||||
return minifyWithLocation(node, node, ast.locations, artificialNodes);
|
||||
}
|
||||
// allows to use top level strings, which are normally directives... but we don't need directives
|
||||
if (node.directives?.length === 1 && !node.statements?.length) {
|
||||
const str = new LiteralStringExpression({ value: node.directives[0].rawValue });
|
||||
const wrapped = minifyWithLocation(str, node.directives[0], ast.locations, artificialNodes);
|
||||
return { ...node, directives: [], statements: [wrapped] };
|
||||
}
|
||||
|
||||
// replace double quote string "xxx" with mini('xxx')
|
||||
if (isStringWithDoubleQuotes(node, ast.locations, code)) {
|
||||
return minifyWithLocation(node, node, ast.locations, artificialNodes);
|
||||
}
|
||||
|
||||
// operator overloading => still not done
|
||||
const operators = {
|
||||
'*': 'fast',
|
||||
'/': 'slow',
|
||||
'&': 'stack',
|
||||
'&&': 'append',
|
||||
};
|
||||
if (
|
||||
node.type === 'BinaryExpression' &&
|
||||
operators[node.operator] &&
|
||||
['LiteralNumericExpression', 'LiteralStringExpression', 'IdentifierExpression'].includes(node.right?.type) &&
|
||||
canBeOverloaded(node.left)
|
||||
) {
|
||||
let arg = node.left;
|
||||
if (node.left.type === 'IdentifierExpression') {
|
||||
arg = wrapFunction('reify', node.left);
|
||||
}
|
||||
return new CallExpression({
|
||||
callee: new StaticMemberExpression({
|
||||
property: operators[node.operator],
|
||||
object: wrapFunction('reify', arg),
|
||||
}),
|
||||
arguments: [node.right],
|
||||
});
|
||||
}
|
||||
|
||||
const isMarkable = isPatternArg(parents) || hasModifierCall(parent);
|
||||
// add to location to pure(x) calls
|
||||
if (node.type === 'CallExpression' && node.callee.name === 'pure') {
|
||||
const literal = node.arguments[0];
|
||||
// const value = literal[{ LiteralNumericExpression: 'value', LiteralStringExpression: 'name' }[literal.type]];
|
||||
return reifyWithLocation(literal, node.arguments[0], ast.locations, artificialNodes);
|
||||
}
|
||||
// replace pseudo note variables
|
||||
if (node.type === 'IdentifierExpression') {
|
||||
if (isNote(node.name)) {
|
||||
const value = node.name[1] === 's' ? node.name.replace('s', '#') : node.name;
|
||||
if (addLocations && isMarkable) {
|
||||
return reifyWithLocation(new LiteralStringExpression({ value }), node, ast.locations, artificialNodes);
|
||||
}
|
||||
return new LiteralStringExpression({ value });
|
||||
}
|
||||
if (node.name === 'r') {
|
||||
return new IdentifierExpression({ name: 'silence' });
|
||||
}
|
||||
}
|
||||
if (
|
||||
addLocations &&
|
||||
['LiteralStringExpression' /* , 'LiteralNumericExpression' */].includes(node.type) &&
|
||||
isMarkable
|
||||
) {
|
||||
// TODO: to make LiteralNumericExpression work, we need to make sure we're not inside timeCat...
|
||||
return reifyWithLocation(node, node, ast.locations, artificialNodes);
|
||||
}
|
||||
if (addMiniLocations) {
|
||||
return addMiniNotationLocations(node, ast.locations, artificialNodes);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
leave() {
|
||||
parents.pop();
|
||||
},
|
||||
});
|
||||
// add return to last statement (because it's wrapped in an async function artificially)
|
||||
addReturn(shifted);
|
||||
const generated = codegen(shifted);
|
||||
return generated;
|
||||
};
|
||||
|
||||
function wrapAsync(code) {
|
||||
// wrap code in async to make await work on top level => this will create 1 line offset to locations
|
||||
// this is why line offset is -1 in getLocationObject calls below
|
||||
code = `(async () => {
|
||||
${code}
|
||||
})()`;
|
||||
const addReturn = (ast) => {
|
||||
const body = ast.statements[0].expression.callee.body; // actual code ast inside async function body
|
||||
body.statements = body.statements
|
||||
.slice(0, -1)
|
||||
.concat([new ReturnStatement({ expression: body.statements.slice(-1)[0] })]);
|
||||
};
|
||||
return {
|
||||
code,
|
||||
addReturn,
|
||||
};
|
||||
}
|
||||
|
||||
function addMiniNotationLocations(node, locations, artificialNodes) {
|
||||
const miniFunctions = ['mini', 'm'];
|
||||
// const isAlreadyWrapped = parent?.type === 'CallExpression' && parent.callee.name === 'withLocationOffset';
|
||||
if (node.type === 'CallExpression' && miniFunctions.includes(node.callee.name)) {
|
||||
// mini('c3')
|
||||
if (node.arguments.length > 1) {
|
||||
// TODO: transform mini(...args) to cat(...args.map(mini)) ?
|
||||
console.warn('multi arg mini locations not supported yet...');
|
||||
return node;
|
||||
}
|
||||
const str = node.arguments[0];
|
||||
return minifyWithLocation(str, str, locations, artificialNodes);
|
||||
}
|
||||
if (node.type === 'StaticMemberExpression' && miniFunctions.includes(node.property)) {
|
||||
// 'c3'.mini or 'c3'.m
|
||||
return minifyWithLocation(node.object, node, locations, artificialNodes);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function wrapFunction(name, ...args) {
|
||||
return new CallExpression({
|
||||
callee: new IdentifierExpression({ name }),
|
||||
arguments: args,
|
||||
});
|
||||
}
|
||||
|
||||
function isBackTickString(node) {
|
||||
return node.type === 'TemplateExpression' && node.elements.length === 1;
|
||||
}
|
||||
|
||||
function isStringWithDoubleQuotes(node, locations, code) {
|
||||
if (node.type !== 'LiteralStringExpression') {
|
||||
return false;
|
||||
}
|
||||
const loc = locations.get(node);
|
||||
const snippet = code.slice(loc.start.offset, loc.end.offset);
|
||||
return snippet[0] === '"'; // we can trust the end is also ", as the parsing did not fail
|
||||
}
|
||||
|
||||
// returns true if the given parents belong to a pattern argument node
|
||||
// this is used to check if a node should receive a location for highlighting
|
||||
function isPatternArg(parents) {
|
||||
if (!parents.length) {
|
||||
return false;
|
||||
}
|
||||
const ancestors = parents.slice(0, -1);
|
||||
const parent = parents[parents.length - 1];
|
||||
if (isPatternFactory(parent)) {
|
||||
return true;
|
||||
}
|
||||
if (parent?.type === 'ArrayExpression') {
|
||||
return isPatternArg(ancestors);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function hasModifierCall(parent) {
|
||||
// TODO: modifiers are more than composables, for example every is not composable but should be seen as modifier..
|
||||
// need all prototypes of Pattern
|
||||
return (
|
||||
parent?.type === 'StaticMemberExpression' && Object.keys(Pattern.prototype.composable).includes(parent.property)
|
||||
);
|
||||
}
|
||||
|
||||
function isPatternFactory(node) {
|
||||
return node?.type === 'CallExpression' && Object.keys(Pattern.prototype.factories).includes(node.callee.name);
|
||||
}
|
||||
|
||||
function canBeOverloaded(node) {
|
||||
return (node.type === 'IdentifierExpression' && isNote(node.name)) || isPatternFactory(node);
|
||||
// TODO: support sequence(c3).transpose(3).x.y.z
|
||||
}
|
||||
|
||||
// turns node in reify(value).withLocation(location), where location is the node's location in the source code
|
||||
// with this, the reified pattern can pass its location to the event, to know where to highlight when it's active
|
||||
function reifyWithLocation(literalNode, node, locations, artificialNodes) {
|
||||
const args = getLocationArguments(node, locations);
|
||||
const withLocation = new CallExpression({
|
||||
callee: new StaticMemberExpression({
|
||||
object: wrapFunction('reify', literalNode),
|
||||
property: 'withLocation',
|
||||
}),
|
||||
arguments: args,
|
||||
});
|
||||
artificialNodes.push(withLocation);
|
||||
return withLocation;
|
||||
}
|
||||
|
||||
// turns node in reify(value).withLocation(location), where location is the node's location in the source code
|
||||
// with this, the reified pattern can pass its location to the event, to know where to highlight when it's active
|
||||
function minifyWithLocation(literalNode, node, locations, artificialNodes) {
|
||||
const args = getLocationArguments(node, locations);
|
||||
const withLocation = new CallExpression({
|
||||
callee: new StaticMemberExpression({
|
||||
object: wrapFunction('mini', literalNode),
|
||||
property: 'withMiniLocation',
|
||||
}),
|
||||
arguments: args,
|
||||
});
|
||||
artificialNodes.push(withLocation);
|
||||
return withLocation;
|
||||
}
|
||||
|
||||
function getLocationArguments(node, locations) {
|
||||
const loc = locations.get(node);
|
||||
return [
|
||||
new ArrayExpression({
|
||||
elements: [
|
||||
new LiteralNumericExpression({ value: loc.start.line - 1 }), // the minus 1 assumes the code has been wrapped in async iife
|
||||
new LiteralNumericExpression({ value: loc.start.column }),
|
||||
new LiteralNumericExpression({ value: loc.start.offset }),
|
||||
],
|
||||
}),
|
||||
new ArrayExpression({
|
||||
elements: [
|
||||
new LiteralNumericExpression({ value: loc.end.line - 1 }), // the minus 1 assumes the code has been wrapped in async iife
|
||||
new LiteralNumericExpression({ value: loc.end.column }),
|
||||
new LiteralNumericExpression({ value: loc.end.offset }),
|
||||
],
|
||||
}),
|
||||
];
|
||||
}
|
||||
@@ -1,409 +0,0 @@
|
||||
/**
|
||||
* Copyright 2014 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import MultiMap from 'multimap';
|
||||
|
||||
function addEach(thisMap, ...otherMaps) {
|
||||
otherMaps.forEach(otherMap => {
|
||||
otherMap.forEachEntry((v, k) => {
|
||||
thisMap.set.apply(thisMap, [k].concat(v));
|
||||
});
|
||||
});
|
||||
return thisMap;
|
||||
}
|
||||
|
||||
let identity; // initialised below EarlyErrorState
|
||||
|
||||
export class EarlyErrorState {
|
||||
|
||||
constructor() {
|
||||
this.errors = [];
|
||||
// errors that are only errors in strict mode code
|
||||
this.strictErrors = [];
|
||||
|
||||
// Label values used in LabeledStatement nodes; cleared at function boundaries
|
||||
this.usedLabelNames = [];
|
||||
|
||||
// BreakStatement nodes; cleared at iteration; switch; and function boundaries
|
||||
this.freeBreakStatements = [];
|
||||
// ContinueStatement nodes; cleared at
|
||||
this.freeContinueStatements = [];
|
||||
|
||||
// labeled BreakStatement nodes; cleared at LabeledStatement with same Label and function boundaries
|
||||
this.freeLabeledBreakStatements = [];
|
||||
// labeled ContinueStatement nodes; cleared at labeled iteration statement with same Label and function boundaries
|
||||
this.freeLabeledContinueStatements = [];
|
||||
|
||||
// NewTargetExpression nodes; cleared at function (besides arrow expression) boundaries
|
||||
this.newTargetExpressions = [];
|
||||
|
||||
// BindingIdentifier nodes; cleared at containing declaration node
|
||||
this.boundNames = new MultiMap;
|
||||
// BindingIdentifiers that were found to be in a lexical binding position
|
||||
this.lexicallyDeclaredNames = new MultiMap;
|
||||
// BindingIdentifiers that were the name of a FunctionDeclaration
|
||||
this.functionDeclarationNames = new MultiMap;
|
||||
// BindingIdentifiers that were found to be in a variable binding position
|
||||
this.varDeclaredNames = new MultiMap;
|
||||
// BindingIdentifiers that were found to be in a variable binding position
|
||||
this.forOfVarDeclaredNames = [];
|
||||
|
||||
// Names that this module exports
|
||||
this.exportedNames = new MultiMap;
|
||||
// Locally declared names that are referenced in export declarations
|
||||
this.exportedBindings = new MultiMap;
|
||||
|
||||
// CallExpressions with Super callee
|
||||
this.superCallExpressions = [];
|
||||
// SuperCall expressions in the context of a Method named "constructor"
|
||||
this.superCallExpressionsInConstructorMethod = [];
|
||||
// MemberExpressions with Super object
|
||||
this.superPropertyExpressions = [];
|
||||
|
||||
// YieldExpression and YieldGeneratorExpression nodes; cleared at function boundaries
|
||||
this.yieldExpressions = [];
|
||||
// AwaitExpression nodes; cleared at function boundaries
|
||||
this.awaitExpressions = [];
|
||||
}
|
||||
|
||||
|
||||
addFreeBreakStatement(s) {
|
||||
this.freeBreakStatements.push(s);
|
||||
return this;
|
||||
}
|
||||
|
||||
addFreeLabeledBreakStatement(s) {
|
||||
this.freeLabeledBreakStatements.push(s);
|
||||
return this;
|
||||
}
|
||||
|
||||
clearFreeBreakStatements() {
|
||||
this.freeBreakStatements = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
addFreeContinueStatement(s) {
|
||||
this.freeContinueStatements.push(s);
|
||||
return this;
|
||||
}
|
||||
|
||||
addFreeLabeledContinueStatement(s) {
|
||||
this.freeLabeledContinueStatements.push(s);
|
||||
return this;
|
||||
}
|
||||
|
||||
clearFreeContinueStatements() {
|
||||
this.freeContinueStatements = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
enforceFreeBreakStatementErrors(createError) {
|
||||
[].push.apply(this.errors, this.freeBreakStatements.map(createError));
|
||||
this.freeBreakStatements = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
enforceFreeLabeledBreakStatementErrors(createError) {
|
||||
[].push.apply(this.errors, this.freeLabeledBreakStatements.map(createError));
|
||||
this.freeLabeledBreakStatements = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
enforceFreeContinueStatementErrors(createError) {
|
||||
[].push.apply(this.errors, this.freeContinueStatements.map(createError));
|
||||
this.freeContinueStatements = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
enforceFreeLabeledContinueStatementErrors(createError) {
|
||||
[].push.apply(this.errors, this.freeLabeledContinueStatements.map(createError));
|
||||
this.freeLabeledContinueStatements = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
observeIterationLabel(label) {
|
||||
this.usedLabelNames.push(label);
|
||||
this.freeLabeledBreakStatements = this.freeLabeledBreakStatements.filter(s => s.label !== label);
|
||||
this.freeLabeledContinueStatements = this.freeLabeledContinueStatements.filter(s => s.label !== label);
|
||||
return this;
|
||||
}
|
||||
|
||||
observeNonIterationLabel(label) {
|
||||
this.usedLabelNames.push(label);
|
||||
this.freeLabeledBreakStatements = this.freeLabeledBreakStatements.filter(s => s.label !== label);
|
||||
return this;
|
||||
}
|
||||
|
||||
clearUsedLabelNames() {
|
||||
this.usedLabelNames = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
observeSuperCallExpression(node) {
|
||||
this.superCallExpressions.push(node);
|
||||
return this;
|
||||
}
|
||||
|
||||
observeConstructorMethod() {
|
||||
this.superCallExpressionsInConstructorMethod = this.superCallExpressions;
|
||||
this.superCallExpressions = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
clearSuperCallExpressionsInConstructorMethod() {
|
||||
this.superCallExpressionsInConstructorMethod = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
enforceSuperCallExpressions(createError) {
|
||||
[].push.apply(this.errors, this.superCallExpressions.map(createError));
|
||||
[].push.apply(this.errors, this.superCallExpressionsInConstructorMethod.map(createError));
|
||||
this.superCallExpressions = [];
|
||||
this.superCallExpressionsInConstructorMethod = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
enforceSuperCallExpressionsInConstructorMethod(createError) {
|
||||
[].push.apply(this.errors, this.superCallExpressionsInConstructorMethod.map(createError));
|
||||
this.superCallExpressionsInConstructorMethod = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
observeSuperPropertyExpression(node) {
|
||||
this.superPropertyExpressions.push(node);
|
||||
return this;
|
||||
}
|
||||
|
||||
clearSuperPropertyExpressions() {
|
||||
this.superPropertyExpressions = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
enforceSuperPropertyExpressions(createError) {
|
||||
[].push.apply(this.errors, this.superPropertyExpressions.map(createError));
|
||||
this.superPropertyExpressions = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
observeNewTargetExpression(node) {
|
||||
this.newTargetExpressions.push(node);
|
||||
return this;
|
||||
}
|
||||
|
||||
clearNewTargetExpressions() {
|
||||
this.newTargetExpressions = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
bindName(name, node) {
|
||||
this.boundNames.set(name, node);
|
||||
return this;
|
||||
}
|
||||
|
||||
clearBoundNames() {
|
||||
this.boundNames = new MultiMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
observeLexicalDeclaration() {
|
||||
addEach(this.lexicallyDeclaredNames, this.boundNames);
|
||||
this.boundNames = new MultiMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
observeLexicalBoundary() {
|
||||
this.previousLexicallyDeclaredNames = this.lexicallyDeclaredNames;
|
||||
this.lexicallyDeclaredNames = new MultiMap;
|
||||
this.functionDeclarationNames = new MultiMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
enforceDuplicateLexicallyDeclaredNames(createError) {
|
||||
this.lexicallyDeclaredNames.forEachEntry(nodes => {
|
||||
if (nodes.length > 1) {
|
||||
nodes.slice(1).forEach(dupeNode => {
|
||||
this.addError(createError(dupeNode));
|
||||
});
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
enforceConflictingLexicallyDeclaredNames(otherNames, createError) {
|
||||
this.lexicallyDeclaredNames.forEachEntry((nodes, bindingName) => {
|
||||
if (otherNames.has(bindingName)) {
|
||||
nodes.forEach(conflictingNode => {
|
||||
this.addError(createError(conflictingNode));
|
||||
});
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
observeFunctionDeclaration() {
|
||||
this.observeVarBoundary();
|
||||
addEach(this.functionDeclarationNames, this.boundNames);
|
||||
this.boundNames = new MultiMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
functionDeclarationNamesAreLexical() {
|
||||
addEach(this.lexicallyDeclaredNames, this.functionDeclarationNames);
|
||||
this.functionDeclarationNames = new MultiMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
observeVarDeclaration() {
|
||||
addEach(this.varDeclaredNames, this.boundNames);
|
||||
this.boundNames = new MultiMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
recordForOfVars() {
|
||||
this.varDeclaredNames.forEach(bindingIdentifier => {
|
||||
this.forOfVarDeclaredNames.push(bindingIdentifier);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
observeVarBoundary() {
|
||||
this.lexicallyDeclaredNames = new MultiMap;
|
||||
this.functionDeclarationNames = new MultiMap;
|
||||
this.varDeclaredNames = new MultiMap;
|
||||
this.forOfVarDeclaredNames = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
exportName(name, node) {
|
||||
this.exportedNames.set(name, node);
|
||||
return this;
|
||||
}
|
||||
|
||||
exportDeclaredNames() {
|
||||
addEach(this.exportedNames, this.lexicallyDeclaredNames, this.varDeclaredNames);
|
||||
addEach(this.exportedBindings, this.lexicallyDeclaredNames, this.varDeclaredNames);
|
||||
return this;
|
||||
}
|
||||
|
||||
exportBinding(name, node) {
|
||||
this.exportedBindings.set(name, node);
|
||||
return this;
|
||||
}
|
||||
|
||||
clearExportedBindings() {
|
||||
this.exportedBindings = new MultiMap;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
observeYieldExpression(node) {
|
||||
this.yieldExpressions.push(node);
|
||||
return this;
|
||||
}
|
||||
|
||||
clearYieldExpressions() {
|
||||
this.yieldExpressions = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
observeAwaitExpression(node) {
|
||||
this.awaitExpressions.push(node);
|
||||
return this;
|
||||
}
|
||||
|
||||
clearAwaitExpressions() {
|
||||
this.awaitExpressions = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
addError(e) {
|
||||
this.errors.push(e);
|
||||
return this;
|
||||
}
|
||||
|
||||
addStrictError(e) {
|
||||
this.strictErrors.push(e);
|
||||
return this;
|
||||
}
|
||||
|
||||
enforceStrictErrors() {
|
||||
[].push.apply(this.errors, this.strictErrors);
|
||||
this.strictErrors = [];
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// MONOID IMPLEMENTATION
|
||||
|
||||
static empty() {
|
||||
return identity;
|
||||
}
|
||||
|
||||
concat(s) {
|
||||
if (this === identity) return s;
|
||||
if (s === identity) return this;
|
||||
[].push.apply(this.errors, s.errors);
|
||||
[].push.apply(this.strictErrors, s.strictErrors);
|
||||
[].push.apply(this.usedLabelNames, s.usedLabelNames);
|
||||
[].push.apply(this.freeBreakStatements, s.freeBreakStatements);
|
||||
[].push.apply(this.freeContinueStatements, s.freeContinueStatements);
|
||||
[].push.apply(this.freeLabeledBreakStatements, s.freeLabeledBreakStatements);
|
||||
[].push.apply(this.freeLabeledContinueStatements, s.freeLabeledContinueStatements);
|
||||
[].push.apply(this.newTargetExpressions, s.newTargetExpressions);
|
||||
addEach(this.boundNames, s.boundNames);
|
||||
addEach(this.lexicallyDeclaredNames, s.lexicallyDeclaredNames);
|
||||
addEach(this.functionDeclarationNames, s.functionDeclarationNames);
|
||||
addEach(this.varDeclaredNames, s.varDeclaredNames);
|
||||
[].push.apply(this.forOfVarDeclaredNames, s.forOfVarDeclaredNames);
|
||||
addEach(this.exportedNames, s.exportedNames);
|
||||
addEach(this.exportedBindings, s.exportedBindings);
|
||||
[].push.apply(this.superCallExpressions, s.superCallExpressions);
|
||||
[].push.apply(this.superCallExpressionsInConstructorMethod, s.superCallExpressionsInConstructorMethod);
|
||||
[].push.apply(this.superPropertyExpressions, s.superPropertyExpressions);
|
||||
[].push.apply(this.yieldExpressions, s.yieldExpressions);
|
||||
[].push.apply(this.awaitExpressions, s.awaitExpressions);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
identity = new EarlyErrorState;
|
||||
Object.getOwnPropertyNames(EarlyErrorState.prototype).forEach(methodName => {
|
||||
if (methodName === 'constructor') return;
|
||||
Object.defineProperty(identity, methodName, {
|
||||
value() {
|
||||
return EarlyErrorState.prototype[methodName].apply(new EarlyErrorState, arguments);
|
||||
},
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
});
|
||||
|
||||
export class EarlyError extends Error {
|
||||
constructor(node, message) {
|
||||
super(message);
|
||||
this.node = node;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -1,772 +0,0 @@
|
||||
/**
|
||||
* Copyright 2014 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import reduce, { MonoidalReducer } from '../shift-reducer';
|
||||
import { isStrictModeReservedWord } from './utils';
|
||||
import { ErrorMessages } from './errors';
|
||||
|
||||
import { EarlyErrorState, EarlyError } from './early-error-state';
|
||||
|
||||
function isStrictFunctionBody({ directives }) {
|
||||
return directives.some(directive => directive.rawValue === 'use strict');
|
||||
}
|
||||
|
||||
function isLabelledFunction(node) {
|
||||
return node.type === 'LabeledStatement' &&
|
||||
(node.body.type === 'FunctionDeclaration' || isLabelledFunction(node.body));
|
||||
}
|
||||
|
||||
function isIterationStatement(node) {
|
||||
switch (node.type) {
|
||||
case 'LabeledStatement':
|
||||
return isIterationStatement(node.body);
|
||||
case 'DoWhileStatement':
|
||||
case 'ForInStatement':
|
||||
case 'ForOfStatement':
|
||||
case 'ForStatement':
|
||||
case 'WhileStatement':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isSpecialMethod(methodDefinition) {
|
||||
if (methodDefinition.name.type !== 'StaticPropertyName' || methodDefinition.name.value !== 'constructor') {
|
||||
return false;
|
||||
}
|
||||
switch (methodDefinition.type) {
|
||||
case 'Getter':
|
||||
case 'Setter':
|
||||
return true;
|
||||
case 'Method':
|
||||
return methodDefinition.isGenerator || methodDefinition.isAsync;
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
throw new Error('not reached');
|
||||
}
|
||||
|
||||
|
||||
function enforceDuplicateConstructorMethods(node, s) {
|
||||
let ctors = node.elements.filter(e =>
|
||||
!e.isStatic &&
|
||||
e.method.type === 'Method' &&
|
||||
!e.method.isGenerator &&
|
||||
e.method.name.type === 'StaticPropertyName' &&
|
||||
e.method.name.value === 'constructor'
|
||||
);
|
||||
if (ctors.length > 1) {
|
||||
ctors.slice(1).forEach(ctor => {
|
||||
s = s.addError(new EarlyError(ctor, 'Duplicate constructor method in class'));
|
||||
});
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
const SUPERCALL_ERROR = node => new EarlyError(node, ErrorMessages.ILLEGAL_SUPER_CALL);
|
||||
const SUPERPROPERTY_ERROR = node => new EarlyError(node, 'Member access on super must be in a method');
|
||||
const DUPLICATE_BINDING = node => new EarlyError(node, `Duplicate binding ${JSON.stringify(node.name)}`);
|
||||
const FREE_CONTINUE = node => new EarlyError(node, 'Continue statement must be nested within an iteration statement');
|
||||
const UNBOUND_CONTINUE = node => new EarlyError(node, `Continue statement must be nested within an iteration statement with label ${JSON.stringify(node.label)}`);
|
||||
const FREE_BREAK = node => new EarlyError(node, 'Break statement must be nested within an iteration statement or a switch statement');
|
||||
const UNBOUND_BREAK = node => new EarlyError(node, `Break statement must be nested within a statement with label ${JSON.stringify(node.label)}`);
|
||||
|
||||
export class EarlyErrorChecker extends MonoidalReducer {
|
||||
constructor() {
|
||||
super(EarlyErrorState);
|
||||
}
|
||||
|
||||
reduceAssignmentExpression() {
|
||||
return super.reduceAssignmentExpression(...arguments).clearBoundNames();
|
||||
}
|
||||
|
||||
reduceAssignmentTargetIdentifier(node) {
|
||||
let s = this.identity;
|
||||
if (node.name === 'eval' || node.name === 'arguments' || isStrictModeReservedWord(node.name)) {
|
||||
s = s.addStrictError(new EarlyError(node, `The identifier ${JSON.stringify(node.name)} must not be in binding position in strict mode`));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceArrowExpression(node, { params, body }) {
|
||||
let isSimpleParameterList = node.params.rest == null && node.params.items.every(i => i.type === 'BindingIdentifier');
|
||||
params = params.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
if (node.body.type === 'FunctionBody') {
|
||||
body = body.enforceConflictingLexicallyDeclaredNames(params.lexicallyDeclaredNames, DUPLICATE_BINDING);
|
||||
if (isStrictFunctionBody(node.body)) {
|
||||
params = params.enforceStrictErrors();
|
||||
body = body.enforceStrictErrors();
|
||||
}
|
||||
}
|
||||
params.yieldExpressions.forEach(n => {
|
||||
params = params.addError(new EarlyError(n, 'Arrow parameters must not contain yield expressions'));
|
||||
});
|
||||
params.awaitExpressions.forEach(n => {
|
||||
params = params.addError(new EarlyError(n, 'Arrow parameters must not contain await expressions'));
|
||||
});
|
||||
let s = super.reduceArrowExpression(node, { params, body });
|
||||
if (!isSimpleParameterList && node.body.type === 'FunctionBody' && isStrictFunctionBody(node.body)) {
|
||||
s = s.addError(new EarlyError(node, 'Functions with non-simple parameter lists may not contain a "use strict" directive'));
|
||||
}
|
||||
s = s.clearYieldExpressions();
|
||||
s = s.clearAwaitExpressions();
|
||||
s = s.observeVarBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceAwaitExpression(node, { expression }) {
|
||||
return expression.observeAwaitExpression(node);
|
||||
}
|
||||
|
||||
reduceBindingIdentifier(node) {
|
||||
let s = this.identity;
|
||||
if (node.name === 'eval' || node.name === 'arguments' || isStrictModeReservedWord(node.name)) {
|
||||
s = s.addStrictError(new EarlyError(node, `The identifier ${JSON.stringify(node.name)} must not be in binding position in strict mode`));
|
||||
}
|
||||
s = s.bindName(node.name, node);
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceBlock() {
|
||||
let s = super.reduceBlock(...arguments);
|
||||
s = s.functionDeclarationNamesAreLexical();
|
||||
s = s.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
s = s.enforceConflictingLexicallyDeclaredNames(s.varDeclaredNames, DUPLICATE_BINDING);
|
||||
s = s.observeLexicalBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceBreakStatement(node) {
|
||||
let s = super.reduceBreakStatement(...arguments);
|
||||
s = node.label == null
|
||||
? s.addFreeBreakStatement(node)
|
||||
: s.addFreeLabeledBreakStatement(node);
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceCallExpression(node) {
|
||||
let s = super.reduceCallExpression(...arguments);
|
||||
if (node.callee.type === 'Super') {
|
||||
s = s.observeSuperCallExpression(node);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceCatchClause(node, { binding, body }) {
|
||||
binding = binding.observeLexicalDeclaration();
|
||||
binding = binding.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
binding = binding.enforceConflictingLexicallyDeclaredNames(body.previousLexicallyDeclaredNames, DUPLICATE_BINDING);
|
||||
binding.lexicallyDeclaredNames.forEachEntry((nodes, bindingName) => {
|
||||
if (body.varDeclaredNames.has(bindingName)) {
|
||||
body.varDeclaredNames.get(bindingName).forEach(conflictingNode => {
|
||||
if (body.forOfVarDeclaredNames.indexOf(conflictingNode) >= 0) {
|
||||
binding = binding.addError(DUPLICATE_BINDING(conflictingNode));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
let s = super.reduceCatchClause(node, { binding, body });
|
||||
s = s.observeLexicalBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceClassDeclaration(node, { name, super: _super, elements }) {
|
||||
let s = name.enforceStrictErrors();
|
||||
let sElements = this.append(...elements);
|
||||
sElements = sElements.enforceStrictErrors();
|
||||
if (node.super != null) {
|
||||
_super = _super.enforceStrictErrors();
|
||||
s = this.append(s, _super);
|
||||
sElements = sElements.clearSuperCallExpressionsInConstructorMethod();
|
||||
}
|
||||
s = this.append(s, sElements);
|
||||
s = enforceDuplicateConstructorMethods(node, s);
|
||||
s = s.observeLexicalDeclaration();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceClassElement(node) {
|
||||
let s = super.reduceClassElement(...arguments);
|
||||
if (!node.isStatic && isSpecialMethod(node.method)) {
|
||||
s = s.addError(new EarlyError(node, ErrorMessages.ILLEGAL_CONSTRUCTORS));
|
||||
}
|
||||
if (node.isStatic && node.method.name.type === 'StaticPropertyName' && node.method.name.value === 'prototype') {
|
||||
s = s.addError(new EarlyError(node, 'Static class methods cannot be named "prototype"'));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceClassExpression(node, { name, super: _super, elements }) {
|
||||
let s = node.name == null ? this.identity : name.enforceStrictErrors();
|
||||
let sElements = this.append(...elements);
|
||||
sElements = sElements.enforceStrictErrors();
|
||||
if (node.super != null) {
|
||||
_super = _super.enforceStrictErrors();
|
||||
s = this.append(s, _super);
|
||||
sElements = sElements.clearSuperCallExpressionsInConstructorMethod();
|
||||
}
|
||||
s = this.append(s, sElements);
|
||||
s = enforceDuplicateConstructorMethods(node, s);
|
||||
s = s.clearBoundNames();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceCompoundAssignmentExpression() {
|
||||
return super.reduceCompoundAssignmentExpression(...arguments).clearBoundNames();
|
||||
}
|
||||
|
||||
reduceComputedMemberExpression(node) {
|
||||
let s = super.reduceComputedMemberExpression(...arguments);
|
||||
if (node.object.type === 'Super') {
|
||||
s = s.observeSuperPropertyExpression(node);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceContinueStatement(node) {
|
||||
let s = super.reduceContinueStatement(...arguments);
|
||||
s = node.label == null
|
||||
? s.addFreeContinueStatement(node)
|
||||
: s.addFreeLabeledContinueStatement(node);
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceDoWhileStatement(node) {
|
||||
let s = super.reduceDoWhileStatement(...arguments);
|
||||
if (isLabelledFunction(node.body)) {
|
||||
s = s.addError(new EarlyError(node.body, 'The body of a do-while statement must not be a labeled function declaration'));
|
||||
}
|
||||
s = s.clearFreeContinueStatements();
|
||||
s = s.clearFreeBreakStatements();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceExport() {
|
||||
let s = super.reduceExport(...arguments);
|
||||
s = s.functionDeclarationNamesAreLexical();
|
||||
s = s.exportDeclaredNames();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceExportFrom() {
|
||||
let s = super.reduceExportFrom(...arguments);
|
||||
s = s.clearExportedBindings();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceExportFromSpecifier(node) {
|
||||
let s = super.reduceExportFromSpecifier(...arguments);
|
||||
s = s.exportName(node.exportedName || node.name, node);
|
||||
s = s.exportBinding(node.name, node);
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceExportLocalSpecifier(node) {
|
||||
let s = super.reduceExportLocalSpecifier(...arguments);
|
||||
s = s.exportName(node.exportedName || node.name.name, node);
|
||||
s = s.exportBinding(node.name.name, node);
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceExportDefault(node) {
|
||||
let s = super.reduceExportDefault(...arguments);
|
||||
s = s.functionDeclarationNamesAreLexical();
|
||||
s = s.exportName('default', node);
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceFormalParameters() {
|
||||
let s = super.reduceFormalParameters(...arguments);
|
||||
s = s.observeLexicalDeclaration();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceForStatement(node, { init, test, update, body }) {
|
||||
if (init != null) {
|
||||
init = init.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
init = init.enforceConflictingLexicallyDeclaredNames(body.varDeclaredNames, DUPLICATE_BINDING);
|
||||
}
|
||||
let s = super.reduceForStatement(node, { init, test, update, body });
|
||||
if (node.init != null && node.init.type === 'VariableDeclaration' && node.init.kind === 'const') {
|
||||
node.init.declarators.forEach(declarator => {
|
||||
if (declarator.init == null) {
|
||||
s = s.addError(new EarlyError(declarator, 'Constant lexical declarations must have an initialiser'));
|
||||
}
|
||||
});
|
||||
}
|
||||
if (isLabelledFunction(node.body)) {
|
||||
s = s.addError(new EarlyError(node.body, 'The body of a for statement must not be a labeled function declaration'));
|
||||
}
|
||||
s = s.clearFreeContinueStatements();
|
||||
s = s.clearFreeBreakStatements();
|
||||
s = s.observeLexicalBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceForInStatement(node, { left, right, body }) {
|
||||
left = left.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
left = left.enforceConflictingLexicallyDeclaredNames(body.varDeclaredNames, DUPLICATE_BINDING);
|
||||
let s = super.reduceForInStatement(node, { left, right, body });
|
||||
if (isLabelledFunction(node.body)) {
|
||||
s = s.addError(new EarlyError(node.body, 'The body of a for-in statement must not be a labeled function declaration'));
|
||||
}
|
||||
s = s.clearFreeContinueStatements();
|
||||
s = s.clearFreeBreakStatements();
|
||||
s = s.observeLexicalBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceForOfStatement(node, { left, right, body }) {
|
||||
left = left.recordForOfVars();
|
||||
left = left.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
left = left.enforceConflictingLexicallyDeclaredNames(body.varDeclaredNames, DUPLICATE_BINDING);
|
||||
let s = super.reduceForOfStatement(node, { left, right, body });
|
||||
if (isLabelledFunction(node.body)) {
|
||||
s = s.addError(new EarlyError(node.body, 'The body of a for-of statement must not be a labeled function declaration'));
|
||||
}
|
||||
s = s.clearFreeContinueStatements();
|
||||
s = s.clearFreeBreakStatements();
|
||||
s = s.observeLexicalBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceForAwaitStatement(node, { left, right, body }) {
|
||||
left = left.recordForOfVars();
|
||||
left = left.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
left = left.enforceConflictingLexicallyDeclaredNames(body.varDeclaredNames, DUPLICATE_BINDING);
|
||||
let s = super.reduceForOfStatement(node, { left, right, body });
|
||||
if (isLabelledFunction(node.body)) {
|
||||
s = s.addError(new EarlyError(node.body, 'The body of a for-await statement must not be a labeled function declaration'));
|
||||
}
|
||||
s = s.clearFreeContinueStatements();
|
||||
s = s.clearFreeBreakStatements();
|
||||
s = s.observeLexicalBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceFunctionBody(node) {
|
||||
let s = super.reduceFunctionBody(...arguments);
|
||||
s = s.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
s = s.enforceConflictingLexicallyDeclaredNames(s.varDeclaredNames, DUPLICATE_BINDING);
|
||||
s = s.enforceFreeContinueStatementErrors(FREE_CONTINUE);
|
||||
s = s.enforceFreeLabeledContinueStatementErrors(UNBOUND_CONTINUE);
|
||||
s = s.enforceFreeBreakStatementErrors(FREE_BREAK);
|
||||
s = s.enforceFreeLabeledBreakStatementErrors(UNBOUND_BREAK);
|
||||
s = s.clearUsedLabelNames();
|
||||
s = s.clearYieldExpressions();
|
||||
s = s.clearAwaitExpressions();
|
||||
if (isStrictFunctionBody(node)) {
|
||||
s = s.enforceStrictErrors();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceFunctionDeclaration(node, { name, params, body }) {
|
||||
let isSimpleParameterList = node.params.rest == null && node.params.items.every(i => i.type === 'BindingIdentifier');
|
||||
let addError = !isSimpleParameterList || node.isGenerator ? 'addError' : 'addStrictError';
|
||||
params.lexicallyDeclaredNames.forEachEntry(nodes => {
|
||||
if (nodes.length > 1) {
|
||||
nodes.slice(1).forEach(dupeNode => {
|
||||
params = params[addError](DUPLICATE_BINDING(dupeNode));
|
||||
});
|
||||
}
|
||||
});
|
||||
body = body.enforceConflictingLexicallyDeclaredNames(params.lexicallyDeclaredNames, DUPLICATE_BINDING);
|
||||
body = body.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
body = body.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
|
||||
params = params.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
params = params.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
|
||||
if (node.isGenerator) {
|
||||
params.yieldExpressions.forEach(n => {
|
||||
params = params.addError(new EarlyError(n, 'Generator parameters must not contain yield expressions'));
|
||||
});
|
||||
}
|
||||
if (node.isAsync) {
|
||||
params.awaitExpressions.forEach(n => {
|
||||
params = params.addError(new EarlyError(n, 'Async function parameters must not contain await expressions'));
|
||||
});
|
||||
}
|
||||
params = params.clearNewTargetExpressions();
|
||||
body = body.clearNewTargetExpressions();
|
||||
if (isStrictFunctionBody(node.body)) {
|
||||
params = params.enforceStrictErrors();
|
||||
body = body.enforceStrictErrors();
|
||||
}
|
||||
let s = super.reduceFunctionDeclaration(node, { name, params, body });
|
||||
if (!isSimpleParameterList && isStrictFunctionBody(node.body)) {
|
||||
s = s.addError(new EarlyError(node, 'Functions with non-simple parameter lists may not contain a "use strict" directive'));
|
||||
}
|
||||
s = s.clearYieldExpressions();
|
||||
s = s.clearAwaitExpressions();
|
||||
s = s.observeFunctionDeclaration();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceFunctionExpression(node, { name, params, body }) {
|
||||
let isSimpleParameterList = node.params.rest == null && node.params.items.every(i => i.type === 'BindingIdentifier');
|
||||
let addError = !isSimpleParameterList || node.isGenerator ? 'addError' : 'addStrictError';
|
||||
params.lexicallyDeclaredNames.forEachEntry((nodes, bindingName) => {
|
||||
if (nodes.length > 1) {
|
||||
nodes.slice(1).forEach(dupeNode => {
|
||||
params = params[addError](new EarlyError(dupeNode, `Duplicate binding ${JSON.stringify(bindingName)}`));
|
||||
});
|
||||
}
|
||||
});
|
||||
body = body.enforceConflictingLexicallyDeclaredNames(params.lexicallyDeclaredNames, DUPLICATE_BINDING);
|
||||
body = body.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
body = body.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
|
||||
params = params.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
params = params.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
|
||||
if (node.isGenerator) {
|
||||
params.yieldExpressions.forEach(n => {
|
||||
params = params.addError(new EarlyError(n, 'Generator parameters must not contain yield expressions'));
|
||||
});
|
||||
}
|
||||
if (node.isAsync) {
|
||||
params.awaitExpressions.forEach(n => {
|
||||
params = params.addError(new EarlyError(n, 'Async function parameters must not contain await expressions'));
|
||||
});
|
||||
}
|
||||
params = params.clearNewTargetExpressions();
|
||||
body = body.clearNewTargetExpressions();
|
||||
if (isStrictFunctionBody(node.body)) {
|
||||
params = params.enforceStrictErrors();
|
||||
body = body.enforceStrictErrors();
|
||||
}
|
||||
let s = super.reduceFunctionExpression(node, { name, params, body });
|
||||
if (!isSimpleParameterList && isStrictFunctionBody(node.body)) {
|
||||
s = s.addError(new EarlyError(node, 'Functions with non-simple parameter lists may not contain a "use strict" directive'));
|
||||
}
|
||||
s = s.clearBoundNames();
|
||||
s = s.clearYieldExpressions();
|
||||
s = s.clearAwaitExpressions();
|
||||
s = s.observeVarBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceGetter(node, { name, body }) {
|
||||
body = body.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
body = body.clearSuperPropertyExpressions();
|
||||
body = body.clearNewTargetExpressions();
|
||||
if (isStrictFunctionBody(node.body)) {
|
||||
body = body.enforceStrictErrors();
|
||||
}
|
||||
let s = super.reduceGetter(node, { name, body });
|
||||
s = s.observeVarBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceIdentifierExpression(node) {
|
||||
let s = this.identity;
|
||||
if (isStrictModeReservedWord(node.name)) {
|
||||
s = s.addStrictError(new EarlyError(node, `The identifier ${JSON.stringify(node.name)} must not be in expression position in strict mode`));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceIfStatement(node, { test, consequent, alternate }) {
|
||||
if (isLabelledFunction(node.consequent)) {
|
||||
consequent = consequent.addError(new EarlyError(node.consequent, 'The consequent of an if statement must not be a labeled function declaration'));
|
||||
}
|
||||
if (node.alternate != null && isLabelledFunction(node.alternate)) {
|
||||
alternate = alternate.addError(new EarlyError(node.alternate, 'The alternate of an if statement must not be a labeled function declaration'));
|
||||
}
|
||||
if (node.consequent.type === 'FunctionDeclaration') {
|
||||
consequent = consequent.addStrictError(new EarlyError(node.consequent, 'FunctionDeclarations in IfStatements are disallowed in strict mode'));
|
||||
consequent = consequent.observeLexicalBoundary();
|
||||
}
|
||||
if (node.alternate != null && node.alternate.type === 'FunctionDeclaration') {
|
||||
alternate = alternate.addStrictError(new EarlyError(node.alternate, 'FunctionDeclarations in IfStatements are disallowed in strict mode'));
|
||||
alternate = alternate.observeLexicalBoundary();
|
||||
}
|
||||
return super.reduceIfStatement(node, { test, consequent, alternate });
|
||||
}
|
||||
|
||||
reduceImport() {
|
||||
let s = super.reduceImport(...arguments);
|
||||
s = s.observeLexicalDeclaration();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceImportNamespace() {
|
||||
let s = super.reduceImportNamespace(...arguments);
|
||||
s = s.observeLexicalDeclaration();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceLabeledStatement(node) {
|
||||
let s = super.reduceLabeledStatement(...arguments);
|
||||
if (node.label === 'yield' || isStrictModeReservedWord(node.label)) {
|
||||
s = s.addStrictError(new EarlyError(node, `The identifier ${JSON.stringify(node.label)} must not be in label position in strict mode`));
|
||||
}
|
||||
if (s.usedLabelNames.indexOf(node.label) >= 0) {
|
||||
s = s.addError(new EarlyError(node, `Label ${JSON.stringify(node.label)} has already been declared`));
|
||||
}
|
||||
if (node.body.type === 'FunctionDeclaration') {
|
||||
s = s.addStrictError(new EarlyError(node, 'Labeled FunctionDeclarations are disallowed in strict mode'));
|
||||
}
|
||||
s = isIterationStatement(node.body)
|
||||
? s.observeIterationLabel(node.label)
|
||||
: s.observeNonIterationLabel(node.label);
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceLiteralRegExpExpression() {
|
||||
let s = this.identity;
|
||||
// NOTE: the RegExp pattern acceptor is disabled until we have more confidence in its correctness (more tests)
|
||||
// if (!PatternAcceptor.test(node.pattern, node.flags.indexOf("u") >= 0)) {
|
||||
// s = s.addError(new EarlyError(node, "Invalid regular expression pattern"));
|
||||
// }
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceMethod(node, { name, params, body }) {
|
||||
let isSimpleParameterList = node.params.rest == null && node.params.items.every(i => i.type === 'BindingIdentifier');
|
||||
params = params.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
body = body.enforceConflictingLexicallyDeclaredNames(params.lexicallyDeclaredNames, DUPLICATE_BINDING);
|
||||
if (node.name.type === 'StaticPropertyName' && node.name.value === 'constructor') {
|
||||
body = body.observeConstructorMethod();
|
||||
params = params.observeConstructorMethod();
|
||||
} else {
|
||||
body = body.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
params = params.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
}
|
||||
if (node.isGenerator) {
|
||||
params.yieldExpressions.forEach(n => {
|
||||
params = params.addError(new EarlyError(n, 'Generator parameters must not contain yield expressions'));
|
||||
});
|
||||
}
|
||||
if (node.isAsync) {
|
||||
params.awaitExpressions.forEach(n => {
|
||||
params = params.addError(new EarlyError(n, 'Async function parameters must not contain await expressions'));
|
||||
});
|
||||
}
|
||||
body = body.clearSuperPropertyExpressions();
|
||||
params = params.clearSuperPropertyExpressions();
|
||||
params = params.clearNewTargetExpressions();
|
||||
body = body.clearNewTargetExpressions();
|
||||
if (isStrictFunctionBody(node.body)) {
|
||||
params = params.enforceStrictErrors();
|
||||
body = body.enforceStrictErrors();
|
||||
}
|
||||
let s = super.reduceMethod(node, { name, params, body });
|
||||
if (!isSimpleParameterList && isStrictFunctionBody(node.body)) {
|
||||
s = s.addError(new EarlyError(node, 'Functions with non-simple parameter lists may not contain a "use strict" directive'));
|
||||
}
|
||||
s = s.clearYieldExpressions();
|
||||
s = s.clearAwaitExpressions();
|
||||
s = s.observeVarBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceModule() {
|
||||
let s = super.reduceModule(...arguments);
|
||||
s = s.functionDeclarationNamesAreLexical();
|
||||
s = s.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
s = s.enforceConflictingLexicallyDeclaredNames(s.varDeclaredNames, DUPLICATE_BINDING);
|
||||
s.exportedNames.forEachEntry((nodes, bindingName) => {
|
||||
if (nodes.length > 1) {
|
||||
nodes.slice(1).forEach(dupeNode => {
|
||||
s = s.addError(new EarlyError(dupeNode, `Duplicate export ${JSON.stringify(bindingName)}`));
|
||||
});
|
||||
}
|
||||
});
|
||||
s.exportedBindings.forEachEntry((nodes, bindingName) => {
|
||||
if (!s.lexicallyDeclaredNames.has(bindingName) && !s.varDeclaredNames.has(bindingName)) {
|
||||
nodes.forEach(undeclaredNode => {
|
||||
s = s.addError(new EarlyError(undeclaredNode, `Exported binding ${JSON.stringify(bindingName)} is not declared`));
|
||||
});
|
||||
}
|
||||
});
|
||||
s.newTargetExpressions.forEach(node => {
|
||||
s = s.addError(new EarlyError(node, 'new.target must be within function (but not arrow expression) code'));
|
||||
});
|
||||
s = s.enforceFreeContinueStatementErrors(FREE_CONTINUE);
|
||||
s = s.enforceFreeLabeledContinueStatementErrors(UNBOUND_CONTINUE);
|
||||
s = s.enforceFreeBreakStatementErrors(FREE_BREAK);
|
||||
s = s.enforceFreeLabeledBreakStatementErrors(UNBOUND_BREAK);
|
||||
s = s.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
s = s.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
|
||||
s = s.enforceStrictErrors();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceNewTargetExpression(node) {
|
||||
return this.identity.observeNewTargetExpression(node);
|
||||
}
|
||||
|
||||
reduceObjectExpression(node) {
|
||||
let s = super.reduceObjectExpression(...arguments);
|
||||
s = s.enforceSuperCallExpressionsInConstructorMethod(SUPERCALL_ERROR);
|
||||
let protos = node.properties.filter(p => p.type === 'DataProperty' && p.name.type === 'StaticPropertyName' && p.name.value === '__proto__');
|
||||
protos.slice(1).forEach(n => {
|
||||
s = s.addError(new EarlyError(n, 'Duplicate __proto__ property in object literal not allowed'));
|
||||
});
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceUpdateExpression() {
|
||||
let s = super.reduceUpdateExpression(...arguments);
|
||||
s = s.clearBoundNames();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceUnaryExpression(node) {
|
||||
let s = super.reduceUnaryExpression(...arguments);
|
||||
if (node.operator === 'delete' && node.operand.type === 'IdentifierExpression') {
|
||||
s = s.addStrictError(new EarlyError(node, 'Identifier expressions must not be deleted in strict mode'));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceScript(node) {
|
||||
let s = super.reduceScript(...arguments);
|
||||
s = s.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
s = s.enforceConflictingLexicallyDeclaredNames(s.varDeclaredNames, DUPLICATE_BINDING);
|
||||
s.newTargetExpressions.forEach(n => {
|
||||
s = s.addError(new EarlyError(n, 'new.target must be within function (but not arrow expression) code'));
|
||||
});
|
||||
s = s.enforceFreeContinueStatementErrors(FREE_CONTINUE);
|
||||
s = s.enforceFreeLabeledContinueStatementErrors(UNBOUND_CONTINUE);
|
||||
s = s.enforceFreeBreakStatementErrors(FREE_BREAK);
|
||||
s = s.enforceFreeLabeledBreakStatementErrors(UNBOUND_BREAK);
|
||||
s = s.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
s = s.enforceSuperPropertyExpressions(SUPERPROPERTY_ERROR);
|
||||
if (isStrictFunctionBody(node)) {
|
||||
s = s.enforceStrictErrors();
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceSetter(node, { name, param, body }) {
|
||||
let isSimpleParameterList = node.param.type === 'BindingIdentifier';
|
||||
param = param.observeLexicalDeclaration();
|
||||
param = param.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
body = body.enforceConflictingLexicallyDeclaredNames(param.lexicallyDeclaredNames, DUPLICATE_BINDING);
|
||||
param = param.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
body = body.enforceSuperCallExpressions(SUPERCALL_ERROR);
|
||||
param = param.clearSuperPropertyExpressions();
|
||||
body = body.clearSuperPropertyExpressions();
|
||||
param = param.clearNewTargetExpressions();
|
||||
body = body.clearNewTargetExpressions();
|
||||
if (isStrictFunctionBody(node.body)) {
|
||||
param = param.enforceStrictErrors();
|
||||
body = body.enforceStrictErrors();
|
||||
}
|
||||
let s = super.reduceSetter(node, { name, param, body });
|
||||
if (!isSimpleParameterList && isStrictFunctionBody(node.body)) {
|
||||
s = s.addError(new EarlyError(node, 'Functions with non-simple parameter lists may not contain a "use strict" directive'));
|
||||
}
|
||||
s = s.observeVarBoundary();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceStaticMemberExpression(node) {
|
||||
let s = super.reduceStaticMemberExpression(...arguments);
|
||||
if (node.object.type === 'Super') {
|
||||
s = s.observeSuperPropertyExpression(node);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceSwitchStatement(node, { discriminant, cases }) {
|
||||
let sCases = this.append(...cases);
|
||||
sCases = sCases.functionDeclarationNamesAreLexical();
|
||||
sCases = sCases.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
sCases = sCases.enforceConflictingLexicallyDeclaredNames(sCases.varDeclaredNames, DUPLICATE_BINDING);
|
||||
sCases = sCases.observeLexicalBoundary();
|
||||
let s = this.append(discriminant, sCases);
|
||||
s = s.clearFreeBreakStatements();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) {
|
||||
let sCases = this.append(defaultCase, ...preDefaultCases, ...postDefaultCases);
|
||||
sCases = sCases.functionDeclarationNamesAreLexical();
|
||||
sCases = sCases.enforceDuplicateLexicallyDeclaredNames(DUPLICATE_BINDING);
|
||||
sCases = sCases.enforceConflictingLexicallyDeclaredNames(sCases.varDeclaredNames, DUPLICATE_BINDING);
|
||||
sCases = sCases.observeLexicalBoundary();
|
||||
let s = this.append(discriminant, sCases);
|
||||
s = s.clearFreeBreakStatements();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceVariableDeclaration(node) {
|
||||
let s = super.reduceVariableDeclaration(...arguments);
|
||||
switch (node.kind) {
|
||||
case 'const':
|
||||
case 'let': {
|
||||
s = s.observeLexicalDeclaration();
|
||||
if (s.lexicallyDeclaredNames.has('let')) {
|
||||
s.lexicallyDeclaredNames.get('let').forEach(n => {
|
||||
s = s.addError(new EarlyError(n, 'Lexical declarations must not have a binding named "let"'));
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'var':
|
||||
s = s.observeVarDeclaration();
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceVariableDeclarationStatement(node) {
|
||||
let s = super.reduceVariableDeclarationStatement(...arguments);
|
||||
if (node.declaration.kind === 'const') {
|
||||
node.declaration.declarators.forEach(declarator => {
|
||||
if (declarator.init == null) {
|
||||
s = s.addError(new EarlyError(declarator, 'Constant lexical declarations must have an initialiser'));
|
||||
}
|
||||
});
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceWhileStatement(node) {
|
||||
let s = super.reduceWhileStatement(...arguments);
|
||||
if (isLabelledFunction(node.body)) {
|
||||
s = s.addError(new EarlyError(node.body, 'The body of a while statement must not be a labeled function declaration'));
|
||||
}
|
||||
s = s.clearFreeContinueStatements().clearFreeBreakStatements();
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceWithStatement(node) {
|
||||
let s = super.reduceWithStatement(...arguments);
|
||||
if (isLabelledFunction(node.body)) {
|
||||
s = s.addError(new EarlyError(node.body, 'The body of a with statement must not be a labeled function declaration'));
|
||||
}
|
||||
s = s.addStrictError(new EarlyError(node, 'Strict mode code must not include a with statement'));
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceYieldExpression(node) {
|
||||
let s = super.reduceYieldExpression(...arguments);
|
||||
s = s.observeYieldExpression(node);
|
||||
return s;
|
||||
}
|
||||
|
||||
reduceYieldGeneratorExpression(node) {
|
||||
let s = super.reduceYieldGeneratorExpression(...arguments);
|
||||
s = s.observeYieldExpression(node);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static check(node) {
|
||||
return reduce(new EarlyErrorChecker, node).errors;
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/**
|
||||
* Copyright 2014 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const ErrorMessages = {
|
||||
UNEXPECTED_TOKEN(id) {
|
||||
return `Unexpected token ${JSON.stringify(id)}`;
|
||||
},
|
||||
UNEXPECTED_ILLEGAL_TOKEN(id) {
|
||||
return `Unexpected ${JSON.stringify(id)}`;
|
||||
},
|
||||
UNEXPECTED_ESCAPED_KEYWORD: 'Unexpected escaped keyword',
|
||||
UNEXPECTED_NUMBER: 'Unexpected number',
|
||||
UNEXPECTED_STRING: 'Unexpected string',
|
||||
UNEXPECTED_IDENTIFIER: 'Unexpected identifier',
|
||||
UNEXPECTED_RESERVED_WORD: 'Unexpected reserved word',
|
||||
UNEXPECTED_TEMPLATE: 'Unexpected template',
|
||||
UNEXPECTED_EOS: 'Unexpected end of input',
|
||||
UNEXPECTED_LINE_TERMINATOR: 'Unexpected line terminator',
|
||||
UNEXPECTED_COMMA_AFTER_REST: 'Unexpected comma after rest',
|
||||
UNEXPECTED_REST_PARAMETERS_INITIALIZATION: 'Rest parameter may not have a default initializer',
|
||||
NEWLINE_AFTER_THROW: 'Illegal newline after throw',
|
||||
UNTERMINATED_REGEXP: 'Invalid regular expression: missing /',
|
||||
INVALID_LAST_REST_PARAMETER: 'Rest parameter must be last formal parameter',
|
||||
INVALID_REST_PARAMETERS_INITIALIZATION: 'Rest parameter may not have a default initializer',
|
||||
INVALID_REGEXP_FLAGS: 'Invalid regular expression flags',
|
||||
INVALID_REGEX: 'Invalid regular expression',
|
||||
INVALID_LHS_IN_ASSIGNMENT: 'Invalid left-hand side in assignment',
|
||||
INVALID_LHS_IN_BINDING: 'Invalid left-hand side in binding', // todo collapse messages?
|
||||
INVALID_LHS_IN_FOR_IN: 'Invalid left-hand side in for-in',
|
||||
INVALID_LHS_IN_FOR_OF: 'Invalid left-hand side in for-of',
|
||||
INVALID_LHS_IN_FOR_AWAIT: 'Invalid left-hand side in for-await',
|
||||
INVALID_UPDATE_OPERAND: 'Increment/decrement target must be an identifier or member expression',
|
||||
INVALID_EXPONENTIATION_LHS: 'Unary expressions as the left operand of an exponentation expression ' +
|
||||
'must be disambiguated with parentheses',
|
||||
MULTIPLE_DEFAULTS_IN_SWITCH: 'More than one default clause in switch statement',
|
||||
NO_CATCH_OR_FINALLY: 'Missing catch or finally after try',
|
||||
ILLEGAL_RETURN: 'Illegal return statement',
|
||||
ILLEGAL_ARROW_FUNCTION_PARAMS: 'Illegal arrow function parameter list',
|
||||
INVALID_ASYNC_PARAMS: 'Async function parameters must not contain await expressions',
|
||||
INVALID_VAR_INIT_FOR_IN: 'Invalid variable declaration in for-in statement',
|
||||
INVALID_VAR_INIT_FOR_OF: 'Invalid variable declaration in for-of statement',
|
||||
INVALID_VAR_INIT_FOR_AWAIT: 'Invalid variable declaration in for-await statement',
|
||||
UNINITIALIZED_BINDINGPATTERN_IN_FOR_INIT: 'Binding pattern appears without initializer in for statement init',
|
||||
ILLEGAL_PROPERTY: 'Illegal property initializer',
|
||||
INVALID_ID_BINDING_STRICT_MODE(id) {
|
||||
return `The identifier ${JSON.stringify(id)} must not be in binding position in strict mode`;
|
||||
},
|
||||
INVALID_ID_IN_LABEL_STRICT_MODE(id) {
|
||||
return `The identifier ${JSON.stringify(id)} must not be in label position in strict mode`;
|
||||
},
|
||||
INVALID_ID_IN_EXPRESSION_STRICT_MODE(id) {
|
||||
return `The identifier ${JSON.stringify(id)} must not be in expression position in strict mode`;
|
||||
},
|
||||
INVALID_CALL_TO_SUPER: 'Calls to super must be in the "constructor" method of a class expression ' +
|
||||
'or class declaration that has a superclass',
|
||||
INVALID_DELETE_STRICT_MODE: 'Identifier expressions must not be deleted in strict mode',
|
||||
DUPLICATE_BINDING(id) {
|
||||
return `Duplicate binding ${JSON.stringify(id)}`;
|
||||
},
|
||||
ILLEGAL_ID_IN_LEXICAL_DECLARATION(id) {
|
||||
return `Lexical declarations must not have a binding named ${JSON.stringify(id)}`;
|
||||
},
|
||||
UNITIALIZED_CONST: 'Constant lexical declarations must have an initialiser',
|
||||
ILLEGAL_LABEL_IN_BODY(stmt) {
|
||||
return `The body of a ${stmt} statement must not be a labeled function declaration`;
|
||||
},
|
||||
ILLEGEAL_LABEL_IN_IF: 'The consequent of an if statement must not be a labeled function declaration',
|
||||
ILLEGAL_LABEL_IN_ELSE: 'The alternate of an if statement must not be a labeled function declaration',
|
||||
ILLEGAL_CONTINUE_WITHOUT_ITERATION_WITH_ID(id) {
|
||||
return `Continue statement must be nested within an iteration statement with label ${JSON.stringify(id)}`;
|
||||
},
|
||||
ILLEGAL_CONTINUE_WITHOUT_ITERATION: 'Continue statement must be nested within an iteration statement',
|
||||
ILLEGAL_BREAK_WITHOUT_ITERATION_OR_SWITCH:
|
||||
'Break statement must be nested within an iteration statement or a switch statement',
|
||||
ILLEGAL_WITH_STRICT_MODE: 'Strict mode code must not include a with statement',
|
||||
ILLEGAL_ACCESS_SUPER_MEMBER: 'Member access on super must be in a method',
|
||||
ILLEGAL_SUPER_CALL: 'Calls to super must be in the "constructor" method of a class expression or class declaration that has a superclass',
|
||||
DUPLICATE_LABEL_DECLARATION(label) {
|
||||
return `Label ${JSON.stringify(label)} has already been declared`;
|
||||
},
|
||||
ILLEGAL_BREAK_WITHIN_LABEL(label) {
|
||||
return `Break statement must be nested within a statement with label ${JSON.stringify(label)}`;
|
||||
},
|
||||
ILLEGAL_YIELD_EXPRESSIONS(paramType) {
|
||||
return `${paramType} parameters must not contain yield expressions`;
|
||||
},
|
||||
ILLEGAL_YIELD_IDENTIFIER: '"yield" may not be used as an identifier in this context',
|
||||
ILLEGAL_AWAIT_IDENTIFIER: '"await" may not be used as an identifier in this context',
|
||||
DUPLICATE_CONSTRUCTOR: 'Duplicate constructor method in class',
|
||||
ILLEGAL_CONSTRUCTORS: 'Constructors cannot be async, generators, getters or setters',
|
||||
ILLEGAL_STATIC_CLASS_NAME: 'Static class methods cannot be named "prototype"',
|
||||
NEW_TARGET_ERROR: 'new.target must be within function (but not arrow expression) code',
|
||||
DUPLICATE_EXPORT(id) {
|
||||
return `Duplicate export ${JSON.stringify(id)}`;
|
||||
},
|
||||
UNDECLARED_BINDING(id) {
|
||||
return `Exported binding ${JSON.stringify(id)} is not declared`;
|
||||
},
|
||||
DUPLICATE_PROPTO_PROP: 'Duplicate __proto__ property in object literal not allowed',
|
||||
ILLEGAL_LABEL_FUNC_DECLARATION: 'Labeled FunctionDeclarations are disallowed in strict mode',
|
||||
ILLEGAL_FUNC_DECL_IF: 'FunctionDeclarations in IfStatements are disallowed in strict mode',
|
||||
ILLEGAL_USE_STRICT: 'Functions with non-simple parameter lists may not contain a "use strict" directive',
|
||||
ILLEGAL_EXPORTED_NAME: 'Names of variables used in an export specifier from the current module must be identifiers',
|
||||
NO_OCTALS_IN_TEMPLATES: 'Template literals may not contain octal escape sequences',
|
||||
NO_AWAIT_IN_ASYNC_PARAMS: 'Async arrow parameters may not contain "await"',
|
||||
};
|
||||
@@ -1,149 +0,0 @@
|
||||
/**
|
||||
* Copyright 2016 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { GenericParser } from './parser';
|
||||
import { JsError } from './tokenizer';
|
||||
import { EarlyErrorChecker } from './early-errors';
|
||||
import { isLineTerminator } from './utils';
|
||||
|
||||
class ParserWithLocation extends GenericParser {
|
||||
constructor(source) {
|
||||
super(source);
|
||||
this.locations = new WeakMap;
|
||||
this.comments = [];
|
||||
}
|
||||
|
||||
startNode() {
|
||||
return this.getLocation();
|
||||
}
|
||||
|
||||
finishNode(node, start) {
|
||||
if (node.type === 'Script' || node.type === 'Module') {
|
||||
this.locations.set(node, {
|
||||
start: { line: 1, column: 0, offset: 0 },
|
||||
end: this.getLocation(),
|
||||
});
|
||||
return node;
|
||||
}
|
||||
if (node.type === 'TemplateExpression') {
|
||||
// Adjust TemplateElements to not include surrounding backticks or braces
|
||||
for (let i = 0; i < node.elements.length; i += 2) {
|
||||
const endAdjustment = i < node.elements.length - 1 ? 2 : 1; // discard '${' or '`' respectively
|
||||
const element = node.elements[i];
|
||||
const location = this.locations.get(element);
|
||||
this.locations.set(element, {
|
||||
start: { line: location.start.line, column: location.start.column + 1, offset: location.start.offset + 1 }, // discard '}' or '`'
|
||||
end: { line: location.end.line, column: location.end.column - endAdjustment, offset: location.end.offset - endAdjustment },
|
||||
});
|
||||
}
|
||||
}
|
||||
this.locations.set(node, {
|
||||
start,
|
||||
end: this.getLastTokenEndLocation(),
|
||||
});
|
||||
return node;
|
||||
}
|
||||
|
||||
copyNode(src, dest) {
|
||||
this.locations.set(dest, this.locations.get(src)); // todo check undefined
|
||||
return dest;
|
||||
}
|
||||
|
||||
skipSingleLineComment(offset) {
|
||||
// We're actually extending the *tokenizer*, here.
|
||||
const start = {
|
||||
line: this.line + 1,
|
||||
column: this.index - this.lineStart,
|
||||
offset: this.index,
|
||||
};
|
||||
const c = this.source[this.index];
|
||||
const type = c === '/' ? 'SingleLine' : c === '<' ? 'HTMLOpen' : 'HTMLClose';
|
||||
|
||||
super.skipSingleLineComment(offset);
|
||||
|
||||
const end = {
|
||||
line: this.line + 1,
|
||||
column: this.index - this.lineStart,
|
||||
offset: this.index,
|
||||
};
|
||||
const trailingLineTerminatorCharacters = this.source[this.index - 2] === '\r' ? 2 : isLineTerminator(this.source.charCodeAt(this.index - 1)) ? 1 : 0;
|
||||
const text = this.source.substring(start.offset + offset, end.offset - trailingLineTerminatorCharacters);
|
||||
|
||||
this.comments.push({ text, type, start, end });
|
||||
}
|
||||
|
||||
skipMultiLineComment() {
|
||||
const start = {
|
||||
line: this.line + 1,
|
||||
column: this.index - this.lineStart,
|
||||
offset: this.index,
|
||||
};
|
||||
const type = 'MultiLine';
|
||||
|
||||
const retval = super.skipMultiLineComment();
|
||||
|
||||
const end = {
|
||||
line: this.line + 1,
|
||||
column: this.index - this.lineStart,
|
||||
offset: this.index,
|
||||
};
|
||||
const text = this.source.substring(start.offset + 2, end.offset - 2);
|
||||
|
||||
this.comments.push({ text, type, start, end });
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
function generateInterface(parsingFunctionName) {
|
||||
return function parse(code, { earlyErrors = true } = {}) {
|
||||
let parser = new GenericParser(code);
|
||||
let tree = parser[parsingFunctionName]();
|
||||
if (earlyErrors) {
|
||||
let errors = EarlyErrorChecker.check(tree);
|
||||
// for now, just throw the first error; we will handle multiple errors later
|
||||
if (errors.length > 0) {
|
||||
throw new JsError(0, 1, 0, errors[0].message);
|
||||
}
|
||||
}
|
||||
return tree;
|
||||
};
|
||||
}
|
||||
|
||||
function generateInterfaceWithLocation(parsingFunctionName) {
|
||||
return function parse(code, { earlyErrors = true } = {}) {
|
||||
let parser = new ParserWithLocation(code);
|
||||
let tree = parser[parsingFunctionName]();
|
||||
if (earlyErrors) {
|
||||
let errors = EarlyErrorChecker.check(tree);
|
||||
// for now, just throw the first error; we will handle multiple errors later
|
||||
if (errors.length > 0) {
|
||||
let { node, message } = errors[0];
|
||||
let { offset, line, column } = parser.locations.get(node).start;
|
||||
throw new JsError(offset, line, column, message);
|
||||
}
|
||||
}
|
||||
return { tree, locations: parser.locations, comments: parser.comments };
|
||||
};
|
||||
}
|
||||
|
||||
export const parseModule = generateInterface('parseModule');
|
||||
export const parseScript = generateInterface('parseScript');
|
||||
export const parseModuleWithLocation = generateInterfaceWithLocation('parseModule');
|
||||
export const parseScriptWithLocation = generateInterfaceWithLocation('parseScript');
|
||||
export default parseScript;
|
||||
export { EarlyErrorChecker, GenericParser, ParserWithLocation };
|
||||
export { default as Tokenizer, TokenClass, TokenType } from './tokenizer';
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,105 +0,0 @@
|
||||
/**
|
||||
* Copyright 2017 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { whitespaceArray, whitespaceBool, idStartLargeRegex, idStartBool, idContinueLargeRegex, idContinueBool } from './unicode';
|
||||
|
||||
|
||||
const strictReservedWords = [
|
||||
'null',
|
||||
'true',
|
||||
'false',
|
||||
|
||||
'implements',
|
||||
'interface',
|
||||
'package',
|
||||
'private',
|
||||
'protected',
|
||||
'public',
|
||||
'static',
|
||||
'let',
|
||||
|
||||
'if',
|
||||
'in',
|
||||
'do',
|
||||
'var',
|
||||
'for',
|
||||
'new',
|
||||
'try',
|
||||
'this',
|
||||
'else',
|
||||
'case',
|
||||
'void',
|
||||
'with',
|
||||
'enum',
|
||||
'while',
|
||||
'break',
|
||||
'catch',
|
||||
'throw',
|
||||
'const',
|
||||
'yield',
|
||||
'class',
|
||||
'super',
|
||||
'return',
|
||||
'typeof',
|
||||
'delete',
|
||||
'switch',
|
||||
'export',
|
||||
'import',
|
||||
'default',
|
||||
'finally',
|
||||
'extends',
|
||||
'function',
|
||||
'continue',
|
||||
'debugger',
|
||||
'instanceof',
|
||||
];
|
||||
|
||||
export function isStrictModeReservedWord(id) {
|
||||
return strictReservedWords.indexOf(id) !== -1;
|
||||
}
|
||||
|
||||
export function isWhiteSpace(ch) {
|
||||
return ch < 128 ? whitespaceBool[ch] : ch === 0xA0 || ch > 0x167F && whitespaceArray.indexOf(ch) !== -1;
|
||||
}
|
||||
|
||||
export function isLineTerminator(ch) {
|
||||
return ch === 0x0A || ch === 0x0D || ch === 0x2028 || ch === 0x2029;
|
||||
}
|
||||
|
||||
export function isIdentifierStart(ch) {
|
||||
return ch < 128 ? idStartBool[ch] : idStartLargeRegex.test(String.fromCodePoint(ch));
|
||||
}
|
||||
|
||||
export function isIdentifierPart(ch) {
|
||||
return ch < 128 ? idContinueBool[ch] : idContinueLargeRegex.test(String.fromCodePoint(ch));
|
||||
}
|
||||
|
||||
export function isDecimalDigit(ch) {
|
||||
return ch >= 48 && ch <= 57;
|
||||
}
|
||||
|
||||
export function getHexValue(rune) {
|
||||
if (rune >= '0' && rune <= '9') {
|
||||
return rune.charCodeAt(0) - 48;
|
||||
}
|
||||
if (rune >= 'a' && rune <= 'f') {
|
||||
return rune.charCodeAt(0) - 87;
|
||||
}
|
||||
if (rune >= 'A' && rune <= 'F') {
|
||||
return rune.charCodeAt(0) - 55;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1,418 +0,0 @@
|
||||
// Generated by generate-adapt.js
|
||||
/**
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as Shift from 'shift-ast';
|
||||
|
||||
export default (fn, reducer) => ({
|
||||
__proto__: reducer,
|
||||
|
||||
reduceArrayAssignmentTarget(node, data) {
|
||||
return fn(super.reduceArrayAssignmentTarget(node, data), node);
|
||||
},
|
||||
|
||||
reduceArrayBinding(node, data) {
|
||||
return fn(super.reduceArrayBinding(node, data), node);
|
||||
},
|
||||
|
||||
reduceArrayExpression(node, data) {
|
||||
return fn(super.reduceArrayExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceArrowExpression(node, data) {
|
||||
return fn(super.reduceArrowExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceAssignmentExpression(node, data) {
|
||||
return fn(super.reduceAssignmentExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceAssignmentTargetIdentifier(node, data) {
|
||||
return fn(super.reduceAssignmentTargetIdentifier(node, data), node);
|
||||
},
|
||||
|
||||
reduceAssignmentTargetPropertyIdentifier(node, data) {
|
||||
return fn(super.reduceAssignmentTargetPropertyIdentifier(node, data), node);
|
||||
},
|
||||
|
||||
reduceAssignmentTargetPropertyProperty(node, data) {
|
||||
return fn(super.reduceAssignmentTargetPropertyProperty(node, data), node);
|
||||
},
|
||||
|
||||
reduceAssignmentTargetWithDefault(node, data) {
|
||||
return fn(super.reduceAssignmentTargetWithDefault(node, data), node);
|
||||
},
|
||||
|
||||
reduceAwaitExpression(node, data) {
|
||||
return fn(super.reduceAwaitExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceBinaryExpression(node, data) {
|
||||
return fn(super.reduceBinaryExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceBindingIdentifier(node, data) {
|
||||
return fn(super.reduceBindingIdentifier(node, data), node);
|
||||
},
|
||||
|
||||
reduceBindingPropertyIdentifier(node, data) {
|
||||
return fn(super.reduceBindingPropertyIdentifier(node, data), node);
|
||||
},
|
||||
|
||||
reduceBindingPropertyProperty(node, data) {
|
||||
return fn(super.reduceBindingPropertyProperty(node, data), node);
|
||||
},
|
||||
|
||||
reduceBindingWithDefault(node, data) {
|
||||
return fn(super.reduceBindingWithDefault(node, data), node);
|
||||
},
|
||||
|
||||
reduceBlock(node, data) {
|
||||
return fn(super.reduceBlock(node, data), node);
|
||||
},
|
||||
|
||||
reduceBlockStatement(node, data) {
|
||||
return fn(super.reduceBlockStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceBreakStatement(node, data) {
|
||||
return fn(super.reduceBreakStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceCallExpression(node, data) {
|
||||
return fn(super.reduceCallExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceCatchClause(node, data) {
|
||||
return fn(super.reduceCatchClause(node, data), node);
|
||||
},
|
||||
|
||||
reduceClassDeclaration(node, data) {
|
||||
return fn(super.reduceClassDeclaration(node, data), node);
|
||||
},
|
||||
|
||||
reduceClassElement(node, data) {
|
||||
return fn(super.reduceClassElement(node, data), node);
|
||||
},
|
||||
|
||||
reduceClassExpression(node, data) {
|
||||
return fn(super.reduceClassExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceCompoundAssignmentExpression(node, data) {
|
||||
return fn(super.reduceCompoundAssignmentExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceComputedMemberAssignmentTarget(node, data) {
|
||||
return fn(super.reduceComputedMemberAssignmentTarget(node, data), node);
|
||||
},
|
||||
|
||||
reduceComputedMemberExpression(node, data) {
|
||||
return fn(super.reduceComputedMemberExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceComputedPropertyName(node, data) {
|
||||
return fn(super.reduceComputedPropertyName(node, data), node);
|
||||
},
|
||||
|
||||
reduceConditionalExpression(node, data) {
|
||||
return fn(super.reduceConditionalExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceContinueStatement(node, data) {
|
||||
return fn(super.reduceContinueStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceDataProperty(node, data) {
|
||||
return fn(super.reduceDataProperty(node, data), node);
|
||||
},
|
||||
|
||||
reduceDebuggerStatement(node, data) {
|
||||
return fn(super.reduceDebuggerStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceDirective(node, data) {
|
||||
return fn(super.reduceDirective(node, data), node);
|
||||
},
|
||||
|
||||
reduceDoWhileStatement(node, data) {
|
||||
return fn(super.reduceDoWhileStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceEmptyStatement(node, data) {
|
||||
return fn(super.reduceEmptyStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceExport(node, data) {
|
||||
return fn(super.reduceExport(node, data), node);
|
||||
},
|
||||
|
||||
reduceExportAllFrom(node, data) {
|
||||
return fn(super.reduceExportAllFrom(node, data), node);
|
||||
},
|
||||
|
||||
reduceExportDefault(node, data) {
|
||||
return fn(super.reduceExportDefault(node, data), node);
|
||||
},
|
||||
|
||||
reduceExportFrom(node, data) {
|
||||
return fn(super.reduceExportFrom(node, data), node);
|
||||
},
|
||||
|
||||
reduceExportFromSpecifier(node, data) {
|
||||
return fn(super.reduceExportFromSpecifier(node, data), node);
|
||||
},
|
||||
|
||||
reduceExportLocalSpecifier(node, data) {
|
||||
return fn(super.reduceExportLocalSpecifier(node, data), node);
|
||||
},
|
||||
|
||||
reduceExportLocals(node, data) {
|
||||
return fn(super.reduceExportLocals(node, data), node);
|
||||
},
|
||||
|
||||
reduceExpressionStatement(node, data) {
|
||||
return fn(super.reduceExpressionStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceForAwaitStatement(node, data) {
|
||||
return fn(super.reduceForAwaitStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceForInStatement(node, data) {
|
||||
return fn(super.reduceForInStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceForOfStatement(node, data) {
|
||||
return fn(super.reduceForOfStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceForStatement(node, data) {
|
||||
return fn(super.reduceForStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceFormalParameters(node, data) {
|
||||
return fn(super.reduceFormalParameters(node, data), node);
|
||||
},
|
||||
|
||||
reduceFunctionBody(node, data) {
|
||||
return fn(super.reduceFunctionBody(node, data), node);
|
||||
},
|
||||
|
||||
reduceFunctionDeclaration(node, data) {
|
||||
return fn(super.reduceFunctionDeclaration(node, data), node);
|
||||
},
|
||||
|
||||
reduceFunctionExpression(node, data) {
|
||||
return fn(super.reduceFunctionExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceGetter(node, data) {
|
||||
return fn(super.reduceGetter(node, data), node);
|
||||
},
|
||||
|
||||
reduceIdentifierExpression(node, data) {
|
||||
return fn(super.reduceIdentifierExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceIfStatement(node, data) {
|
||||
return fn(super.reduceIfStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceImport(node, data) {
|
||||
return fn(super.reduceImport(node, data), node);
|
||||
},
|
||||
|
||||
reduceImportNamespace(node, data) {
|
||||
return fn(super.reduceImportNamespace(node, data), node);
|
||||
},
|
||||
|
||||
reduceImportSpecifier(node, data) {
|
||||
return fn(super.reduceImportSpecifier(node, data), node);
|
||||
},
|
||||
|
||||
reduceLabeledStatement(node, data) {
|
||||
return fn(super.reduceLabeledStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceLiteralBooleanExpression(node, data) {
|
||||
return fn(super.reduceLiteralBooleanExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceLiteralInfinityExpression(node, data) {
|
||||
return fn(super.reduceLiteralInfinityExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceLiteralNullExpression(node, data) {
|
||||
return fn(super.reduceLiteralNullExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceLiteralNumericExpression(node, data) {
|
||||
return fn(super.reduceLiteralNumericExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceLiteralRegExpExpression(node, data) {
|
||||
return fn(super.reduceLiteralRegExpExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceLiteralStringExpression(node, data) {
|
||||
return fn(super.reduceLiteralStringExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceMethod(node, data) {
|
||||
return fn(super.reduceMethod(node, data), node);
|
||||
},
|
||||
|
||||
reduceModule(node, data) {
|
||||
return fn(super.reduceModule(node, data), node);
|
||||
},
|
||||
|
||||
reduceNewExpression(node, data) {
|
||||
return fn(super.reduceNewExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceNewTargetExpression(node, data) {
|
||||
return fn(super.reduceNewTargetExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceObjectAssignmentTarget(node, data) {
|
||||
return fn(super.reduceObjectAssignmentTarget(node, data), node);
|
||||
},
|
||||
|
||||
reduceObjectBinding(node, data) {
|
||||
return fn(super.reduceObjectBinding(node, data), node);
|
||||
},
|
||||
|
||||
reduceObjectExpression(node, data) {
|
||||
return fn(super.reduceObjectExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceReturnStatement(node, data) {
|
||||
return fn(super.reduceReturnStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceScript(node, data) {
|
||||
return fn(super.reduceScript(node, data), node);
|
||||
},
|
||||
|
||||
reduceSetter(node, data) {
|
||||
return fn(super.reduceSetter(node, data), node);
|
||||
},
|
||||
|
||||
reduceShorthandProperty(node, data) {
|
||||
return fn(super.reduceShorthandProperty(node, data), node);
|
||||
},
|
||||
|
||||
reduceSpreadElement(node, data) {
|
||||
return fn(super.reduceSpreadElement(node, data), node);
|
||||
},
|
||||
|
||||
reduceSpreadProperty(node, data) {
|
||||
return fn(super.reduceSpreadProperty(node, data), node);
|
||||
},
|
||||
|
||||
reduceStaticMemberAssignmentTarget(node, data) {
|
||||
return fn(super.reduceStaticMemberAssignmentTarget(node, data), node);
|
||||
},
|
||||
|
||||
reduceStaticMemberExpression(node, data) {
|
||||
return fn(super.reduceStaticMemberExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceStaticPropertyName(node, data) {
|
||||
return fn(super.reduceStaticPropertyName(node, data), node);
|
||||
},
|
||||
|
||||
reduceSuper(node, data) {
|
||||
return fn(super.reduceSuper(node, data), node);
|
||||
},
|
||||
|
||||
reduceSwitchCase(node, data) {
|
||||
return fn(super.reduceSwitchCase(node, data), node);
|
||||
},
|
||||
|
||||
reduceSwitchDefault(node, data) {
|
||||
return fn(super.reduceSwitchDefault(node, data), node);
|
||||
},
|
||||
|
||||
reduceSwitchStatement(node, data) {
|
||||
return fn(super.reduceSwitchStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceSwitchStatementWithDefault(node, data) {
|
||||
return fn(super.reduceSwitchStatementWithDefault(node, data), node);
|
||||
},
|
||||
|
||||
reduceTemplateElement(node, data) {
|
||||
return fn(super.reduceTemplateElement(node, data), node);
|
||||
},
|
||||
|
||||
reduceTemplateExpression(node, data) {
|
||||
return fn(super.reduceTemplateExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceThisExpression(node, data) {
|
||||
return fn(super.reduceThisExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceThrowStatement(node, data) {
|
||||
return fn(super.reduceThrowStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceTryCatchStatement(node, data) {
|
||||
return fn(super.reduceTryCatchStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceTryFinallyStatement(node, data) {
|
||||
return fn(super.reduceTryFinallyStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceUnaryExpression(node, data) {
|
||||
return fn(super.reduceUnaryExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceUpdateExpression(node, data) {
|
||||
return fn(super.reduceUpdateExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceVariableDeclaration(node, data) {
|
||||
return fn(super.reduceVariableDeclaration(node, data), node);
|
||||
},
|
||||
|
||||
reduceVariableDeclarationStatement(node, data) {
|
||||
return fn(super.reduceVariableDeclarationStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceVariableDeclarator(node, data) {
|
||||
return fn(super.reduceVariableDeclarator(node, data), node);
|
||||
},
|
||||
|
||||
reduceWhileStatement(node, data) {
|
||||
return fn(super.reduceWhileStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceWithStatement(node, data) {
|
||||
return fn(super.reduceWithStatement(node, data), node);
|
||||
},
|
||||
|
||||
reduceYieldExpression(node, data) {
|
||||
return fn(super.reduceYieldExpression(node, data), node);
|
||||
},
|
||||
|
||||
reduceYieldGeneratorExpression(node, data) {
|
||||
return fn(super.reduceYieldGeneratorExpression(node, data), node);
|
||||
},
|
||||
});
|
||||
@@ -1,416 +0,0 @@
|
||||
// Generated by generate-clone-reducer.js
|
||||
/**
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as Shift from 'shift-ast';
|
||||
|
||||
export default class CloneReducer {
|
||||
reduceArrayAssignmentTarget(node, { elements, rest }) {
|
||||
return new Shift.ArrayAssignmentTarget({ elements, rest });
|
||||
}
|
||||
|
||||
reduceArrayBinding(node, { elements, rest }) {
|
||||
return new Shift.ArrayBinding({ elements, rest });
|
||||
}
|
||||
|
||||
reduceArrayExpression(node, { elements }) {
|
||||
return new Shift.ArrayExpression({ elements });
|
||||
}
|
||||
|
||||
reduceArrowExpression(node, { params, body }) {
|
||||
return new Shift.ArrowExpression({ isAsync: node.isAsync, params, body });
|
||||
}
|
||||
|
||||
reduceAssignmentExpression(node, { binding, expression }) {
|
||||
return new Shift.AssignmentExpression({ binding, expression });
|
||||
}
|
||||
|
||||
reduceAssignmentTargetIdentifier(node) {
|
||||
return new Shift.AssignmentTargetIdentifier({ name: node.name });
|
||||
}
|
||||
|
||||
reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) {
|
||||
return new Shift.AssignmentTargetPropertyIdentifier({ binding, init });
|
||||
}
|
||||
|
||||
reduceAssignmentTargetPropertyProperty(node, { name, binding }) {
|
||||
return new Shift.AssignmentTargetPropertyProperty({ name, binding });
|
||||
}
|
||||
|
||||
reduceAssignmentTargetWithDefault(node, { binding, init }) {
|
||||
return new Shift.AssignmentTargetWithDefault({ binding, init });
|
||||
}
|
||||
|
||||
reduceAwaitExpression(node, { expression }) {
|
||||
return new Shift.AwaitExpression({ expression });
|
||||
}
|
||||
|
||||
reduceBinaryExpression(node, { left, right }) {
|
||||
return new Shift.BinaryExpression({ left, operator: node.operator, right });
|
||||
}
|
||||
|
||||
reduceBindingIdentifier(node) {
|
||||
return new Shift.BindingIdentifier({ name: node.name });
|
||||
}
|
||||
|
||||
reduceBindingPropertyIdentifier(node, { binding, init }) {
|
||||
return new Shift.BindingPropertyIdentifier({ binding, init });
|
||||
}
|
||||
|
||||
reduceBindingPropertyProperty(node, { name, binding }) {
|
||||
return new Shift.BindingPropertyProperty({ name, binding });
|
||||
}
|
||||
|
||||
reduceBindingWithDefault(node, { binding, init }) {
|
||||
return new Shift.BindingWithDefault({ binding, init });
|
||||
}
|
||||
|
||||
reduceBlock(node, { statements }) {
|
||||
return new Shift.Block({ statements });
|
||||
}
|
||||
|
||||
reduceBlockStatement(node, { block }) {
|
||||
return new Shift.BlockStatement({ block });
|
||||
}
|
||||
|
||||
reduceBreakStatement(node) {
|
||||
return new Shift.BreakStatement({ label: node.label });
|
||||
}
|
||||
|
||||
reduceCallExpression(node, { callee, arguments: _arguments }) {
|
||||
return new Shift.CallExpression({ callee, arguments: _arguments });
|
||||
}
|
||||
|
||||
reduceCatchClause(node, { binding, body }) {
|
||||
return new Shift.CatchClause({ binding, body });
|
||||
}
|
||||
|
||||
reduceClassDeclaration(node, { name, super: _super, elements }) {
|
||||
return new Shift.ClassDeclaration({ name, super: _super, elements });
|
||||
}
|
||||
|
||||
reduceClassElement(node, { method }) {
|
||||
return new Shift.ClassElement({ isStatic: node.isStatic, method });
|
||||
}
|
||||
|
||||
reduceClassExpression(node, { name, super: _super, elements }) {
|
||||
return new Shift.ClassExpression({ name, super: _super, elements });
|
||||
}
|
||||
|
||||
reduceCompoundAssignmentExpression(node, { binding, expression }) {
|
||||
return new Shift.CompoundAssignmentExpression({ binding, operator: node.operator, expression });
|
||||
}
|
||||
|
||||
reduceComputedMemberAssignmentTarget(node, { object, expression }) {
|
||||
return new Shift.ComputedMemberAssignmentTarget({ object, expression });
|
||||
}
|
||||
|
||||
reduceComputedMemberExpression(node, { object, expression }) {
|
||||
return new Shift.ComputedMemberExpression({ object, expression });
|
||||
}
|
||||
|
||||
reduceComputedPropertyName(node, { expression }) {
|
||||
return new Shift.ComputedPropertyName({ expression });
|
||||
}
|
||||
|
||||
reduceConditionalExpression(node, { test, consequent, alternate }) {
|
||||
return new Shift.ConditionalExpression({ test, consequent, alternate });
|
||||
}
|
||||
|
||||
reduceContinueStatement(node) {
|
||||
return new Shift.ContinueStatement({ label: node.label });
|
||||
}
|
||||
|
||||
reduceDataProperty(node, { name, expression }) {
|
||||
return new Shift.DataProperty({ name, expression });
|
||||
}
|
||||
|
||||
reduceDebuggerStatement(node) {
|
||||
return new Shift.DebuggerStatement;
|
||||
}
|
||||
|
||||
reduceDirective(node) {
|
||||
return new Shift.Directive({ rawValue: node.rawValue });
|
||||
}
|
||||
|
||||
reduceDoWhileStatement(node, { body, test }) {
|
||||
return new Shift.DoWhileStatement({ body, test });
|
||||
}
|
||||
|
||||
reduceEmptyStatement(node) {
|
||||
return new Shift.EmptyStatement;
|
||||
}
|
||||
|
||||
reduceExport(node, { declaration }) {
|
||||
return new Shift.Export({ declaration });
|
||||
}
|
||||
|
||||
reduceExportAllFrom(node) {
|
||||
return new Shift.ExportAllFrom({ moduleSpecifier: node.moduleSpecifier });
|
||||
}
|
||||
|
||||
reduceExportDefault(node, { body }) {
|
||||
return new Shift.ExportDefault({ body });
|
||||
}
|
||||
|
||||
reduceExportFrom(node, { namedExports }) {
|
||||
return new Shift.ExportFrom({ namedExports, moduleSpecifier: node.moduleSpecifier });
|
||||
}
|
||||
|
||||
reduceExportFromSpecifier(node) {
|
||||
return new Shift.ExportFromSpecifier({ name: node.name, exportedName: node.exportedName });
|
||||
}
|
||||
|
||||
reduceExportLocalSpecifier(node, { name }) {
|
||||
return new Shift.ExportLocalSpecifier({ name, exportedName: node.exportedName });
|
||||
}
|
||||
|
||||
reduceExportLocals(node, { namedExports }) {
|
||||
return new Shift.ExportLocals({ namedExports });
|
||||
}
|
||||
|
||||
reduceExpressionStatement(node, { expression }) {
|
||||
return new Shift.ExpressionStatement({ expression });
|
||||
}
|
||||
|
||||
reduceForAwaitStatement(node, { left, right, body }) {
|
||||
return new Shift.ForAwaitStatement({ left, right, body });
|
||||
}
|
||||
|
||||
reduceForInStatement(node, { left, right, body }) {
|
||||
return new Shift.ForInStatement({ left, right, body });
|
||||
}
|
||||
|
||||
reduceForOfStatement(node, { left, right, body }) {
|
||||
return new Shift.ForOfStatement({ left, right, body });
|
||||
}
|
||||
|
||||
reduceForStatement(node, { init, test, update, body }) {
|
||||
return new Shift.ForStatement({ init, test, update, body });
|
||||
}
|
||||
|
||||
reduceFormalParameters(node, { items, rest }) {
|
||||
return new Shift.FormalParameters({ items, rest });
|
||||
}
|
||||
|
||||
reduceFunctionBody(node, { directives, statements }) {
|
||||
return new Shift.FunctionBody({ directives, statements });
|
||||
}
|
||||
|
||||
reduceFunctionDeclaration(node, { name, params, body }) {
|
||||
return new Shift.FunctionDeclaration({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body });
|
||||
}
|
||||
|
||||
reduceFunctionExpression(node, { name, params, body }) {
|
||||
return new Shift.FunctionExpression({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body });
|
||||
}
|
||||
|
||||
reduceGetter(node, { name, body }) {
|
||||
return new Shift.Getter({ name, body });
|
||||
}
|
||||
|
||||
reduceIdentifierExpression(node) {
|
||||
return new Shift.IdentifierExpression({ name: node.name });
|
||||
}
|
||||
|
||||
reduceIfStatement(node, { test, consequent, alternate }) {
|
||||
return new Shift.IfStatement({ test, consequent, alternate });
|
||||
}
|
||||
|
||||
reduceImport(node, { defaultBinding, namedImports }) {
|
||||
return new Shift.Import({ defaultBinding, namedImports, moduleSpecifier: node.moduleSpecifier });
|
||||
}
|
||||
|
||||
reduceImportNamespace(node, { defaultBinding, namespaceBinding }) {
|
||||
return new Shift.ImportNamespace({ defaultBinding, namespaceBinding, moduleSpecifier: node.moduleSpecifier });
|
||||
}
|
||||
|
||||
reduceImportSpecifier(node, { binding }) {
|
||||
return new Shift.ImportSpecifier({ name: node.name, binding });
|
||||
}
|
||||
|
||||
reduceLabeledStatement(node, { body }) {
|
||||
return new Shift.LabeledStatement({ label: node.label, body });
|
||||
}
|
||||
|
||||
reduceLiteralBooleanExpression(node) {
|
||||
return new Shift.LiteralBooleanExpression({ value: node.value });
|
||||
}
|
||||
|
||||
reduceLiteralInfinityExpression(node) {
|
||||
return new Shift.LiteralInfinityExpression;
|
||||
}
|
||||
|
||||
reduceLiteralNullExpression(node) {
|
||||
return new Shift.LiteralNullExpression;
|
||||
}
|
||||
|
||||
reduceLiteralNumericExpression(node) {
|
||||
return new Shift.LiteralNumericExpression({ value: node.value });
|
||||
}
|
||||
|
||||
reduceLiteralRegExpExpression(node) {
|
||||
return new Shift.LiteralRegExpExpression({ pattern: node.pattern, global: node.global, ignoreCase: node.ignoreCase, multiLine: node.multiLine, dotAll: node.dotAll, unicode: node.unicode, sticky: node.sticky });
|
||||
}
|
||||
|
||||
reduceLiteralStringExpression(node) {
|
||||
return new Shift.LiteralStringExpression({ value: node.value });
|
||||
}
|
||||
|
||||
reduceMethod(node, { name, params, body }) {
|
||||
return new Shift.Method({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body });
|
||||
}
|
||||
|
||||
reduceModule(node, { directives, items }) {
|
||||
return new Shift.Module({ directives, items });
|
||||
}
|
||||
|
||||
reduceNewExpression(node, { callee, arguments: _arguments }) {
|
||||
return new Shift.NewExpression({ callee, arguments: _arguments });
|
||||
}
|
||||
|
||||
reduceNewTargetExpression(node) {
|
||||
return new Shift.NewTargetExpression;
|
||||
}
|
||||
|
||||
reduceObjectAssignmentTarget(node, { properties, rest }) {
|
||||
return new Shift.ObjectAssignmentTarget({ properties, rest });
|
||||
}
|
||||
|
||||
reduceObjectBinding(node, { properties, rest }) {
|
||||
return new Shift.ObjectBinding({ properties, rest });
|
||||
}
|
||||
|
||||
reduceObjectExpression(node, { properties }) {
|
||||
return new Shift.ObjectExpression({ properties });
|
||||
}
|
||||
|
||||
reduceReturnStatement(node, { expression }) {
|
||||
return new Shift.ReturnStatement({ expression });
|
||||
}
|
||||
|
||||
reduceScript(node, { directives, statements }) {
|
||||
return new Shift.Script({ directives, statements });
|
||||
}
|
||||
|
||||
reduceSetter(node, { name, param, body }) {
|
||||
return new Shift.Setter({ name, param, body });
|
||||
}
|
||||
|
||||
reduceShorthandProperty(node, { name }) {
|
||||
return new Shift.ShorthandProperty({ name });
|
||||
}
|
||||
|
||||
reduceSpreadElement(node, { expression }) {
|
||||
return new Shift.SpreadElement({ expression });
|
||||
}
|
||||
|
||||
reduceSpreadProperty(node, { expression }) {
|
||||
return new Shift.SpreadProperty({ expression });
|
||||
}
|
||||
|
||||
reduceStaticMemberAssignmentTarget(node, { object }) {
|
||||
return new Shift.StaticMemberAssignmentTarget({ object, property: node.property });
|
||||
}
|
||||
|
||||
reduceStaticMemberExpression(node, { object }) {
|
||||
return new Shift.StaticMemberExpression({ object, property: node.property });
|
||||
}
|
||||
|
||||
reduceStaticPropertyName(node) {
|
||||
return new Shift.StaticPropertyName({ value: node.value });
|
||||
}
|
||||
|
||||
reduceSuper(node) {
|
||||
return new Shift.Super;
|
||||
}
|
||||
|
||||
reduceSwitchCase(node, { test, consequent }) {
|
||||
return new Shift.SwitchCase({ test, consequent });
|
||||
}
|
||||
|
||||
reduceSwitchDefault(node, { consequent }) {
|
||||
return new Shift.SwitchDefault({ consequent });
|
||||
}
|
||||
|
||||
reduceSwitchStatement(node, { discriminant, cases }) {
|
||||
return new Shift.SwitchStatement({ discriminant, cases });
|
||||
}
|
||||
|
||||
reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) {
|
||||
return new Shift.SwitchStatementWithDefault({ discriminant, preDefaultCases, defaultCase, postDefaultCases });
|
||||
}
|
||||
|
||||
reduceTemplateElement(node) {
|
||||
return new Shift.TemplateElement({ rawValue: node.rawValue });
|
||||
}
|
||||
|
||||
reduceTemplateExpression(node, { tag, elements }) {
|
||||
return new Shift.TemplateExpression({ tag, elements });
|
||||
}
|
||||
|
||||
reduceThisExpression(node) {
|
||||
return new Shift.ThisExpression;
|
||||
}
|
||||
|
||||
reduceThrowStatement(node, { expression }) {
|
||||
return new Shift.ThrowStatement({ expression });
|
||||
}
|
||||
|
||||
reduceTryCatchStatement(node, { body, catchClause }) {
|
||||
return new Shift.TryCatchStatement({ body, catchClause });
|
||||
}
|
||||
|
||||
reduceTryFinallyStatement(node, { body, catchClause, finalizer }) {
|
||||
return new Shift.TryFinallyStatement({ body, catchClause, finalizer });
|
||||
}
|
||||
|
||||
reduceUnaryExpression(node, { operand }) {
|
||||
return new Shift.UnaryExpression({ operator: node.operator, operand });
|
||||
}
|
||||
|
||||
reduceUpdateExpression(node, { operand }) {
|
||||
return new Shift.UpdateExpression({ isPrefix: node.isPrefix, operator: node.operator, operand });
|
||||
}
|
||||
|
||||
reduceVariableDeclaration(node, { declarators }) {
|
||||
return new Shift.VariableDeclaration({ kind: node.kind, declarators });
|
||||
}
|
||||
|
||||
reduceVariableDeclarationStatement(node, { declaration }) {
|
||||
return new Shift.VariableDeclarationStatement({ declaration });
|
||||
}
|
||||
|
||||
reduceVariableDeclarator(node, { binding, init }) {
|
||||
return new Shift.VariableDeclarator({ binding, init });
|
||||
}
|
||||
|
||||
reduceWhileStatement(node, { test, body }) {
|
||||
return new Shift.WhileStatement({ test, body });
|
||||
}
|
||||
|
||||
reduceWithStatement(node, { object, body }) {
|
||||
return new Shift.WithStatement({ object, body });
|
||||
}
|
||||
|
||||
reduceYieldExpression(node, { expression }) {
|
||||
return new Shift.YieldExpression({ expression });
|
||||
}
|
||||
|
||||
reduceYieldGeneratorExpression(node, { expression }) {
|
||||
return new Shift.YieldGeneratorExpression({ expression });
|
||||
}
|
||||
}
|
||||
@@ -1,418 +0,0 @@
|
||||
// Generated by generate-director.js
|
||||
/**
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const director = {
|
||||
ArrayAssignmentTarget(reducer, node) {
|
||||
return reducer.reduceArrayAssignmentTarget(node, { elements: node.elements.map(v => v && this[v.type](reducer, v)), rest: node.rest && this[node.rest.type](reducer, node.rest) });
|
||||
},
|
||||
|
||||
ArrayBinding(reducer, node) {
|
||||
return reducer.reduceArrayBinding(node, { elements: node.elements.map(v => v && this[v.type](reducer, v)), rest: node.rest && this[node.rest.type](reducer, node.rest) });
|
||||
},
|
||||
|
||||
ArrayExpression(reducer, node) {
|
||||
return reducer.reduceArrayExpression(node, { elements: node.elements.map(v => v && this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
ArrowExpression(reducer, node) {
|
||||
return reducer.reduceArrowExpression(node, { params: this.FormalParameters(reducer, node.params), body: this[node.body.type](reducer, node.body) });
|
||||
},
|
||||
|
||||
AssignmentExpression(reducer, node) {
|
||||
return reducer.reduceAssignmentExpression(node, { binding: this[node.binding.type](reducer, node.binding), expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
AssignmentTargetIdentifier(reducer, node) {
|
||||
return reducer.reduceAssignmentTargetIdentifier(node);
|
||||
},
|
||||
|
||||
AssignmentTargetPropertyIdentifier(reducer, node) {
|
||||
return reducer.reduceAssignmentTargetPropertyIdentifier(node, { binding: this.AssignmentTargetIdentifier(reducer, node.binding), init: node.init && this[node.init.type](reducer, node.init) });
|
||||
},
|
||||
|
||||
AssignmentTargetPropertyProperty(reducer, node) {
|
||||
return reducer.reduceAssignmentTargetPropertyProperty(node, { name: this[node.name.type](reducer, node.name), binding: this[node.binding.type](reducer, node.binding) });
|
||||
},
|
||||
|
||||
AssignmentTargetWithDefault(reducer, node) {
|
||||
return reducer.reduceAssignmentTargetWithDefault(node, { binding: this[node.binding.type](reducer, node.binding), init: this[node.init.type](reducer, node.init) });
|
||||
},
|
||||
|
||||
AwaitExpression(reducer, node) {
|
||||
return reducer.reduceAwaitExpression(node, { expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
BinaryExpression(reducer, node) {
|
||||
return reducer.reduceBinaryExpression(node, { left: this[node.left.type](reducer, node.left), right: this[node.right.type](reducer, node.right) });
|
||||
},
|
||||
|
||||
BindingIdentifier(reducer, node) {
|
||||
return reducer.reduceBindingIdentifier(node);
|
||||
},
|
||||
|
||||
BindingPropertyIdentifier(reducer, node) {
|
||||
return reducer.reduceBindingPropertyIdentifier(node, { binding: this.BindingIdentifier(reducer, node.binding), init: node.init && this[node.init.type](reducer, node.init) });
|
||||
},
|
||||
|
||||
BindingPropertyProperty(reducer, node) {
|
||||
return reducer.reduceBindingPropertyProperty(node, { name: this[node.name.type](reducer, node.name), binding: this[node.binding.type](reducer, node.binding) });
|
||||
},
|
||||
|
||||
BindingWithDefault(reducer, node) {
|
||||
return reducer.reduceBindingWithDefault(node, { binding: this[node.binding.type](reducer, node.binding), init: this[node.init.type](reducer, node.init) });
|
||||
},
|
||||
|
||||
Block(reducer, node) {
|
||||
return reducer.reduceBlock(node, { statements: node.statements.map(v => this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
BlockStatement(reducer, node) {
|
||||
return reducer.reduceBlockStatement(node, { block: this.Block(reducer, node.block) });
|
||||
},
|
||||
|
||||
BreakStatement(reducer, node) {
|
||||
return reducer.reduceBreakStatement(node);
|
||||
},
|
||||
|
||||
CallExpression(reducer, node) {
|
||||
return reducer.reduceCallExpression(node, { callee: this[node.callee.type](reducer, node.callee), arguments: node.arguments.map(v => this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
CatchClause(reducer, node) {
|
||||
return reducer.reduceCatchClause(node, { binding: this[node.binding.type](reducer, node.binding), body: this.Block(reducer, node.body) });
|
||||
},
|
||||
|
||||
ClassDeclaration(reducer, node) {
|
||||
return reducer.reduceClassDeclaration(node, { name: this.BindingIdentifier(reducer, node.name), super: node.super && this[node.super.type](reducer, node.super), elements: node.elements.map(v => this.ClassElement(reducer, v)) });
|
||||
},
|
||||
|
||||
ClassElement(reducer, node) {
|
||||
return reducer.reduceClassElement(node, { method: this[node.method.type](reducer, node.method) });
|
||||
},
|
||||
|
||||
ClassExpression(reducer, node) {
|
||||
return reducer.reduceClassExpression(node, { name: node.name && this.BindingIdentifier(reducer, node.name), super: node.super && this[node.super.type](reducer, node.super), elements: node.elements.map(v => this.ClassElement(reducer, v)) });
|
||||
},
|
||||
|
||||
CompoundAssignmentExpression(reducer, node) {
|
||||
return reducer.reduceCompoundAssignmentExpression(node, { binding: this[node.binding.type](reducer, node.binding), expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
ComputedMemberAssignmentTarget(reducer, node) {
|
||||
return reducer.reduceComputedMemberAssignmentTarget(node, { object: this[node.object.type](reducer, node.object), expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
ComputedMemberExpression(reducer, node) {
|
||||
return reducer.reduceComputedMemberExpression(node, { object: this[node.object.type](reducer, node.object), expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
ComputedPropertyName(reducer, node) {
|
||||
return reducer.reduceComputedPropertyName(node, { expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
ConditionalExpression(reducer, node) {
|
||||
return reducer.reduceConditionalExpression(node, { test: this[node.test.type](reducer, node.test), consequent: this[node.consequent.type](reducer, node.consequent), alternate: this[node.alternate.type](reducer, node.alternate) });
|
||||
},
|
||||
|
||||
ContinueStatement(reducer, node) {
|
||||
return reducer.reduceContinueStatement(node);
|
||||
},
|
||||
|
||||
DataProperty(reducer, node) {
|
||||
return reducer.reduceDataProperty(node, { name: this[node.name.type](reducer, node.name), expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
DebuggerStatement(reducer, node) {
|
||||
return reducer.reduceDebuggerStatement(node);
|
||||
},
|
||||
|
||||
Directive(reducer, node) {
|
||||
return reducer.reduceDirective(node);
|
||||
},
|
||||
|
||||
DoWhileStatement(reducer, node) {
|
||||
return reducer.reduceDoWhileStatement(node, { body: this[node.body.type](reducer, node.body), test: this[node.test.type](reducer, node.test) });
|
||||
},
|
||||
|
||||
EmptyStatement(reducer, node) {
|
||||
return reducer.reduceEmptyStatement(node);
|
||||
},
|
||||
|
||||
Export(reducer, node) {
|
||||
return reducer.reduceExport(node, { declaration: this[node.declaration.type](reducer, node.declaration) });
|
||||
},
|
||||
|
||||
ExportAllFrom(reducer, node) {
|
||||
return reducer.reduceExportAllFrom(node);
|
||||
},
|
||||
|
||||
ExportDefault(reducer, node) {
|
||||
return reducer.reduceExportDefault(node, { body: this[node.body.type](reducer, node.body) });
|
||||
},
|
||||
|
||||
ExportFrom(reducer, node) {
|
||||
return reducer.reduceExportFrom(node, { namedExports: node.namedExports.map(v => this.ExportFromSpecifier(reducer, v)) });
|
||||
},
|
||||
|
||||
ExportFromSpecifier(reducer, node) {
|
||||
return reducer.reduceExportFromSpecifier(node);
|
||||
},
|
||||
|
||||
ExportLocalSpecifier(reducer, node) {
|
||||
return reducer.reduceExportLocalSpecifier(node, { name: this.IdentifierExpression(reducer, node.name) });
|
||||
},
|
||||
|
||||
ExportLocals(reducer, node) {
|
||||
return reducer.reduceExportLocals(node, { namedExports: node.namedExports.map(v => this.ExportLocalSpecifier(reducer, v)) });
|
||||
},
|
||||
|
||||
ExpressionStatement(reducer, node) {
|
||||
return reducer.reduceExpressionStatement(node, { expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
ForAwaitStatement(reducer, node) {
|
||||
return reducer.reduceForAwaitStatement(node, { left: this[node.left.type](reducer, node.left), right: this[node.right.type](reducer, node.right), body: this[node.body.type](reducer, node.body) });
|
||||
},
|
||||
|
||||
ForInStatement(reducer, node) {
|
||||
return reducer.reduceForInStatement(node, { left: this[node.left.type](reducer, node.left), right: this[node.right.type](reducer, node.right), body: this[node.body.type](reducer, node.body) });
|
||||
},
|
||||
|
||||
ForOfStatement(reducer, node) {
|
||||
return reducer.reduceForOfStatement(node, { left: this[node.left.type](reducer, node.left), right: this[node.right.type](reducer, node.right), body: this[node.body.type](reducer, node.body) });
|
||||
},
|
||||
|
||||
ForStatement(reducer, node) {
|
||||
return reducer.reduceForStatement(node, { init: node.init && this[node.init.type](reducer, node.init), test: node.test && this[node.test.type](reducer, node.test), update: node.update && this[node.update.type](reducer, node.update), body: this[node.body.type](reducer, node.body) });
|
||||
},
|
||||
|
||||
FormalParameters(reducer, node) {
|
||||
return reducer.reduceFormalParameters(node, { items: node.items.map(v => this[v.type](reducer, v)), rest: node.rest && this[node.rest.type](reducer, node.rest) });
|
||||
},
|
||||
|
||||
FunctionBody(reducer, node) {
|
||||
return reducer.reduceFunctionBody(node, { directives: node.directives.map(v => this.Directive(reducer, v)), statements: node.statements.map(v => this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
FunctionDeclaration(reducer, node) {
|
||||
return reducer.reduceFunctionDeclaration(node, { name: this.BindingIdentifier(reducer, node.name), params: this.FormalParameters(reducer, node.params), body: this.FunctionBody(reducer, node.body) });
|
||||
},
|
||||
|
||||
FunctionExpression(reducer, node) {
|
||||
return reducer.reduceFunctionExpression(node, { name: node.name && this.BindingIdentifier(reducer, node.name), params: this.FormalParameters(reducer, node.params), body: this.FunctionBody(reducer, node.body) });
|
||||
},
|
||||
|
||||
Getter(reducer, node) {
|
||||
return reducer.reduceGetter(node, { name: this[node.name.type](reducer, node.name), body: this.FunctionBody(reducer, node.body) });
|
||||
},
|
||||
|
||||
IdentifierExpression(reducer, node) {
|
||||
return reducer.reduceIdentifierExpression(node);
|
||||
},
|
||||
|
||||
IfStatement(reducer, node) {
|
||||
return reducer.reduceIfStatement(node, { test: this[node.test.type](reducer, node.test), consequent: this[node.consequent.type](reducer, node.consequent), alternate: node.alternate && this[node.alternate.type](reducer, node.alternate) });
|
||||
},
|
||||
|
||||
Import(reducer, node) {
|
||||
return reducer.reduceImport(node, { defaultBinding: node.defaultBinding && this.BindingIdentifier(reducer, node.defaultBinding), namedImports: node.namedImports.map(v => this.ImportSpecifier(reducer, v)) });
|
||||
},
|
||||
|
||||
ImportNamespace(reducer, node) {
|
||||
return reducer.reduceImportNamespace(node, { defaultBinding: node.defaultBinding && this.BindingIdentifier(reducer, node.defaultBinding), namespaceBinding: this.BindingIdentifier(reducer, node.namespaceBinding) });
|
||||
},
|
||||
|
||||
ImportSpecifier(reducer, node) {
|
||||
return reducer.reduceImportSpecifier(node, { binding: this.BindingIdentifier(reducer, node.binding) });
|
||||
},
|
||||
|
||||
LabeledStatement(reducer, node) {
|
||||
return reducer.reduceLabeledStatement(node, { body: this[node.body.type](reducer, node.body) });
|
||||
},
|
||||
|
||||
LiteralBooleanExpression(reducer, node) {
|
||||
return reducer.reduceLiteralBooleanExpression(node);
|
||||
},
|
||||
|
||||
LiteralInfinityExpression(reducer, node) {
|
||||
return reducer.reduceLiteralInfinityExpression(node);
|
||||
},
|
||||
|
||||
LiteralNullExpression(reducer, node) {
|
||||
return reducer.reduceLiteralNullExpression(node);
|
||||
},
|
||||
|
||||
LiteralNumericExpression(reducer, node) {
|
||||
return reducer.reduceLiteralNumericExpression(node);
|
||||
},
|
||||
|
||||
LiteralRegExpExpression(reducer, node) {
|
||||
return reducer.reduceLiteralRegExpExpression(node);
|
||||
},
|
||||
|
||||
LiteralStringExpression(reducer, node) {
|
||||
return reducer.reduceLiteralStringExpression(node);
|
||||
},
|
||||
|
||||
Method(reducer, node) {
|
||||
return reducer.reduceMethod(node, { name: this[node.name.type](reducer, node.name), params: this.FormalParameters(reducer, node.params), body: this.FunctionBody(reducer, node.body) });
|
||||
},
|
||||
|
||||
Module(reducer, node) {
|
||||
return reducer.reduceModule(node, { directives: node.directives.map(v => this.Directive(reducer, v)), items: node.items.map(v => this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
NewExpression(reducer, node) {
|
||||
return reducer.reduceNewExpression(node, { callee: this[node.callee.type](reducer, node.callee), arguments: node.arguments.map(v => this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
NewTargetExpression(reducer, node) {
|
||||
return reducer.reduceNewTargetExpression(node);
|
||||
},
|
||||
|
||||
ObjectAssignmentTarget(reducer, node) {
|
||||
return reducer.reduceObjectAssignmentTarget(node, { properties: node.properties.map(v => this[v.type](reducer, v)), rest: node.rest && this[node.rest.type](reducer, node.rest) });
|
||||
},
|
||||
|
||||
ObjectBinding(reducer, node) {
|
||||
return reducer.reduceObjectBinding(node, { properties: node.properties.map(v => this[v.type](reducer, v)), rest: node.rest && this[node.rest.type](reducer, node.rest) });
|
||||
},
|
||||
|
||||
ObjectExpression(reducer, node) {
|
||||
return reducer.reduceObjectExpression(node, { properties: node.properties.map(v => this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
ReturnStatement(reducer, node) {
|
||||
return reducer.reduceReturnStatement(node, { expression: node.expression && this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
Script(reducer, node) {
|
||||
return reducer.reduceScript(node, { directives: node.directives.map(v => this.Directive(reducer, v)), statements: node.statements.map(v => this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
Setter(reducer, node) {
|
||||
return reducer.reduceSetter(node, { name: this[node.name.type](reducer, node.name), param: this[node.param.type](reducer, node.param), body: this.FunctionBody(reducer, node.body) });
|
||||
},
|
||||
|
||||
ShorthandProperty(reducer, node) {
|
||||
return reducer.reduceShorthandProperty(node, { name: this.IdentifierExpression(reducer, node.name) });
|
||||
},
|
||||
|
||||
SpreadElement(reducer, node) {
|
||||
return reducer.reduceSpreadElement(node, { expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
SpreadProperty(reducer, node) {
|
||||
return reducer.reduceSpreadProperty(node, { expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
StaticMemberAssignmentTarget(reducer, node) {
|
||||
return reducer.reduceStaticMemberAssignmentTarget(node, { object: this[node.object.type](reducer, node.object) });
|
||||
},
|
||||
|
||||
StaticMemberExpression(reducer, node) {
|
||||
return reducer.reduceStaticMemberExpression(node, { object: this[node.object.type](reducer, node.object) });
|
||||
},
|
||||
|
||||
StaticPropertyName(reducer, node) {
|
||||
return reducer.reduceStaticPropertyName(node);
|
||||
},
|
||||
|
||||
Super(reducer, node) {
|
||||
return reducer.reduceSuper(node);
|
||||
},
|
||||
|
||||
SwitchCase(reducer, node) {
|
||||
return reducer.reduceSwitchCase(node, { test: this[node.test.type](reducer, node.test), consequent: node.consequent.map(v => this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
SwitchDefault(reducer, node) {
|
||||
return reducer.reduceSwitchDefault(node, { consequent: node.consequent.map(v => this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
SwitchStatement(reducer, node) {
|
||||
return reducer.reduceSwitchStatement(node, { discriminant: this[node.discriminant.type](reducer, node.discriminant), cases: node.cases.map(v => this.SwitchCase(reducer, v)) });
|
||||
},
|
||||
|
||||
SwitchStatementWithDefault(reducer, node) {
|
||||
return reducer.reduceSwitchStatementWithDefault(node, { discriminant: this[node.discriminant.type](reducer, node.discriminant), preDefaultCases: node.preDefaultCases.map(v => this.SwitchCase(reducer, v)), defaultCase: this.SwitchDefault(reducer, node.defaultCase), postDefaultCases: node.postDefaultCases.map(v => this.SwitchCase(reducer, v)) });
|
||||
},
|
||||
|
||||
TemplateElement(reducer, node) {
|
||||
return reducer.reduceTemplateElement(node);
|
||||
},
|
||||
|
||||
TemplateExpression(reducer, node) {
|
||||
return reducer.reduceTemplateExpression(node, { tag: node.tag && this[node.tag.type](reducer, node.tag), elements: node.elements.map(v => this[v.type](reducer, v)) });
|
||||
},
|
||||
|
||||
ThisExpression(reducer, node) {
|
||||
return reducer.reduceThisExpression(node);
|
||||
},
|
||||
|
||||
ThrowStatement(reducer, node) {
|
||||
return reducer.reduceThrowStatement(node, { expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
TryCatchStatement(reducer, node) {
|
||||
return reducer.reduceTryCatchStatement(node, { body: this.Block(reducer, node.body), catchClause: this.CatchClause(reducer, node.catchClause) });
|
||||
},
|
||||
|
||||
TryFinallyStatement(reducer, node) {
|
||||
return reducer.reduceTryFinallyStatement(node, { body: this.Block(reducer, node.body), catchClause: node.catchClause && this.CatchClause(reducer, node.catchClause), finalizer: this.Block(reducer, node.finalizer) });
|
||||
},
|
||||
|
||||
UnaryExpression(reducer, node) {
|
||||
return reducer.reduceUnaryExpression(node, { operand: this[node.operand.type](reducer, node.operand) });
|
||||
},
|
||||
|
||||
UpdateExpression(reducer, node) {
|
||||
return reducer.reduceUpdateExpression(node, { operand: this[node.operand.type](reducer, node.operand) });
|
||||
},
|
||||
|
||||
VariableDeclaration(reducer, node) {
|
||||
return reducer.reduceVariableDeclaration(node, { declarators: node.declarators.map(v => this.VariableDeclarator(reducer, v)) });
|
||||
},
|
||||
|
||||
VariableDeclarationStatement(reducer, node) {
|
||||
return reducer.reduceVariableDeclarationStatement(node, { declaration: this.VariableDeclaration(reducer, node.declaration) });
|
||||
},
|
||||
|
||||
VariableDeclarator(reducer, node) {
|
||||
return reducer.reduceVariableDeclarator(node, { binding: this[node.binding.type](reducer, node.binding), init: node.init && this[node.init.type](reducer, node.init) });
|
||||
},
|
||||
|
||||
WhileStatement(reducer, node) {
|
||||
return reducer.reduceWhileStatement(node, { test: this[node.test.type](reducer, node.test), body: this[node.body.type](reducer, node.body) });
|
||||
},
|
||||
|
||||
WithStatement(reducer, node) {
|
||||
return reducer.reduceWithStatement(node, { object: this[node.object.type](reducer, node.object), body: this[node.body.type](reducer, node.body) });
|
||||
},
|
||||
|
||||
YieldExpression(reducer, node) {
|
||||
return reducer.reduceYieldExpression(node, { expression: node.expression && this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
|
||||
YieldGeneratorExpression(reducer, node) {
|
||||
return reducer.reduceYieldGeneratorExpression(node, { expression: this[node.expression.type](reducer, node.expression) });
|
||||
},
|
||||
};
|
||||
|
||||
export function reduce(reducer, node) {
|
||||
return director[node.type](reducer, node);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { reduce, reduce as default } from './director.js';
|
||||
export { thunkedReduce } from './thunked-director.js';
|
||||
export { default as thunkify } from './thunkify.js';
|
||||
export { default as thunkifyClass } from './thunkify-class.js';
|
||||
export { default as memoize } from './memoize.js';
|
||||
export { default as CloneReducer } from './clone-reducer.js';
|
||||
export { default as LazyCloneReducer } from './lazy-clone-reducer.js';
|
||||
export { default as MonoidalReducer } from './monoidal-reducer.js';
|
||||
export { default as ThunkedMonoidalReducer } from './thunked-monoidal-reducer.js';
|
||||
export { default as adapt } from './adapt.js';
|
||||
export { PlusReducer, ThunkedPlusReducer, ConcatReducer, ThunkedConcatReducer, AndReducer, ThunkedAndReducer, OrReducer, ThunkedOrReducer } from './reducers.js';
|
||||
@@ -1,650 +0,0 @@
|
||||
// Generated by generate-lazy-clone-reducer.js
|
||||
/**
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as Shift from 'shift-ast';
|
||||
|
||||
export default class LazyCloneReducer {
|
||||
reduceArrayAssignmentTarget(node, { elements, rest }) {
|
||||
if ((node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i])) && node.rest === rest) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ArrayAssignmentTarget({ elements, rest });
|
||||
}
|
||||
|
||||
reduceArrayBinding(node, { elements, rest }) {
|
||||
if ((node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i])) && node.rest === rest) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ArrayBinding({ elements, rest });
|
||||
}
|
||||
|
||||
reduceArrayExpression(node, { elements }) {
|
||||
if ((node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ArrayExpression({ elements });
|
||||
}
|
||||
|
||||
reduceArrowExpression(node, { params, body }) {
|
||||
if (node.params === params && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ArrowExpression({ isAsync: node.isAsync, params, body });
|
||||
}
|
||||
|
||||
reduceAssignmentExpression(node, { binding, expression }) {
|
||||
if (node.binding === binding && node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.AssignmentExpression({ binding, expression });
|
||||
}
|
||||
|
||||
reduceAssignmentTargetIdentifier(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) {
|
||||
if (node.binding === binding && node.init === init) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.AssignmentTargetPropertyIdentifier({ binding, init });
|
||||
}
|
||||
|
||||
reduceAssignmentTargetPropertyProperty(node, { name, binding }) {
|
||||
if (node.name === name && node.binding === binding) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.AssignmentTargetPropertyProperty({ name, binding });
|
||||
}
|
||||
|
||||
reduceAssignmentTargetWithDefault(node, { binding, init }) {
|
||||
if (node.binding === binding && node.init === init) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.AssignmentTargetWithDefault({ binding, init });
|
||||
}
|
||||
|
||||
reduceAwaitExpression(node, { expression }) {
|
||||
if (node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.AwaitExpression({ expression });
|
||||
}
|
||||
|
||||
reduceBinaryExpression(node, { left, right }) {
|
||||
if (node.left === left && node.right === right) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.BinaryExpression({ left, operator: node.operator, right });
|
||||
}
|
||||
|
||||
reduceBindingIdentifier(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceBindingPropertyIdentifier(node, { binding, init }) {
|
||||
if (node.binding === binding && node.init === init) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.BindingPropertyIdentifier({ binding, init });
|
||||
}
|
||||
|
||||
reduceBindingPropertyProperty(node, { name, binding }) {
|
||||
if (node.name === name && node.binding === binding) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.BindingPropertyProperty({ name, binding });
|
||||
}
|
||||
|
||||
reduceBindingWithDefault(node, { binding, init }) {
|
||||
if (node.binding === binding && node.init === init) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.BindingWithDefault({ binding, init });
|
||||
}
|
||||
|
||||
reduceBlock(node, { statements }) {
|
||||
if ((node.statements.length === statements.length && node.statements.every((v, i) => v === statements[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.Block({ statements });
|
||||
}
|
||||
|
||||
reduceBlockStatement(node, { block }) {
|
||||
if (node.block === block) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.BlockStatement({ block });
|
||||
}
|
||||
|
||||
reduceBreakStatement(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceCallExpression(node, { callee, arguments: _arguments }) {
|
||||
if (node.callee === callee && (node.arguments.length === _arguments.length && node.arguments.every((v, i) => v === _arguments[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.CallExpression({ callee, arguments: _arguments });
|
||||
}
|
||||
|
||||
reduceCatchClause(node, { binding, body }) {
|
||||
if (node.binding === binding && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.CatchClause({ binding, body });
|
||||
}
|
||||
|
||||
reduceClassDeclaration(node, { name, super: _super, elements }) {
|
||||
if (node.name === name && node.super === _super && (node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ClassDeclaration({ name, super: _super, elements });
|
||||
}
|
||||
|
||||
reduceClassElement(node, { method }) {
|
||||
if (node.method === method) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ClassElement({ isStatic: node.isStatic, method });
|
||||
}
|
||||
|
||||
reduceClassExpression(node, { name, super: _super, elements }) {
|
||||
if (node.name === name && node.super === _super && (node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ClassExpression({ name, super: _super, elements });
|
||||
}
|
||||
|
||||
reduceCompoundAssignmentExpression(node, { binding, expression }) {
|
||||
if (node.binding === binding && node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.CompoundAssignmentExpression({ binding, operator: node.operator, expression });
|
||||
}
|
||||
|
||||
reduceComputedMemberAssignmentTarget(node, { object, expression }) {
|
||||
if (node.object === object && node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ComputedMemberAssignmentTarget({ object, expression });
|
||||
}
|
||||
|
||||
reduceComputedMemberExpression(node, { object, expression }) {
|
||||
if (node.object === object && node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ComputedMemberExpression({ object, expression });
|
||||
}
|
||||
|
||||
reduceComputedPropertyName(node, { expression }) {
|
||||
if (node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ComputedPropertyName({ expression });
|
||||
}
|
||||
|
||||
reduceConditionalExpression(node, { test, consequent, alternate }) {
|
||||
if (node.test === test && node.consequent === consequent && node.alternate === alternate) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ConditionalExpression({ test, consequent, alternate });
|
||||
}
|
||||
|
||||
reduceContinueStatement(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceDataProperty(node, { name, expression }) {
|
||||
if (node.name === name && node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.DataProperty({ name, expression });
|
||||
}
|
||||
|
||||
reduceDebuggerStatement(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceDirective(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceDoWhileStatement(node, { body, test }) {
|
||||
if (node.body === body && node.test === test) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.DoWhileStatement({ body, test });
|
||||
}
|
||||
|
||||
reduceEmptyStatement(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceExport(node, { declaration }) {
|
||||
if (node.declaration === declaration) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.Export({ declaration });
|
||||
}
|
||||
|
||||
reduceExportAllFrom(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceExportDefault(node, { body }) {
|
||||
if (node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ExportDefault({ body });
|
||||
}
|
||||
|
||||
reduceExportFrom(node, { namedExports }) {
|
||||
if ((node.namedExports.length === namedExports.length && node.namedExports.every((v, i) => v === namedExports[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ExportFrom({ namedExports, moduleSpecifier: node.moduleSpecifier });
|
||||
}
|
||||
|
||||
reduceExportFromSpecifier(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceExportLocalSpecifier(node, { name }) {
|
||||
if (node.name === name) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ExportLocalSpecifier({ name, exportedName: node.exportedName });
|
||||
}
|
||||
|
||||
reduceExportLocals(node, { namedExports }) {
|
||||
if ((node.namedExports.length === namedExports.length && node.namedExports.every((v, i) => v === namedExports[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ExportLocals({ namedExports });
|
||||
}
|
||||
|
||||
reduceExpressionStatement(node, { expression }) {
|
||||
if (node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ExpressionStatement({ expression });
|
||||
}
|
||||
|
||||
reduceForAwaitStatement(node, { left, right, body }) {
|
||||
if (node.left === left && node.right === right && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ForAwaitStatement({ left, right, body });
|
||||
}
|
||||
|
||||
reduceForInStatement(node, { left, right, body }) {
|
||||
if (node.left === left && node.right === right && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ForInStatement({ left, right, body });
|
||||
}
|
||||
|
||||
reduceForOfStatement(node, { left, right, body }) {
|
||||
if (node.left === left && node.right === right && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ForOfStatement({ left, right, body });
|
||||
}
|
||||
|
||||
reduceForStatement(node, { init, test, update, body }) {
|
||||
if (node.init === init && node.test === test && node.update === update && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ForStatement({ init, test, update, body });
|
||||
}
|
||||
|
||||
reduceFormalParameters(node, { items, rest }) {
|
||||
if ((node.items.length === items.length && node.items.every((v, i) => v === items[i])) && node.rest === rest) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.FormalParameters({ items, rest });
|
||||
}
|
||||
|
||||
reduceFunctionBody(node, { directives, statements }) {
|
||||
if ((node.directives.length === directives.length && node.directives.every((v, i) => v === directives[i])) && (node.statements.length === statements.length && node.statements.every((v, i) => v === statements[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.FunctionBody({ directives, statements });
|
||||
}
|
||||
|
||||
reduceFunctionDeclaration(node, { name, params, body }) {
|
||||
if (node.name === name && node.params === params && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.FunctionDeclaration({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body });
|
||||
}
|
||||
|
||||
reduceFunctionExpression(node, { name, params, body }) {
|
||||
if (node.name === name && node.params === params && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.FunctionExpression({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body });
|
||||
}
|
||||
|
||||
reduceGetter(node, { name, body }) {
|
||||
if (node.name === name && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.Getter({ name, body });
|
||||
}
|
||||
|
||||
reduceIdentifierExpression(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceIfStatement(node, { test, consequent, alternate }) {
|
||||
if (node.test === test && node.consequent === consequent && node.alternate === alternate) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.IfStatement({ test, consequent, alternate });
|
||||
}
|
||||
|
||||
reduceImport(node, { defaultBinding, namedImports }) {
|
||||
if (node.defaultBinding === defaultBinding && (node.namedImports.length === namedImports.length && node.namedImports.every((v, i) => v === namedImports[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.Import({ defaultBinding, namedImports, moduleSpecifier: node.moduleSpecifier });
|
||||
}
|
||||
|
||||
reduceImportNamespace(node, { defaultBinding, namespaceBinding }) {
|
||||
if (node.defaultBinding === defaultBinding && node.namespaceBinding === namespaceBinding) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ImportNamespace({ defaultBinding, namespaceBinding, moduleSpecifier: node.moduleSpecifier });
|
||||
}
|
||||
|
||||
reduceImportSpecifier(node, { binding }) {
|
||||
if (node.binding === binding) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ImportSpecifier({ name: node.name, binding });
|
||||
}
|
||||
|
||||
reduceLabeledStatement(node, { body }) {
|
||||
if (node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.LabeledStatement({ label: node.label, body });
|
||||
}
|
||||
|
||||
reduceLiteralBooleanExpression(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceLiteralInfinityExpression(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceLiteralNullExpression(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceLiteralNumericExpression(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceLiteralRegExpExpression(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceLiteralStringExpression(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceMethod(node, { name, params, body }) {
|
||||
if (node.name === name && node.params === params && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.Method({ isAsync: node.isAsync, isGenerator: node.isGenerator, name, params, body });
|
||||
}
|
||||
|
||||
reduceModule(node, { directives, items }) {
|
||||
if ((node.directives.length === directives.length && node.directives.every((v, i) => v === directives[i])) && (node.items.length === items.length && node.items.every((v, i) => v === items[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.Module({ directives, items });
|
||||
}
|
||||
|
||||
reduceNewExpression(node, { callee, arguments: _arguments }) {
|
||||
if (node.callee === callee && (node.arguments.length === _arguments.length && node.arguments.every((v, i) => v === _arguments[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.NewExpression({ callee, arguments: _arguments });
|
||||
}
|
||||
|
||||
reduceNewTargetExpression(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceObjectAssignmentTarget(node, { properties, rest }) {
|
||||
if ((node.properties.length === properties.length && node.properties.every((v, i) => v === properties[i])) && node.rest === rest) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ObjectAssignmentTarget({ properties, rest });
|
||||
}
|
||||
|
||||
reduceObjectBinding(node, { properties, rest }) {
|
||||
if ((node.properties.length === properties.length && node.properties.every((v, i) => v === properties[i])) && node.rest === rest) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ObjectBinding({ properties, rest });
|
||||
}
|
||||
|
||||
reduceObjectExpression(node, { properties }) {
|
||||
if ((node.properties.length === properties.length && node.properties.every((v, i) => v === properties[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ObjectExpression({ properties });
|
||||
}
|
||||
|
||||
reduceReturnStatement(node, { expression }) {
|
||||
if (node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ReturnStatement({ expression });
|
||||
}
|
||||
|
||||
reduceScript(node, { directives, statements }) {
|
||||
if ((node.directives.length === directives.length && node.directives.every((v, i) => v === directives[i])) && (node.statements.length === statements.length && node.statements.every((v, i) => v === statements[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.Script({ directives, statements });
|
||||
}
|
||||
|
||||
reduceSetter(node, { name, param, body }) {
|
||||
if (node.name === name && node.param === param && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.Setter({ name, param, body });
|
||||
}
|
||||
|
||||
reduceShorthandProperty(node, { name }) {
|
||||
if (node.name === name) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ShorthandProperty({ name });
|
||||
}
|
||||
|
||||
reduceSpreadElement(node, { expression }) {
|
||||
if (node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.SpreadElement({ expression });
|
||||
}
|
||||
|
||||
reduceSpreadProperty(node, { expression }) {
|
||||
if (node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.SpreadProperty({ expression });
|
||||
}
|
||||
|
||||
reduceStaticMemberAssignmentTarget(node, { object }) {
|
||||
if (node.object === object) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.StaticMemberAssignmentTarget({ object, property: node.property });
|
||||
}
|
||||
|
||||
reduceStaticMemberExpression(node, { object }) {
|
||||
if (node.object === object) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.StaticMemberExpression({ object, property: node.property });
|
||||
}
|
||||
|
||||
reduceStaticPropertyName(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceSuper(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceSwitchCase(node, { test, consequent }) {
|
||||
if (node.test === test && (node.consequent.length === consequent.length && node.consequent.every((v, i) => v === consequent[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.SwitchCase({ test, consequent });
|
||||
}
|
||||
|
||||
reduceSwitchDefault(node, { consequent }) {
|
||||
if ((node.consequent.length === consequent.length && node.consequent.every((v, i) => v === consequent[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.SwitchDefault({ consequent });
|
||||
}
|
||||
|
||||
reduceSwitchStatement(node, { discriminant, cases }) {
|
||||
if (node.discriminant === discriminant && (node.cases.length === cases.length && node.cases.every((v, i) => v === cases[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.SwitchStatement({ discriminant, cases });
|
||||
}
|
||||
|
||||
reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) {
|
||||
if (node.discriminant === discriminant && (node.preDefaultCases.length === preDefaultCases.length && node.preDefaultCases.every((v, i) => v === preDefaultCases[i])) && node.defaultCase === defaultCase && (node.postDefaultCases.length === postDefaultCases.length && node.postDefaultCases.every((v, i) => v === postDefaultCases[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.SwitchStatementWithDefault({ discriminant, preDefaultCases, defaultCase, postDefaultCases });
|
||||
}
|
||||
|
||||
reduceTemplateElement(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceTemplateExpression(node, { tag, elements }) {
|
||||
if (node.tag === tag && (node.elements.length === elements.length && node.elements.every((v, i) => v === elements[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.TemplateExpression({ tag, elements });
|
||||
}
|
||||
|
||||
reduceThisExpression(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
reduceThrowStatement(node, { expression }) {
|
||||
if (node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.ThrowStatement({ expression });
|
||||
}
|
||||
|
||||
reduceTryCatchStatement(node, { body, catchClause }) {
|
||||
if (node.body === body && node.catchClause === catchClause) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.TryCatchStatement({ body, catchClause });
|
||||
}
|
||||
|
||||
reduceTryFinallyStatement(node, { body, catchClause, finalizer }) {
|
||||
if (node.body === body && node.catchClause === catchClause && node.finalizer === finalizer) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.TryFinallyStatement({ body, catchClause, finalizer });
|
||||
}
|
||||
|
||||
reduceUnaryExpression(node, { operand }) {
|
||||
if (node.operand === operand) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.UnaryExpression({ operator: node.operator, operand });
|
||||
}
|
||||
|
||||
reduceUpdateExpression(node, { operand }) {
|
||||
if (node.operand === operand) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.UpdateExpression({ isPrefix: node.isPrefix, operator: node.operator, operand });
|
||||
}
|
||||
|
||||
reduceVariableDeclaration(node, { declarators }) {
|
||||
if ((node.declarators.length === declarators.length && node.declarators.every((v, i) => v === declarators[i]))) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.VariableDeclaration({ kind: node.kind, declarators });
|
||||
}
|
||||
|
||||
reduceVariableDeclarationStatement(node, { declaration }) {
|
||||
if (node.declaration === declaration) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.VariableDeclarationStatement({ declaration });
|
||||
}
|
||||
|
||||
reduceVariableDeclarator(node, { binding, init }) {
|
||||
if (node.binding === binding && node.init === init) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.VariableDeclarator({ binding, init });
|
||||
}
|
||||
|
||||
reduceWhileStatement(node, { test, body }) {
|
||||
if (node.test === test && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.WhileStatement({ test, body });
|
||||
}
|
||||
|
||||
reduceWithStatement(node, { object, body }) {
|
||||
if (node.object === object && node.body === body) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.WithStatement({ object, body });
|
||||
}
|
||||
|
||||
reduceYieldExpression(node, { expression }) {
|
||||
if (node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.YieldExpression({ expression });
|
||||
}
|
||||
|
||||
reduceYieldGeneratorExpression(node, { expression }) {
|
||||
if (node.expression === expression) {
|
||||
return node;
|
||||
}
|
||||
return new Shift.YieldGeneratorExpression({ expression });
|
||||
}
|
||||
}
|
||||
@@ -1,914 +0,0 @@
|
||||
// Generated by generate-memoize.js
|
||||
/**
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as Shift from 'shift-ast';
|
||||
|
||||
export default function memoize(reducer) {
|
||||
const cache = new WeakMap;
|
||||
return {
|
||||
reduceArrayAssignmentTarget(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceArrayAssignmentTarget(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceArrayBinding(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceArrayBinding(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceArrayExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceArrayExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceArrowExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceArrowExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceAssignmentExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceAssignmentExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceAssignmentTargetIdentifier(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceAssignmentTargetIdentifier(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceAssignmentTargetPropertyIdentifier(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceAssignmentTargetPropertyIdentifier(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceAssignmentTargetPropertyProperty(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceAssignmentTargetPropertyProperty(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceAssignmentTargetWithDefault(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceAssignmentTargetWithDefault(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceAwaitExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceAwaitExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceBinaryExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceBinaryExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceBindingIdentifier(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceBindingIdentifier(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceBindingPropertyIdentifier(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceBindingPropertyIdentifier(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceBindingPropertyProperty(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceBindingPropertyProperty(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceBindingWithDefault(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceBindingWithDefault(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceBlock(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceBlock(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceBlockStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceBlockStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceBreakStatement(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceBreakStatement(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceCallExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceCallExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceCatchClause(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceCatchClause(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceClassDeclaration(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceClassDeclaration(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceClassElement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceClassElement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceClassExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceClassExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceCompoundAssignmentExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceCompoundAssignmentExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceComputedMemberAssignmentTarget(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceComputedMemberAssignmentTarget(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceComputedMemberExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceComputedMemberExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceComputedPropertyName(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceComputedPropertyName(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceConditionalExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceConditionalExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceContinueStatement(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceContinueStatement(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceDataProperty(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceDataProperty(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceDebuggerStatement(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceDebuggerStatement(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceDirective(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceDirective(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceDoWhileStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceDoWhileStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceEmptyStatement(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceEmptyStatement(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceExport(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceExport(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceExportAllFrom(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceExportAllFrom(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceExportDefault(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceExportDefault(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceExportFrom(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceExportFrom(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceExportFromSpecifier(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceExportFromSpecifier(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceExportLocalSpecifier(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceExportLocalSpecifier(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceExportLocals(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceExportLocals(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceExpressionStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceExpressionStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceForAwaitStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceForAwaitStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceForInStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceForInStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceForOfStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceForOfStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceForStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceForStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceFormalParameters(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceFormalParameters(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceFunctionBody(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceFunctionBody(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceFunctionDeclaration(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceFunctionDeclaration(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceFunctionExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceFunctionExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceGetter(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceGetter(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceIdentifierExpression(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceIdentifierExpression(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceIfStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceIfStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceImport(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceImport(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceImportNamespace(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceImportNamespace(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceImportSpecifier(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceImportSpecifier(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceLabeledStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceLabeledStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceLiteralBooleanExpression(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceLiteralBooleanExpression(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceLiteralInfinityExpression(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceLiteralInfinityExpression(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceLiteralNullExpression(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceLiteralNullExpression(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceLiteralNumericExpression(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceLiteralNumericExpression(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceLiteralRegExpExpression(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceLiteralRegExpExpression(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceLiteralStringExpression(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceLiteralStringExpression(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceMethod(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceMethod(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceModule(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceModule(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceNewExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceNewExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceNewTargetExpression(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceNewTargetExpression(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceObjectAssignmentTarget(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceObjectAssignmentTarget(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceObjectBinding(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceObjectBinding(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceObjectExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceObjectExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceReturnStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceReturnStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceScript(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceScript(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceSetter(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceSetter(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceShorthandProperty(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceShorthandProperty(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceSpreadElement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceSpreadElement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceSpreadProperty(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceSpreadProperty(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceStaticMemberAssignmentTarget(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceStaticMemberAssignmentTarget(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceStaticMemberExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceStaticMemberExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceStaticPropertyName(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceStaticPropertyName(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceSuper(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceSuper(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceSwitchCase(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceSwitchCase(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceSwitchDefault(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceSwitchDefault(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceSwitchStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceSwitchStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceSwitchStatementWithDefault(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceSwitchStatementWithDefault(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceTemplateElement(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceTemplateElement(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceTemplateExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceTemplateExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceThisExpression(node) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceThisExpression(node);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceThrowStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceThrowStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceTryCatchStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceTryCatchStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceTryFinallyStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceTryFinallyStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceUnaryExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceUnaryExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceUpdateExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceUpdateExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceVariableDeclaration(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceVariableDeclaration(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceVariableDeclarationStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceVariableDeclarationStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceVariableDeclarator(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceVariableDeclarator(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceWhileStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceWhileStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceWithStatement(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceWithStatement(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceYieldExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceYieldExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
|
||||
reduceYieldGeneratorExpression(node, arg) {
|
||||
if (cache.has(node)) {
|
||||
return cache.get(node);
|
||||
}
|
||||
const res = reducer.reduceYieldGeneratorExpression(node, arg);
|
||||
cache.set(node, res);
|
||||
return res;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,430 +0,0 @@
|
||||
// Generated by generate-monoidal-reducer.js
|
||||
/**
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Shift from 'shift-ast';
|
||||
|
||||
export default class MonoidalReducer {
|
||||
constructor(monoid) {
|
||||
let identity = monoid.empty();
|
||||
this.identity = identity;
|
||||
let concat;
|
||||
if (monoid.prototype && typeof monoid.prototype.concat === 'function') {
|
||||
concat = Function.prototype.call.bind(monoid.prototype.concat);
|
||||
} else if (typeof monoid.concat === 'function') {
|
||||
concat = monoid.concat;
|
||||
} else {
|
||||
throw new TypeError('Monoid must provide a `concat` method');
|
||||
}
|
||||
this.append = (...args) => args.reduce(concat, identity);
|
||||
}
|
||||
|
||||
reduceArrayAssignmentTarget(node, { elements, rest }) {
|
||||
return this.append(...elements.filter(n => n != null), rest == null ? this.identity : rest);
|
||||
}
|
||||
|
||||
reduceArrayBinding(node, { elements, rest }) {
|
||||
return this.append(...elements.filter(n => n != null), rest == null ? this.identity : rest);
|
||||
}
|
||||
|
||||
reduceArrayExpression(node, { elements }) {
|
||||
return this.append(...elements.filter(n => n != null));
|
||||
}
|
||||
|
||||
reduceArrowExpression(node, { params, body }) {
|
||||
return this.append(params, body);
|
||||
}
|
||||
|
||||
reduceAssignmentExpression(node, { binding, expression }) {
|
||||
return this.append(binding, expression);
|
||||
}
|
||||
|
||||
reduceAssignmentTargetIdentifier(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) {
|
||||
return this.append(binding, init == null ? this.identity : init);
|
||||
}
|
||||
|
||||
reduceAssignmentTargetPropertyProperty(node, { name, binding }) {
|
||||
return this.append(name, binding);
|
||||
}
|
||||
|
||||
reduceAssignmentTargetWithDefault(node, { binding, init }) {
|
||||
return this.append(binding, init);
|
||||
}
|
||||
|
||||
reduceAwaitExpression(node, { expression }) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
reduceBinaryExpression(node, { left, right }) {
|
||||
return this.append(left, right);
|
||||
}
|
||||
|
||||
reduceBindingIdentifier(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceBindingPropertyIdentifier(node, { binding, init }) {
|
||||
return this.append(binding, init == null ? this.identity : init);
|
||||
}
|
||||
|
||||
reduceBindingPropertyProperty(node, { name, binding }) {
|
||||
return this.append(name, binding);
|
||||
}
|
||||
|
||||
reduceBindingWithDefault(node, { binding, init }) {
|
||||
return this.append(binding, init);
|
||||
}
|
||||
|
||||
reduceBlock(node, { statements }) {
|
||||
return this.append(...statements);
|
||||
}
|
||||
|
||||
reduceBlockStatement(node, { block }) {
|
||||
return block;
|
||||
}
|
||||
|
||||
reduceBreakStatement(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceCallExpression(node, { callee, arguments: _arguments }) {
|
||||
return this.append(callee, ..._arguments);
|
||||
}
|
||||
|
||||
reduceCatchClause(node, { binding, body }) {
|
||||
return this.append(binding, body);
|
||||
}
|
||||
|
||||
reduceClassDeclaration(node, { name, super: _super, elements }) {
|
||||
return this.append(name, _super == null ? this.identity : _super, ...elements);
|
||||
}
|
||||
|
||||
reduceClassElement(node, { method }) {
|
||||
return method;
|
||||
}
|
||||
|
||||
reduceClassExpression(node, { name, super: _super, elements }) {
|
||||
return this.append(name == null ? this.identity : name, _super == null ? this.identity : _super, ...elements);
|
||||
}
|
||||
|
||||
reduceCompoundAssignmentExpression(node, { binding, expression }) {
|
||||
return this.append(binding, expression);
|
||||
}
|
||||
|
||||
reduceComputedMemberAssignmentTarget(node, { object, expression }) {
|
||||
return this.append(object, expression);
|
||||
}
|
||||
|
||||
reduceComputedMemberExpression(node, { object, expression }) {
|
||||
return this.append(object, expression);
|
||||
}
|
||||
|
||||
reduceComputedPropertyName(node, { expression }) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
reduceConditionalExpression(node, { test, consequent, alternate }) {
|
||||
return this.append(test, consequent, alternate);
|
||||
}
|
||||
|
||||
reduceContinueStatement(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceDataProperty(node, { name, expression }) {
|
||||
return this.append(name, expression);
|
||||
}
|
||||
|
||||
reduceDebuggerStatement(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceDirective(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceDoWhileStatement(node, { body, test }) {
|
||||
return this.append(body, test);
|
||||
}
|
||||
|
||||
reduceEmptyStatement(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceExport(node, { declaration }) {
|
||||
return declaration;
|
||||
}
|
||||
|
||||
reduceExportAllFrom(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceExportDefault(node, { body }) {
|
||||
return body;
|
||||
}
|
||||
|
||||
reduceExportFrom(node, { namedExports }) {
|
||||
return this.append(...namedExports);
|
||||
}
|
||||
|
||||
reduceExportFromSpecifier(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceExportLocalSpecifier(node, { name }) {
|
||||
return name;
|
||||
}
|
||||
|
||||
reduceExportLocals(node, { namedExports }) {
|
||||
return this.append(...namedExports);
|
||||
}
|
||||
|
||||
reduceExpressionStatement(node, { expression }) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
reduceForAwaitStatement(node, { left, right, body }) {
|
||||
return this.append(left, right, body);
|
||||
}
|
||||
|
||||
reduceForInStatement(node, { left, right, body }) {
|
||||
return this.append(left, right, body);
|
||||
}
|
||||
|
||||
reduceForOfStatement(node, { left, right, body }) {
|
||||
return this.append(left, right, body);
|
||||
}
|
||||
|
||||
reduceForStatement(node, { init, test, update, body }) {
|
||||
return this.append(init == null ? this.identity : init, test == null ? this.identity : test, update == null ? this.identity : update, body);
|
||||
}
|
||||
|
||||
reduceFormalParameters(node, { items, rest }) {
|
||||
return this.append(...items, rest == null ? this.identity : rest);
|
||||
}
|
||||
|
||||
reduceFunctionBody(node, { directives, statements }) {
|
||||
return this.append(...directives, ...statements);
|
||||
}
|
||||
|
||||
reduceFunctionDeclaration(node, { name, params, body }) {
|
||||
return this.append(name, params, body);
|
||||
}
|
||||
|
||||
reduceFunctionExpression(node, { name, params, body }) {
|
||||
return this.append(name == null ? this.identity : name, params, body);
|
||||
}
|
||||
|
||||
reduceGetter(node, { name, body }) {
|
||||
return this.append(name, body);
|
||||
}
|
||||
|
||||
reduceIdentifierExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceIfStatement(node, { test, consequent, alternate }) {
|
||||
return this.append(test, consequent, alternate == null ? this.identity : alternate);
|
||||
}
|
||||
|
||||
reduceImport(node, { defaultBinding, namedImports }) {
|
||||
return this.append(defaultBinding == null ? this.identity : defaultBinding, ...namedImports);
|
||||
}
|
||||
|
||||
reduceImportNamespace(node, { defaultBinding, namespaceBinding }) {
|
||||
return this.append(defaultBinding == null ? this.identity : defaultBinding, namespaceBinding);
|
||||
}
|
||||
|
||||
reduceImportSpecifier(node, { binding }) {
|
||||
return binding;
|
||||
}
|
||||
|
||||
reduceLabeledStatement(node, { body }) {
|
||||
return body;
|
||||
}
|
||||
|
||||
reduceLiteralBooleanExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceLiteralInfinityExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceLiteralNullExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceLiteralNumericExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceLiteralRegExpExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceLiteralStringExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceMethod(node, { name, params, body }) {
|
||||
return this.append(name, params, body);
|
||||
}
|
||||
|
||||
reduceModule(node, { directives, items }) {
|
||||
return this.append(...directives, ...items);
|
||||
}
|
||||
|
||||
reduceNewExpression(node, { callee, arguments: _arguments }) {
|
||||
return this.append(callee, ..._arguments);
|
||||
}
|
||||
|
||||
reduceNewTargetExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceObjectAssignmentTarget(node, { properties, rest }) {
|
||||
return this.append(...properties, rest == null ? this.identity : rest);
|
||||
}
|
||||
|
||||
reduceObjectBinding(node, { properties, rest }) {
|
||||
return this.append(...properties, rest == null ? this.identity : rest);
|
||||
}
|
||||
|
||||
reduceObjectExpression(node, { properties }) {
|
||||
return this.append(...properties);
|
||||
}
|
||||
|
||||
reduceReturnStatement(node, { expression }) {
|
||||
return expression == null ? this.identity : expression;
|
||||
}
|
||||
|
||||
reduceScript(node, { directives, statements }) {
|
||||
return this.append(...directives, ...statements);
|
||||
}
|
||||
|
||||
reduceSetter(node, { name, param, body }) {
|
||||
return this.append(name, param, body);
|
||||
}
|
||||
|
||||
reduceShorthandProperty(node, { name }) {
|
||||
return name;
|
||||
}
|
||||
|
||||
reduceSpreadElement(node, { expression }) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
reduceSpreadProperty(node, { expression }) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
reduceStaticMemberAssignmentTarget(node, { object }) {
|
||||
return object;
|
||||
}
|
||||
|
||||
reduceStaticMemberExpression(node, { object }) {
|
||||
return object;
|
||||
}
|
||||
|
||||
reduceStaticPropertyName(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceSuper(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceSwitchCase(node, { test, consequent }) {
|
||||
return this.append(test, ...consequent);
|
||||
}
|
||||
|
||||
reduceSwitchDefault(node, { consequent }) {
|
||||
return this.append(...consequent);
|
||||
}
|
||||
|
||||
reduceSwitchStatement(node, { discriminant, cases }) {
|
||||
return this.append(discriminant, ...cases);
|
||||
}
|
||||
|
||||
reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) {
|
||||
return this.append(discriminant, ...preDefaultCases, defaultCase, ...postDefaultCases);
|
||||
}
|
||||
|
||||
reduceTemplateElement(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceTemplateExpression(node, { tag, elements }) {
|
||||
return this.append(tag == null ? this.identity : tag, ...elements);
|
||||
}
|
||||
|
||||
reduceThisExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceThrowStatement(node, { expression }) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
reduceTryCatchStatement(node, { body, catchClause }) {
|
||||
return this.append(body, catchClause);
|
||||
}
|
||||
|
||||
reduceTryFinallyStatement(node, { body, catchClause, finalizer }) {
|
||||
return this.append(body, catchClause == null ? this.identity : catchClause, finalizer);
|
||||
}
|
||||
|
||||
reduceUnaryExpression(node, { operand }) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
reduceUpdateExpression(node, { operand }) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
reduceVariableDeclaration(node, { declarators }) {
|
||||
return this.append(...declarators);
|
||||
}
|
||||
|
||||
reduceVariableDeclarationStatement(node, { declaration }) {
|
||||
return declaration;
|
||||
}
|
||||
|
||||
reduceVariableDeclarator(node, { binding, init }) {
|
||||
return this.append(binding, init == null ? this.identity : init);
|
||||
}
|
||||
|
||||
reduceWhileStatement(node, { test, body }) {
|
||||
return this.append(test, body);
|
||||
}
|
||||
|
||||
reduceWithStatement(node, { object, body }) {
|
||||
return this.append(object, body);
|
||||
}
|
||||
|
||||
reduceYieldExpression(node, { expression }) {
|
||||
return expression == null ? this.identity : expression;
|
||||
}
|
||||
|
||||
reduceYieldGeneratorExpression(node, { expression }) {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import MonoidalReducer from './monoidal-reducer.js';
|
||||
import ThunkedMonoidalReducer from './thunked-monoidal-reducer.js';
|
||||
|
||||
const PlusMonoid = {
|
||||
empty: () => 0,
|
||||
concat: (a, b) => a + b,
|
||||
};
|
||||
|
||||
const ConcatMonoid = {
|
||||
empty: () => [],
|
||||
concat: (a, b) => a.concat(b),
|
||||
};
|
||||
|
||||
const AndMonoid = {
|
||||
empty: () => true,
|
||||
concat: (a, b) => a && b,
|
||||
concatThunk: (a, b) => a && b(),
|
||||
};
|
||||
|
||||
const OrMonoid = {
|
||||
empty: () => false,
|
||||
concat: (a, b) => a || b,
|
||||
concatThunk: (a, b) => a || b(),
|
||||
};
|
||||
|
||||
|
||||
export class PlusReducer extends MonoidalReducer {
|
||||
constructor() {
|
||||
super(PlusMonoid);
|
||||
}
|
||||
}
|
||||
|
||||
export class ThunkedPlusReducer extends ThunkedMonoidalReducer {
|
||||
constructor() {
|
||||
super(PlusMonoid);
|
||||
}
|
||||
}
|
||||
|
||||
export class ConcatReducer extends MonoidalReducer {
|
||||
constructor() {
|
||||
super(ConcatMonoid);
|
||||
}
|
||||
}
|
||||
|
||||
export class ThunkedConcatReducer extends ThunkedMonoidalReducer {
|
||||
constructor() {
|
||||
super(ConcatMonoid);
|
||||
}
|
||||
}
|
||||
|
||||
export class AndReducer extends MonoidalReducer {
|
||||
constructor() {
|
||||
super(AndMonoid);
|
||||
}
|
||||
}
|
||||
|
||||
export class ThunkedAndReducer extends ThunkedMonoidalReducer {
|
||||
constructor() {
|
||||
super(AndMonoid);
|
||||
}
|
||||
}
|
||||
|
||||
export class OrReducer extends MonoidalReducer {
|
||||
constructor() {
|
||||
super(OrMonoid);
|
||||
}
|
||||
}
|
||||
|
||||
export class ThunkedOrReducer extends ThunkedMonoidalReducer {
|
||||
constructor() {
|
||||
super(OrMonoid);
|
||||
}
|
||||
}
|
||||
@@ -1,418 +0,0 @@
|
||||
// Generated by generate-director.js
|
||||
/**
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const director = {
|
||||
ArrayAssignmentTarget(reducer, node) {
|
||||
return reducer.reduceArrayAssignmentTarget(node, { elements: node.elements.map(v => v && (() => this[v.type](reducer, v))), rest: node.rest && (() => this[node.rest.type](reducer, node.rest)) });
|
||||
},
|
||||
|
||||
ArrayBinding(reducer, node) {
|
||||
return reducer.reduceArrayBinding(node, { elements: node.elements.map(v => v && (() => this[v.type](reducer, v))), rest: node.rest && (() => this[node.rest.type](reducer, node.rest)) });
|
||||
},
|
||||
|
||||
ArrayExpression(reducer, node) {
|
||||
return reducer.reduceArrayExpression(node, { elements: node.elements.map(v => v && (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
ArrowExpression(reducer, node) {
|
||||
return reducer.reduceArrowExpression(node, { params: (() => this.FormalParameters(reducer, node.params)), body: (() => this[node.body.type](reducer, node.body)) });
|
||||
},
|
||||
|
||||
AssignmentExpression(reducer, node) {
|
||||
return reducer.reduceAssignmentExpression(node, { binding: (() => this[node.binding.type](reducer, node.binding)), expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
AssignmentTargetIdentifier(reducer, node) {
|
||||
return reducer.reduceAssignmentTargetIdentifier(node);
|
||||
},
|
||||
|
||||
AssignmentTargetPropertyIdentifier(reducer, node) {
|
||||
return reducer.reduceAssignmentTargetPropertyIdentifier(node, { binding: (() => this.AssignmentTargetIdentifier(reducer, node.binding)), init: node.init && (() => this[node.init.type](reducer, node.init)) });
|
||||
},
|
||||
|
||||
AssignmentTargetPropertyProperty(reducer, node) {
|
||||
return reducer.reduceAssignmentTargetPropertyProperty(node, { name: (() => this[node.name.type](reducer, node.name)), binding: (() => this[node.binding.type](reducer, node.binding)) });
|
||||
},
|
||||
|
||||
AssignmentTargetWithDefault(reducer, node) {
|
||||
return reducer.reduceAssignmentTargetWithDefault(node, { binding: (() => this[node.binding.type](reducer, node.binding)), init: (() => this[node.init.type](reducer, node.init)) });
|
||||
},
|
||||
|
||||
AwaitExpression(reducer, node) {
|
||||
return reducer.reduceAwaitExpression(node, { expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
BinaryExpression(reducer, node) {
|
||||
return reducer.reduceBinaryExpression(node, { left: (() => this[node.left.type](reducer, node.left)), right: (() => this[node.right.type](reducer, node.right)) });
|
||||
},
|
||||
|
||||
BindingIdentifier(reducer, node) {
|
||||
return reducer.reduceBindingIdentifier(node);
|
||||
},
|
||||
|
||||
BindingPropertyIdentifier(reducer, node) {
|
||||
return reducer.reduceBindingPropertyIdentifier(node, { binding: (() => this.BindingIdentifier(reducer, node.binding)), init: node.init && (() => this[node.init.type](reducer, node.init)) });
|
||||
},
|
||||
|
||||
BindingPropertyProperty(reducer, node) {
|
||||
return reducer.reduceBindingPropertyProperty(node, { name: (() => this[node.name.type](reducer, node.name)), binding: (() => this[node.binding.type](reducer, node.binding)) });
|
||||
},
|
||||
|
||||
BindingWithDefault(reducer, node) {
|
||||
return reducer.reduceBindingWithDefault(node, { binding: (() => this[node.binding.type](reducer, node.binding)), init: (() => this[node.init.type](reducer, node.init)) });
|
||||
},
|
||||
|
||||
Block(reducer, node) {
|
||||
return reducer.reduceBlock(node, { statements: node.statements.map(v => (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
BlockStatement(reducer, node) {
|
||||
return reducer.reduceBlockStatement(node, { block: (() => this.Block(reducer, node.block)) });
|
||||
},
|
||||
|
||||
BreakStatement(reducer, node) {
|
||||
return reducer.reduceBreakStatement(node);
|
||||
},
|
||||
|
||||
CallExpression(reducer, node) {
|
||||
return reducer.reduceCallExpression(node, { callee: (() => this[node.callee.type](reducer, node.callee)), arguments: node.arguments.map(v => (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
CatchClause(reducer, node) {
|
||||
return reducer.reduceCatchClause(node, { binding: (() => this[node.binding.type](reducer, node.binding)), body: (() => this.Block(reducer, node.body)) });
|
||||
},
|
||||
|
||||
ClassDeclaration(reducer, node) {
|
||||
return reducer.reduceClassDeclaration(node, { name: (() => this.BindingIdentifier(reducer, node.name)), super: node.super && (() => this[node.super.type](reducer, node.super)), elements: node.elements.map(v => (() => this.ClassElement(reducer, v))) });
|
||||
},
|
||||
|
||||
ClassElement(reducer, node) {
|
||||
return reducer.reduceClassElement(node, { method: (() => this[node.method.type](reducer, node.method)) });
|
||||
},
|
||||
|
||||
ClassExpression(reducer, node) {
|
||||
return reducer.reduceClassExpression(node, { name: node.name && (() => this.BindingIdentifier(reducer, node.name)), super: node.super && (() => this[node.super.type](reducer, node.super)), elements: node.elements.map(v => (() => this.ClassElement(reducer, v))) });
|
||||
},
|
||||
|
||||
CompoundAssignmentExpression(reducer, node) {
|
||||
return reducer.reduceCompoundAssignmentExpression(node, { binding: (() => this[node.binding.type](reducer, node.binding)), expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
ComputedMemberAssignmentTarget(reducer, node) {
|
||||
return reducer.reduceComputedMemberAssignmentTarget(node, { object: (() => this[node.object.type](reducer, node.object)), expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
ComputedMemberExpression(reducer, node) {
|
||||
return reducer.reduceComputedMemberExpression(node, { object: (() => this[node.object.type](reducer, node.object)), expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
ComputedPropertyName(reducer, node) {
|
||||
return reducer.reduceComputedPropertyName(node, { expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
ConditionalExpression(reducer, node) {
|
||||
return reducer.reduceConditionalExpression(node, { test: (() => this[node.test.type](reducer, node.test)), consequent: (() => this[node.consequent.type](reducer, node.consequent)), alternate: (() => this[node.alternate.type](reducer, node.alternate)) });
|
||||
},
|
||||
|
||||
ContinueStatement(reducer, node) {
|
||||
return reducer.reduceContinueStatement(node);
|
||||
},
|
||||
|
||||
DataProperty(reducer, node) {
|
||||
return reducer.reduceDataProperty(node, { name: (() => this[node.name.type](reducer, node.name)), expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
DebuggerStatement(reducer, node) {
|
||||
return reducer.reduceDebuggerStatement(node);
|
||||
},
|
||||
|
||||
Directive(reducer, node) {
|
||||
return reducer.reduceDirective(node);
|
||||
},
|
||||
|
||||
DoWhileStatement(reducer, node) {
|
||||
return reducer.reduceDoWhileStatement(node, { body: (() => this[node.body.type](reducer, node.body)), test: (() => this[node.test.type](reducer, node.test)) });
|
||||
},
|
||||
|
||||
EmptyStatement(reducer, node) {
|
||||
return reducer.reduceEmptyStatement(node);
|
||||
},
|
||||
|
||||
Export(reducer, node) {
|
||||
return reducer.reduceExport(node, { declaration: (() => this[node.declaration.type](reducer, node.declaration)) });
|
||||
},
|
||||
|
||||
ExportAllFrom(reducer, node) {
|
||||
return reducer.reduceExportAllFrom(node);
|
||||
},
|
||||
|
||||
ExportDefault(reducer, node) {
|
||||
return reducer.reduceExportDefault(node, { body: (() => this[node.body.type](reducer, node.body)) });
|
||||
},
|
||||
|
||||
ExportFrom(reducer, node) {
|
||||
return reducer.reduceExportFrom(node, { namedExports: node.namedExports.map(v => (() => this.ExportFromSpecifier(reducer, v))) });
|
||||
},
|
||||
|
||||
ExportFromSpecifier(reducer, node) {
|
||||
return reducer.reduceExportFromSpecifier(node);
|
||||
},
|
||||
|
||||
ExportLocalSpecifier(reducer, node) {
|
||||
return reducer.reduceExportLocalSpecifier(node, { name: (() => this.IdentifierExpression(reducer, node.name)) });
|
||||
},
|
||||
|
||||
ExportLocals(reducer, node) {
|
||||
return reducer.reduceExportLocals(node, { namedExports: node.namedExports.map(v => (() => this.ExportLocalSpecifier(reducer, v))) });
|
||||
},
|
||||
|
||||
ExpressionStatement(reducer, node) {
|
||||
return reducer.reduceExpressionStatement(node, { expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
ForAwaitStatement(reducer, node) {
|
||||
return reducer.reduceForAwaitStatement(node, { left: (() => this[node.left.type](reducer, node.left)), right: (() => this[node.right.type](reducer, node.right)), body: (() => this[node.body.type](reducer, node.body)) });
|
||||
},
|
||||
|
||||
ForInStatement(reducer, node) {
|
||||
return reducer.reduceForInStatement(node, { left: (() => this[node.left.type](reducer, node.left)), right: (() => this[node.right.type](reducer, node.right)), body: (() => this[node.body.type](reducer, node.body)) });
|
||||
},
|
||||
|
||||
ForOfStatement(reducer, node) {
|
||||
return reducer.reduceForOfStatement(node, { left: (() => this[node.left.type](reducer, node.left)), right: (() => this[node.right.type](reducer, node.right)), body: (() => this[node.body.type](reducer, node.body)) });
|
||||
},
|
||||
|
||||
ForStatement(reducer, node) {
|
||||
return reducer.reduceForStatement(node, { init: node.init && (() => this[node.init.type](reducer, node.init)), test: node.test && (() => this[node.test.type](reducer, node.test)), update: node.update && (() => this[node.update.type](reducer, node.update)), body: (() => this[node.body.type](reducer, node.body)) });
|
||||
},
|
||||
|
||||
FormalParameters(reducer, node) {
|
||||
return reducer.reduceFormalParameters(node, { items: node.items.map(v => (() => this[v.type](reducer, v))), rest: node.rest && (() => this[node.rest.type](reducer, node.rest)) });
|
||||
},
|
||||
|
||||
FunctionBody(reducer, node) {
|
||||
return reducer.reduceFunctionBody(node, { directives: node.directives.map(v => (() => this.Directive(reducer, v))), statements: node.statements.map(v => (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
FunctionDeclaration(reducer, node) {
|
||||
return reducer.reduceFunctionDeclaration(node, { name: (() => this.BindingIdentifier(reducer, node.name)), params: (() => this.FormalParameters(reducer, node.params)), body: (() => this.FunctionBody(reducer, node.body)) });
|
||||
},
|
||||
|
||||
FunctionExpression(reducer, node) {
|
||||
return reducer.reduceFunctionExpression(node, { name: node.name && (() => this.BindingIdentifier(reducer, node.name)), params: (() => this.FormalParameters(reducer, node.params)), body: (() => this.FunctionBody(reducer, node.body)) });
|
||||
},
|
||||
|
||||
Getter(reducer, node) {
|
||||
return reducer.reduceGetter(node, { name: (() => this[node.name.type](reducer, node.name)), body: (() => this.FunctionBody(reducer, node.body)) });
|
||||
},
|
||||
|
||||
IdentifierExpression(reducer, node) {
|
||||
return reducer.reduceIdentifierExpression(node);
|
||||
},
|
||||
|
||||
IfStatement(reducer, node) {
|
||||
return reducer.reduceIfStatement(node, { test: (() => this[node.test.type](reducer, node.test)), consequent: (() => this[node.consequent.type](reducer, node.consequent)), alternate: node.alternate && (() => this[node.alternate.type](reducer, node.alternate)) });
|
||||
},
|
||||
|
||||
Import(reducer, node) {
|
||||
return reducer.reduceImport(node, { defaultBinding: node.defaultBinding && (() => this.BindingIdentifier(reducer, node.defaultBinding)), namedImports: node.namedImports.map(v => (() => this.ImportSpecifier(reducer, v))) });
|
||||
},
|
||||
|
||||
ImportNamespace(reducer, node) {
|
||||
return reducer.reduceImportNamespace(node, { defaultBinding: node.defaultBinding && (() => this.BindingIdentifier(reducer, node.defaultBinding)), namespaceBinding: (() => this.BindingIdentifier(reducer, node.namespaceBinding)) });
|
||||
},
|
||||
|
||||
ImportSpecifier(reducer, node) {
|
||||
return reducer.reduceImportSpecifier(node, { binding: (() => this.BindingIdentifier(reducer, node.binding)) });
|
||||
},
|
||||
|
||||
LabeledStatement(reducer, node) {
|
||||
return reducer.reduceLabeledStatement(node, { body: (() => this[node.body.type](reducer, node.body)) });
|
||||
},
|
||||
|
||||
LiteralBooleanExpression(reducer, node) {
|
||||
return reducer.reduceLiteralBooleanExpression(node);
|
||||
},
|
||||
|
||||
LiteralInfinityExpression(reducer, node) {
|
||||
return reducer.reduceLiteralInfinityExpression(node);
|
||||
},
|
||||
|
||||
LiteralNullExpression(reducer, node) {
|
||||
return reducer.reduceLiteralNullExpression(node);
|
||||
},
|
||||
|
||||
LiteralNumericExpression(reducer, node) {
|
||||
return reducer.reduceLiteralNumericExpression(node);
|
||||
},
|
||||
|
||||
LiteralRegExpExpression(reducer, node) {
|
||||
return reducer.reduceLiteralRegExpExpression(node);
|
||||
},
|
||||
|
||||
LiteralStringExpression(reducer, node) {
|
||||
return reducer.reduceLiteralStringExpression(node);
|
||||
},
|
||||
|
||||
Method(reducer, node) {
|
||||
return reducer.reduceMethod(node, { name: (() => this[node.name.type](reducer, node.name)), params: (() => this.FormalParameters(reducer, node.params)), body: (() => this.FunctionBody(reducer, node.body)) });
|
||||
},
|
||||
|
||||
Module(reducer, node) {
|
||||
return reducer.reduceModule(node, { directives: node.directives.map(v => (() => this.Directive(reducer, v))), items: node.items.map(v => (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
NewExpression(reducer, node) {
|
||||
return reducer.reduceNewExpression(node, { callee: (() => this[node.callee.type](reducer, node.callee)), arguments: node.arguments.map(v => (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
NewTargetExpression(reducer, node) {
|
||||
return reducer.reduceNewTargetExpression(node);
|
||||
},
|
||||
|
||||
ObjectAssignmentTarget(reducer, node) {
|
||||
return reducer.reduceObjectAssignmentTarget(node, { properties: node.properties.map(v => (() => this[v.type](reducer, v))), rest: node.rest && (() => this[node.rest.type](reducer, node.rest)) });
|
||||
},
|
||||
|
||||
ObjectBinding(reducer, node) {
|
||||
return reducer.reduceObjectBinding(node, { properties: node.properties.map(v => (() => this[v.type](reducer, v))), rest: node.rest && (() => this[node.rest.type](reducer, node.rest)) });
|
||||
},
|
||||
|
||||
ObjectExpression(reducer, node) {
|
||||
return reducer.reduceObjectExpression(node, { properties: node.properties.map(v => (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
ReturnStatement(reducer, node) {
|
||||
return reducer.reduceReturnStatement(node, { expression: node.expression && (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
Script(reducer, node) {
|
||||
return reducer.reduceScript(node, { directives: node.directives.map(v => (() => this.Directive(reducer, v))), statements: node.statements.map(v => (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
Setter(reducer, node) {
|
||||
return reducer.reduceSetter(node, { name: (() => this[node.name.type](reducer, node.name)), param: (() => this[node.param.type](reducer, node.param)), body: (() => this.FunctionBody(reducer, node.body)) });
|
||||
},
|
||||
|
||||
ShorthandProperty(reducer, node) {
|
||||
return reducer.reduceShorthandProperty(node, { name: (() => this.IdentifierExpression(reducer, node.name)) });
|
||||
},
|
||||
|
||||
SpreadElement(reducer, node) {
|
||||
return reducer.reduceSpreadElement(node, { expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
SpreadProperty(reducer, node) {
|
||||
return reducer.reduceSpreadProperty(node, { expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
StaticMemberAssignmentTarget(reducer, node) {
|
||||
return reducer.reduceStaticMemberAssignmentTarget(node, { object: (() => this[node.object.type](reducer, node.object)) });
|
||||
},
|
||||
|
||||
StaticMemberExpression(reducer, node) {
|
||||
return reducer.reduceStaticMemberExpression(node, { object: (() => this[node.object.type](reducer, node.object)) });
|
||||
},
|
||||
|
||||
StaticPropertyName(reducer, node) {
|
||||
return reducer.reduceStaticPropertyName(node);
|
||||
},
|
||||
|
||||
Super(reducer, node) {
|
||||
return reducer.reduceSuper(node);
|
||||
},
|
||||
|
||||
SwitchCase(reducer, node) {
|
||||
return reducer.reduceSwitchCase(node, { test: (() => this[node.test.type](reducer, node.test)), consequent: node.consequent.map(v => (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
SwitchDefault(reducer, node) {
|
||||
return reducer.reduceSwitchDefault(node, { consequent: node.consequent.map(v => (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
SwitchStatement(reducer, node) {
|
||||
return reducer.reduceSwitchStatement(node, { discriminant: (() => this[node.discriminant.type](reducer, node.discriminant)), cases: node.cases.map(v => (() => this.SwitchCase(reducer, v))) });
|
||||
},
|
||||
|
||||
SwitchStatementWithDefault(reducer, node) {
|
||||
return reducer.reduceSwitchStatementWithDefault(node, { discriminant: (() => this[node.discriminant.type](reducer, node.discriminant)), preDefaultCases: node.preDefaultCases.map(v => (() => this.SwitchCase(reducer, v))), defaultCase: (() => this.SwitchDefault(reducer, node.defaultCase)), postDefaultCases: node.postDefaultCases.map(v => (() => this.SwitchCase(reducer, v))) });
|
||||
},
|
||||
|
||||
TemplateElement(reducer, node) {
|
||||
return reducer.reduceTemplateElement(node);
|
||||
},
|
||||
|
||||
TemplateExpression(reducer, node) {
|
||||
return reducer.reduceTemplateExpression(node, { tag: node.tag && (() => this[node.tag.type](reducer, node.tag)), elements: node.elements.map(v => (() => this[v.type](reducer, v))) });
|
||||
},
|
||||
|
||||
ThisExpression(reducer, node) {
|
||||
return reducer.reduceThisExpression(node);
|
||||
},
|
||||
|
||||
ThrowStatement(reducer, node) {
|
||||
return reducer.reduceThrowStatement(node, { expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
TryCatchStatement(reducer, node) {
|
||||
return reducer.reduceTryCatchStatement(node, { body: (() => this.Block(reducer, node.body)), catchClause: (() => this.CatchClause(reducer, node.catchClause)) });
|
||||
},
|
||||
|
||||
TryFinallyStatement(reducer, node) {
|
||||
return reducer.reduceTryFinallyStatement(node, { body: (() => this.Block(reducer, node.body)), catchClause: node.catchClause && (() => this.CatchClause(reducer, node.catchClause)), finalizer: (() => this.Block(reducer, node.finalizer)) });
|
||||
},
|
||||
|
||||
UnaryExpression(reducer, node) {
|
||||
return reducer.reduceUnaryExpression(node, { operand: (() => this[node.operand.type](reducer, node.operand)) });
|
||||
},
|
||||
|
||||
UpdateExpression(reducer, node) {
|
||||
return reducer.reduceUpdateExpression(node, { operand: (() => this[node.operand.type](reducer, node.operand)) });
|
||||
},
|
||||
|
||||
VariableDeclaration(reducer, node) {
|
||||
return reducer.reduceVariableDeclaration(node, { declarators: node.declarators.map(v => (() => this.VariableDeclarator(reducer, v))) });
|
||||
},
|
||||
|
||||
VariableDeclarationStatement(reducer, node) {
|
||||
return reducer.reduceVariableDeclarationStatement(node, { declaration: (() => this.VariableDeclaration(reducer, node.declaration)) });
|
||||
},
|
||||
|
||||
VariableDeclarator(reducer, node) {
|
||||
return reducer.reduceVariableDeclarator(node, { binding: (() => this[node.binding.type](reducer, node.binding)), init: node.init && (() => this[node.init.type](reducer, node.init)) });
|
||||
},
|
||||
|
||||
WhileStatement(reducer, node) {
|
||||
return reducer.reduceWhileStatement(node, { test: (() => this[node.test.type](reducer, node.test)), body: (() => this[node.body.type](reducer, node.body)) });
|
||||
},
|
||||
|
||||
WithStatement(reducer, node) {
|
||||
return reducer.reduceWithStatement(node, { object: (() => this[node.object.type](reducer, node.object)), body: (() => this[node.body.type](reducer, node.body)) });
|
||||
},
|
||||
|
||||
YieldExpression(reducer, node) {
|
||||
return reducer.reduceYieldExpression(node, { expression: node.expression && (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
|
||||
YieldGeneratorExpression(reducer, node) {
|
||||
return reducer.reduceYieldGeneratorExpression(node, { expression: (() => this[node.expression.type](reducer, node.expression)) });
|
||||
},
|
||||
};
|
||||
|
||||
export function thunkedReduce(reducer, node) {
|
||||
return director[node.type](reducer, node);
|
||||
}
|
||||
@@ -1,444 +0,0 @@
|
||||
// Generated by generate-monoidal-reducer.js
|
||||
/**
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Shift from 'shift-ast';
|
||||
|
||||
export default class MonoidalReducer {
|
||||
constructor(monoid) {
|
||||
let identity = monoid.empty();
|
||||
this.identity = identity;
|
||||
|
||||
let concatThunk;
|
||||
if (monoid.prototype && typeof monoid.prototype.concatThunk === 'function') {
|
||||
concatThunk = Function.prototype.call.bind(monoid.prototype.concatThunk);
|
||||
} else if (typeof monoid.concatThunk === 'function') {
|
||||
concatThunk = monoid.concatThunk;
|
||||
} else {
|
||||
let concat;
|
||||
if (monoid.prototype && typeof monoid.prototype.concat === 'function') {
|
||||
concat = Function.prototype.call.bind(monoid.prototype.concat);
|
||||
} else if (typeof monoid.concat === 'function') {
|
||||
concat = monoid.concat;
|
||||
} else {
|
||||
throw new TypeError('Monoid must provide a `concatThunk` or `concat` method');
|
||||
}
|
||||
if (typeof monoid.isAbsorbing === 'function') {
|
||||
let isAbsorbing = monoid.isAbsorbing;
|
||||
concatThunk = (a, b) => isAbsorbing(a) ? a : concat(a, b());
|
||||
} else {
|
||||
concatThunk = (a, b) => concat(a, b());
|
||||
}
|
||||
}
|
||||
this.append = (...args) => args.reduce(concatThunk, identity);
|
||||
}
|
||||
|
||||
reduceArrayAssignmentTarget(node, { elements, rest }) {
|
||||
return this.append(...elements.filter(n => n != null), rest == null ? () => this.identity : rest);
|
||||
}
|
||||
|
||||
reduceArrayBinding(node, { elements, rest }) {
|
||||
return this.append(...elements.filter(n => n != null), rest == null ? () => this.identity : rest);
|
||||
}
|
||||
|
||||
reduceArrayExpression(node, { elements }) {
|
||||
return this.append(...elements.filter(n => n != null));
|
||||
}
|
||||
|
||||
reduceArrowExpression(node, { params, body }) {
|
||||
return this.append(params, body);
|
||||
}
|
||||
|
||||
reduceAssignmentExpression(node, { binding, expression }) {
|
||||
return this.append(binding, expression);
|
||||
}
|
||||
|
||||
reduceAssignmentTargetIdentifier(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) {
|
||||
return this.append(binding, init == null ? () => this.identity : init);
|
||||
}
|
||||
|
||||
reduceAssignmentTargetPropertyProperty(node, { name, binding }) {
|
||||
return this.append(name, binding);
|
||||
}
|
||||
|
||||
reduceAssignmentTargetWithDefault(node, { binding, init }) {
|
||||
return this.append(binding, init);
|
||||
}
|
||||
|
||||
reduceAwaitExpression(node, { expression }) {
|
||||
return expression();
|
||||
}
|
||||
|
||||
reduceBinaryExpression(node, { left, right }) {
|
||||
return this.append(left, right);
|
||||
}
|
||||
|
||||
reduceBindingIdentifier(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceBindingPropertyIdentifier(node, { binding, init }) {
|
||||
return this.append(binding, init == null ? () => this.identity : init);
|
||||
}
|
||||
|
||||
reduceBindingPropertyProperty(node, { name, binding }) {
|
||||
return this.append(name, binding);
|
||||
}
|
||||
|
||||
reduceBindingWithDefault(node, { binding, init }) {
|
||||
return this.append(binding, init);
|
||||
}
|
||||
|
||||
reduceBlock(node, { statements }) {
|
||||
return this.append(...statements);
|
||||
}
|
||||
|
||||
reduceBlockStatement(node, { block }) {
|
||||
return block();
|
||||
}
|
||||
|
||||
reduceBreakStatement(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceCallExpression(node, { callee, arguments: _arguments }) {
|
||||
return this.append(callee, ..._arguments);
|
||||
}
|
||||
|
||||
reduceCatchClause(node, { binding, body }) {
|
||||
return this.append(binding, body);
|
||||
}
|
||||
|
||||
reduceClassDeclaration(node, { name, super: _super, elements }) {
|
||||
return this.append(name, _super == null ? () => this.identity : _super, ...elements);
|
||||
}
|
||||
|
||||
reduceClassElement(node, { method }) {
|
||||
return method();
|
||||
}
|
||||
|
||||
reduceClassExpression(node, { name, super: _super, elements }) {
|
||||
return this.append(name == null ? () => this.identity : name, _super == null ? () => this.identity : _super, ...elements);
|
||||
}
|
||||
|
||||
reduceCompoundAssignmentExpression(node, { binding, expression }) {
|
||||
return this.append(binding, expression);
|
||||
}
|
||||
|
||||
reduceComputedMemberAssignmentTarget(node, { object, expression }) {
|
||||
return this.append(object, expression);
|
||||
}
|
||||
|
||||
reduceComputedMemberExpression(node, { object, expression }) {
|
||||
return this.append(object, expression);
|
||||
}
|
||||
|
||||
reduceComputedPropertyName(node, { expression }) {
|
||||
return expression();
|
||||
}
|
||||
|
||||
reduceConditionalExpression(node, { test, consequent, alternate }) {
|
||||
return this.append(test, consequent, alternate);
|
||||
}
|
||||
|
||||
reduceContinueStatement(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceDataProperty(node, { name, expression }) {
|
||||
return this.append(name, expression);
|
||||
}
|
||||
|
||||
reduceDebuggerStatement(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceDirective(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceDoWhileStatement(node, { body, test }) {
|
||||
return this.append(body, test);
|
||||
}
|
||||
|
||||
reduceEmptyStatement(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceExport(node, { declaration }) {
|
||||
return declaration();
|
||||
}
|
||||
|
||||
reduceExportAllFrom(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceExportDefault(node, { body }) {
|
||||
return body();
|
||||
}
|
||||
|
||||
reduceExportFrom(node, { namedExports }) {
|
||||
return this.append(...namedExports);
|
||||
}
|
||||
|
||||
reduceExportFromSpecifier(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceExportLocalSpecifier(node, { name }) {
|
||||
return name();
|
||||
}
|
||||
|
||||
reduceExportLocals(node, { namedExports }) {
|
||||
return this.append(...namedExports);
|
||||
}
|
||||
|
||||
reduceExpressionStatement(node, { expression }) {
|
||||
return expression();
|
||||
}
|
||||
|
||||
reduceForAwaitStatement(node, { left, right, body }) {
|
||||
return this.append(left, right, body);
|
||||
}
|
||||
|
||||
reduceForInStatement(node, { left, right, body }) {
|
||||
return this.append(left, right, body);
|
||||
}
|
||||
|
||||
reduceForOfStatement(node, { left, right, body }) {
|
||||
return this.append(left, right, body);
|
||||
}
|
||||
|
||||
reduceForStatement(node, { init, test, update, body }) {
|
||||
return this.append(init == null ? () => this.identity : init, test == null ? () => this.identity : test, update == null ? () => this.identity : update, body);
|
||||
}
|
||||
|
||||
reduceFormalParameters(node, { items, rest }) {
|
||||
return this.append(...items, rest == null ? () => this.identity : rest);
|
||||
}
|
||||
|
||||
reduceFunctionBody(node, { directives, statements }) {
|
||||
return this.append(...directives, ...statements);
|
||||
}
|
||||
|
||||
reduceFunctionDeclaration(node, { name, params, body }) {
|
||||
return this.append(name, params, body);
|
||||
}
|
||||
|
||||
reduceFunctionExpression(node, { name, params, body }) {
|
||||
return this.append(name == null ? () => this.identity : name, params, body);
|
||||
}
|
||||
|
||||
reduceGetter(node, { name, body }) {
|
||||
return this.append(name, body);
|
||||
}
|
||||
|
||||
reduceIdentifierExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceIfStatement(node, { test, consequent, alternate }) {
|
||||
return this.append(test, consequent, alternate == null ? () => this.identity : alternate);
|
||||
}
|
||||
|
||||
reduceImport(node, { defaultBinding, namedImports }) {
|
||||
return this.append(defaultBinding == null ? () => this.identity : defaultBinding, ...namedImports);
|
||||
}
|
||||
|
||||
reduceImportNamespace(node, { defaultBinding, namespaceBinding }) {
|
||||
return this.append(defaultBinding == null ? () => this.identity : defaultBinding, namespaceBinding);
|
||||
}
|
||||
|
||||
reduceImportSpecifier(node, { binding }) {
|
||||
return binding();
|
||||
}
|
||||
|
||||
reduceLabeledStatement(node, { body }) {
|
||||
return body();
|
||||
}
|
||||
|
||||
reduceLiteralBooleanExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceLiteralInfinityExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceLiteralNullExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceLiteralNumericExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceLiteralRegExpExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceLiteralStringExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceMethod(node, { name, params, body }) {
|
||||
return this.append(name, params, body);
|
||||
}
|
||||
|
||||
reduceModule(node, { directives, items }) {
|
||||
return this.append(...directives, ...items);
|
||||
}
|
||||
|
||||
reduceNewExpression(node, { callee, arguments: _arguments }) {
|
||||
return this.append(callee, ..._arguments);
|
||||
}
|
||||
|
||||
reduceNewTargetExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceObjectAssignmentTarget(node, { properties, rest }) {
|
||||
return this.append(...properties, rest == null ? () => this.identity : rest);
|
||||
}
|
||||
|
||||
reduceObjectBinding(node, { properties, rest }) {
|
||||
return this.append(...properties, rest == null ? () => this.identity : rest);
|
||||
}
|
||||
|
||||
reduceObjectExpression(node, { properties }) {
|
||||
return this.append(...properties);
|
||||
}
|
||||
|
||||
reduceReturnStatement(node, { expression }) {
|
||||
return expression == null ? this.identity : expression();
|
||||
}
|
||||
|
||||
reduceScript(node, { directives, statements }) {
|
||||
return this.append(...directives, ...statements);
|
||||
}
|
||||
|
||||
reduceSetter(node, { name, param, body }) {
|
||||
return this.append(name, param, body);
|
||||
}
|
||||
|
||||
reduceShorthandProperty(node, { name }) {
|
||||
return name();
|
||||
}
|
||||
|
||||
reduceSpreadElement(node, { expression }) {
|
||||
return expression();
|
||||
}
|
||||
|
||||
reduceSpreadProperty(node, { expression }) {
|
||||
return expression();
|
||||
}
|
||||
|
||||
reduceStaticMemberAssignmentTarget(node, { object }) {
|
||||
return object();
|
||||
}
|
||||
|
||||
reduceStaticMemberExpression(node, { object }) {
|
||||
return object();
|
||||
}
|
||||
|
||||
reduceStaticPropertyName(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceSuper(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceSwitchCase(node, { test, consequent }) {
|
||||
return this.append(test, ...consequent);
|
||||
}
|
||||
|
||||
reduceSwitchDefault(node, { consequent }) {
|
||||
return this.append(...consequent);
|
||||
}
|
||||
|
||||
reduceSwitchStatement(node, { discriminant, cases }) {
|
||||
return this.append(discriminant, ...cases);
|
||||
}
|
||||
|
||||
reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) {
|
||||
return this.append(discriminant, ...preDefaultCases, defaultCase, ...postDefaultCases);
|
||||
}
|
||||
|
||||
reduceTemplateElement(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceTemplateExpression(node, { tag, elements }) {
|
||||
return this.append(tag == null ? () => this.identity : tag, ...elements);
|
||||
}
|
||||
|
||||
reduceThisExpression(node) {
|
||||
return this.identity;
|
||||
}
|
||||
|
||||
reduceThrowStatement(node, { expression }) {
|
||||
return expression();
|
||||
}
|
||||
|
||||
reduceTryCatchStatement(node, { body, catchClause }) {
|
||||
return this.append(body, catchClause);
|
||||
}
|
||||
|
||||
reduceTryFinallyStatement(node, { body, catchClause, finalizer }) {
|
||||
return this.append(body, catchClause == null ? () => this.identity : catchClause, finalizer);
|
||||
}
|
||||
|
||||
reduceUnaryExpression(node, { operand }) {
|
||||
return operand();
|
||||
}
|
||||
|
||||
reduceUpdateExpression(node, { operand }) {
|
||||
return operand();
|
||||
}
|
||||
|
||||
reduceVariableDeclaration(node, { declarators }) {
|
||||
return this.append(...declarators);
|
||||
}
|
||||
|
||||
reduceVariableDeclarationStatement(node, { declaration }) {
|
||||
return declaration();
|
||||
}
|
||||
|
||||
reduceVariableDeclarator(node, { binding, init }) {
|
||||
return this.append(binding, init == null ? () => this.identity : init);
|
||||
}
|
||||
|
||||
reduceWhileStatement(node, { test, body }) {
|
||||
return this.append(test, body);
|
||||
}
|
||||
|
||||
reduceWithStatement(node, { object, body }) {
|
||||
return this.append(object, body);
|
||||
}
|
||||
|
||||
reduceYieldExpression(node, { expression }) {
|
||||
return expression == null ? this.identity : expression();
|
||||
}
|
||||
|
||||
reduceYieldGeneratorExpression(node, { expression }) {
|
||||
return expression();
|
||||
}
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
// Generated by generate-thunkify.js
|
||||
/**
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export default function thunkifyClass(reducerClass) {
|
||||
return class extends reducerClass {
|
||||
reduceArrayAssignmentTarget(node, { elements, rest }) {
|
||||
return super.reduceArrayAssignmentTarget(node, { elements: elements.map(n => n == null ? null : n()), rest: rest == null ? null : rest() });
|
||||
}
|
||||
|
||||
reduceArrayBinding(node, { elements, rest }) {
|
||||
return super.reduceArrayBinding(node, { elements: elements.map(n => n == null ? null : n()), rest: rest == null ? null : rest() });
|
||||
}
|
||||
|
||||
reduceArrayExpression(node, { elements }) {
|
||||
return super.reduceArrayExpression(node, { elements: elements.map(n => n == null ? null : n()) });
|
||||
}
|
||||
|
||||
reduceArrowExpression(node, { params, body }) {
|
||||
return super.reduceArrowExpression(node, { params: params(), body: body() });
|
||||
}
|
||||
|
||||
reduceAssignmentExpression(node, { binding, expression }) {
|
||||
return super.reduceAssignmentExpression(node, { binding: binding(), expression: expression() });
|
||||
}
|
||||
|
||||
reduceAssignmentTargetIdentifier(node) {
|
||||
return super.reduceAssignmentTargetIdentifier(node);
|
||||
}
|
||||
|
||||
reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) {
|
||||
return super.reduceAssignmentTargetPropertyIdentifier(node, { binding: binding(), init: init == null ? null : init() });
|
||||
}
|
||||
|
||||
reduceAssignmentTargetPropertyProperty(node, { name, binding }) {
|
||||
return super.reduceAssignmentTargetPropertyProperty(node, { name: name(), binding: binding() });
|
||||
}
|
||||
|
||||
reduceAssignmentTargetWithDefault(node, { binding, init }) {
|
||||
return super.reduceAssignmentTargetWithDefault(node, { binding: binding(), init: init() });
|
||||
}
|
||||
|
||||
reduceAwaitExpression(node, { expression }) {
|
||||
return super.reduceAwaitExpression(node, { expression: expression() });
|
||||
}
|
||||
|
||||
reduceBinaryExpression(node, { left, right }) {
|
||||
return super.reduceBinaryExpression(node, { left: left(), right: right() });
|
||||
}
|
||||
|
||||
reduceBindingIdentifier(node) {
|
||||
return super.reduceBindingIdentifier(node);
|
||||
}
|
||||
|
||||
reduceBindingPropertyIdentifier(node, { binding, init }) {
|
||||
return super.reduceBindingPropertyIdentifier(node, { binding: binding(), init: init == null ? null : init() });
|
||||
}
|
||||
|
||||
reduceBindingPropertyProperty(node, { name, binding }) {
|
||||
return super.reduceBindingPropertyProperty(node, { name: name(), binding: binding() });
|
||||
}
|
||||
|
||||
reduceBindingWithDefault(node, { binding, init }) {
|
||||
return super.reduceBindingWithDefault(node, { binding: binding(), init: init() });
|
||||
}
|
||||
|
||||
reduceBlock(node, { statements }) {
|
||||
return super.reduceBlock(node, { statements: statements.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceBlockStatement(node, { block }) {
|
||||
return super.reduceBlockStatement(node, { block: block() });
|
||||
}
|
||||
|
||||
reduceBreakStatement(node) {
|
||||
return super.reduceBreakStatement(node);
|
||||
}
|
||||
|
||||
reduceCallExpression(node, { callee, arguments: _arguments }) {
|
||||
return super.reduceCallExpression(node, { callee: callee(), arguments: _arguments.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceCatchClause(node, { binding, body }) {
|
||||
return super.reduceCatchClause(node, { binding: binding(), body: body() });
|
||||
}
|
||||
|
||||
reduceClassDeclaration(node, { name, super: _super, elements }) {
|
||||
return super.reduceClassDeclaration(node, { name: name(), super: _super == null ? null : _super(), elements: elements.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceClassElement(node, { method }) {
|
||||
return super.reduceClassElement(node, { method: method() });
|
||||
}
|
||||
|
||||
reduceClassExpression(node, { name, super: _super, elements }) {
|
||||
return super.reduceClassExpression(node, { name: name == null ? null : name(), super: _super == null ? null : _super(), elements: elements.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceCompoundAssignmentExpression(node, { binding, expression }) {
|
||||
return super.reduceCompoundAssignmentExpression(node, { binding: binding(), expression: expression() });
|
||||
}
|
||||
|
||||
reduceComputedMemberAssignmentTarget(node, { object, expression }) {
|
||||
return super.reduceComputedMemberAssignmentTarget(node, { object: object(), expression: expression() });
|
||||
}
|
||||
|
||||
reduceComputedMemberExpression(node, { object, expression }) {
|
||||
return super.reduceComputedMemberExpression(node, { object: object(), expression: expression() });
|
||||
}
|
||||
|
||||
reduceComputedPropertyName(node, { expression }) {
|
||||
return super.reduceComputedPropertyName(node, { expression: expression() });
|
||||
}
|
||||
|
||||
reduceConditionalExpression(node, { test, consequent, alternate }) {
|
||||
return super.reduceConditionalExpression(node, { test: test(), consequent: consequent(), alternate: alternate() });
|
||||
}
|
||||
|
||||
reduceContinueStatement(node) {
|
||||
return super.reduceContinueStatement(node);
|
||||
}
|
||||
|
||||
reduceDataProperty(node, { name, expression }) {
|
||||
return super.reduceDataProperty(node, { name: name(), expression: expression() });
|
||||
}
|
||||
|
||||
reduceDebuggerStatement(node) {
|
||||
return super.reduceDebuggerStatement(node);
|
||||
}
|
||||
|
||||
reduceDirective(node) {
|
||||
return super.reduceDirective(node);
|
||||
}
|
||||
|
||||
reduceDoWhileStatement(node, { body, test }) {
|
||||
return super.reduceDoWhileStatement(node, { body: body(), test: test() });
|
||||
}
|
||||
|
||||
reduceEmptyStatement(node) {
|
||||
return super.reduceEmptyStatement(node);
|
||||
}
|
||||
|
||||
reduceExport(node, { declaration }) {
|
||||
return super.reduceExport(node, { declaration: declaration() });
|
||||
}
|
||||
|
||||
reduceExportAllFrom(node) {
|
||||
return super.reduceExportAllFrom(node);
|
||||
}
|
||||
|
||||
reduceExportDefault(node, { body }) {
|
||||
return super.reduceExportDefault(node, { body: body() });
|
||||
}
|
||||
|
||||
reduceExportFrom(node, { namedExports }) {
|
||||
return super.reduceExportFrom(node, { namedExports: namedExports.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceExportFromSpecifier(node) {
|
||||
return super.reduceExportFromSpecifier(node);
|
||||
}
|
||||
|
||||
reduceExportLocalSpecifier(node, { name }) {
|
||||
return super.reduceExportLocalSpecifier(node, { name: name() });
|
||||
}
|
||||
|
||||
reduceExportLocals(node, { namedExports }) {
|
||||
return super.reduceExportLocals(node, { namedExports: namedExports.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceExpressionStatement(node, { expression }) {
|
||||
return super.reduceExpressionStatement(node, { expression: expression() });
|
||||
}
|
||||
|
||||
reduceForAwaitStatement(node, { left, right, body }) {
|
||||
return super.reduceForAwaitStatement(node, { left: left(), right: right(), body: body() });
|
||||
}
|
||||
|
||||
reduceForInStatement(node, { left, right, body }) {
|
||||
return super.reduceForInStatement(node, { left: left(), right: right(), body: body() });
|
||||
}
|
||||
|
||||
reduceForOfStatement(node, { left, right, body }) {
|
||||
return super.reduceForOfStatement(node, { left: left(), right: right(), body: body() });
|
||||
}
|
||||
|
||||
reduceForStatement(node, { init, test, update, body }) {
|
||||
return super.reduceForStatement(node, { init: init == null ? null : init(), test: test == null ? null : test(), update: update == null ? null : update(), body: body() });
|
||||
}
|
||||
|
||||
reduceFormalParameters(node, { items, rest }) {
|
||||
return super.reduceFormalParameters(node, { items: items.map(n => n()), rest: rest == null ? null : rest() });
|
||||
}
|
||||
|
||||
reduceFunctionBody(node, { directives, statements }) {
|
||||
return super.reduceFunctionBody(node, { directives: directives.map(n => n()), statements: statements.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceFunctionDeclaration(node, { name, params, body }) {
|
||||
return super.reduceFunctionDeclaration(node, { name: name(), params: params(), body: body() });
|
||||
}
|
||||
|
||||
reduceFunctionExpression(node, { name, params, body }) {
|
||||
return super.reduceFunctionExpression(node, { name: name == null ? null : name(), params: params(), body: body() });
|
||||
}
|
||||
|
||||
reduceGetter(node, { name, body }) {
|
||||
return super.reduceGetter(node, { name: name(), body: body() });
|
||||
}
|
||||
|
||||
reduceIdentifierExpression(node) {
|
||||
return super.reduceIdentifierExpression(node);
|
||||
}
|
||||
|
||||
reduceIfStatement(node, { test, consequent, alternate }) {
|
||||
return super.reduceIfStatement(node, { test: test(), consequent: consequent(), alternate: alternate == null ? null : alternate() });
|
||||
}
|
||||
|
||||
reduceImport(node, { defaultBinding, namedImports }) {
|
||||
return super.reduceImport(node, { defaultBinding: defaultBinding == null ? null : defaultBinding(), namedImports: namedImports.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceImportNamespace(node, { defaultBinding, namespaceBinding }) {
|
||||
return super.reduceImportNamespace(node, { defaultBinding: defaultBinding == null ? null : defaultBinding(), namespaceBinding: namespaceBinding() });
|
||||
}
|
||||
|
||||
reduceImportSpecifier(node, { binding }) {
|
||||
return super.reduceImportSpecifier(node, { binding: binding() });
|
||||
}
|
||||
|
||||
reduceLabeledStatement(node, { body }) {
|
||||
return super.reduceLabeledStatement(node, { body: body() });
|
||||
}
|
||||
|
||||
reduceLiteralBooleanExpression(node) {
|
||||
return super.reduceLiteralBooleanExpression(node);
|
||||
}
|
||||
|
||||
reduceLiteralInfinityExpression(node) {
|
||||
return super.reduceLiteralInfinityExpression(node);
|
||||
}
|
||||
|
||||
reduceLiteralNullExpression(node) {
|
||||
return super.reduceLiteralNullExpression(node);
|
||||
}
|
||||
|
||||
reduceLiteralNumericExpression(node) {
|
||||
return super.reduceLiteralNumericExpression(node);
|
||||
}
|
||||
|
||||
reduceLiteralRegExpExpression(node) {
|
||||
return super.reduceLiteralRegExpExpression(node);
|
||||
}
|
||||
|
||||
reduceLiteralStringExpression(node) {
|
||||
return super.reduceLiteralStringExpression(node);
|
||||
}
|
||||
|
||||
reduceMethod(node, { name, params, body }) {
|
||||
return super.reduceMethod(node, { name: name(), params: params(), body: body() });
|
||||
}
|
||||
|
||||
reduceModule(node, { directives, items }) {
|
||||
return super.reduceModule(node, { directives: directives.map(n => n()), items: items.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceNewExpression(node, { callee, arguments: _arguments }) {
|
||||
return super.reduceNewExpression(node, { callee: callee(), arguments: _arguments.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceNewTargetExpression(node) {
|
||||
return super.reduceNewTargetExpression(node);
|
||||
}
|
||||
|
||||
reduceObjectAssignmentTarget(node, { properties, rest }) {
|
||||
return super.reduceObjectAssignmentTarget(node, { properties: properties.map(n => n()), rest: rest == null ? null : rest() });
|
||||
}
|
||||
|
||||
reduceObjectBinding(node, { properties, rest }) {
|
||||
return super.reduceObjectBinding(node, { properties: properties.map(n => n()), rest: rest == null ? null : rest() });
|
||||
}
|
||||
|
||||
reduceObjectExpression(node, { properties }) {
|
||||
return super.reduceObjectExpression(node, { properties: properties.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceReturnStatement(node, { expression }) {
|
||||
return super.reduceReturnStatement(node, { expression: expression == null ? null : expression() });
|
||||
}
|
||||
|
||||
reduceScript(node, { directives, statements }) {
|
||||
return super.reduceScript(node, { directives: directives.map(n => n()), statements: statements.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceSetter(node, { name, param, body }) {
|
||||
return super.reduceSetter(node, { name: name(), param: param(), body: body() });
|
||||
}
|
||||
|
||||
reduceShorthandProperty(node, { name }) {
|
||||
return super.reduceShorthandProperty(node, { name: name() });
|
||||
}
|
||||
|
||||
reduceSpreadElement(node, { expression }) {
|
||||
return super.reduceSpreadElement(node, { expression: expression() });
|
||||
}
|
||||
|
||||
reduceSpreadProperty(node, { expression }) {
|
||||
return super.reduceSpreadProperty(node, { expression: expression() });
|
||||
}
|
||||
|
||||
reduceStaticMemberAssignmentTarget(node, { object }) {
|
||||
return super.reduceStaticMemberAssignmentTarget(node, { object: object() });
|
||||
}
|
||||
|
||||
reduceStaticMemberExpression(node, { object }) {
|
||||
return super.reduceStaticMemberExpression(node, { object: object() });
|
||||
}
|
||||
|
||||
reduceStaticPropertyName(node) {
|
||||
return super.reduceStaticPropertyName(node);
|
||||
}
|
||||
|
||||
reduceSuper(node) {
|
||||
return super.reduceSuper(node);
|
||||
}
|
||||
|
||||
reduceSwitchCase(node, { test, consequent }) {
|
||||
return super.reduceSwitchCase(node, { test: test(), consequent: consequent.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceSwitchDefault(node, { consequent }) {
|
||||
return super.reduceSwitchDefault(node, { consequent: consequent.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceSwitchStatement(node, { discriminant, cases }) {
|
||||
return super.reduceSwitchStatement(node, { discriminant: discriminant(), cases: cases.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) {
|
||||
return super.reduceSwitchStatementWithDefault(node, { discriminant: discriminant(), preDefaultCases: preDefaultCases.map(n => n()), defaultCase: defaultCase(), postDefaultCases: postDefaultCases.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceTemplateElement(node) {
|
||||
return super.reduceTemplateElement(node);
|
||||
}
|
||||
|
||||
reduceTemplateExpression(node, { tag, elements }) {
|
||||
return super.reduceTemplateExpression(node, { tag: tag == null ? null : tag(), elements: elements.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceThisExpression(node) {
|
||||
return super.reduceThisExpression(node);
|
||||
}
|
||||
|
||||
reduceThrowStatement(node, { expression }) {
|
||||
return super.reduceThrowStatement(node, { expression: expression() });
|
||||
}
|
||||
|
||||
reduceTryCatchStatement(node, { body, catchClause }) {
|
||||
return super.reduceTryCatchStatement(node, { body: body(), catchClause: catchClause() });
|
||||
}
|
||||
|
||||
reduceTryFinallyStatement(node, { body, catchClause, finalizer }) {
|
||||
return super.reduceTryFinallyStatement(node, { body: body(), catchClause: catchClause == null ? null : catchClause(), finalizer: finalizer() });
|
||||
}
|
||||
|
||||
reduceUnaryExpression(node, { operand }) {
|
||||
return super.reduceUnaryExpression(node, { operand: operand() });
|
||||
}
|
||||
|
||||
reduceUpdateExpression(node, { operand }) {
|
||||
return super.reduceUpdateExpression(node, { operand: operand() });
|
||||
}
|
||||
|
||||
reduceVariableDeclaration(node, { declarators }) {
|
||||
return super.reduceVariableDeclaration(node, { declarators: declarators.map(n => n()) });
|
||||
}
|
||||
|
||||
reduceVariableDeclarationStatement(node, { declaration }) {
|
||||
return super.reduceVariableDeclarationStatement(node, { declaration: declaration() });
|
||||
}
|
||||
|
||||
reduceVariableDeclarator(node, { binding, init }) {
|
||||
return super.reduceVariableDeclarator(node, { binding: binding(), init: init == null ? null : init() });
|
||||
}
|
||||
|
||||
reduceWhileStatement(node, { test, body }) {
|
||||
return super.reduceWhileStatement(node, { test: test(), body: body() });
|
||||
}
|
||||
|
||||
reduceWithStatement(node, { object, body }) {
|
||||
return super.reduceWithStatement(node, { object: object(), body: body() });
|
||||
}
|
||||
|
||||
reduceYieldExpression(node, { expression }) {
|
||||
return super.reduceYieldExpression(node, { expression: expression == null ? null : expression() });
|
||||
}
|
||||
|
||||
reduceYieldGeneratorExpression(node, { expression }) {
|
||||
return super.reduceYieldGeneratorExpression(node, { expression: expression() });
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
// Generated by generate-thunkify.js
|
||||
/**
|
||||
* Copyright 2018 Shape Security, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License")
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export default function thunkify(reducer) {
|
||||
return {
|
||||
reduceArrayAssignmentTarget(node, { elements, rest }) {
|
||||
return reducer.reduceArrayAssignmentTarget(node, { elements: elements.map(n => n == null ? null : n()), rest: rest == null ? null : rest() });
|
||||
},
|
||||
|
||||
reduceArrayBinding(node, { elements, rest }) {
|
||||
return reducer.reduceArrayBinding(node, { elements: elements.map(n => n == null ? null : n()), rest: rest == null ? null : rest() });
|
||||
},
|
||||
|
||||
reduceArrayExpression(node, { elements }) {
|
||||
return reducer.reduceArrayExpression(node, { elements: elements.map(n => n == null ? null : n()) });
|
||||
},
|
||||
|
||||
reduceArrowExpression(node, { params, body }) {
|
||||
return reducer.reduceArrowExpression(node, { params: params(), body: body() });
|
||||
},
|
||||
|
||||
reduceAssignmentExpression(node, { binding, expression }) {
|
||||
return reducer.reduceAssignmentExpression(node, { binding: binding(), expression: expression() });
|
||||
},
|
||||
|
||||
reduceAssignmentTargetIdentifier(node) {
|
||||
return reducer.reduceAssignmentTargetIdentifier(node);
|
||||
},
|
||||
|
||||
reduceAssignmentTargetPropertyIdentifier(node, { binding, init }) {
|
||||
return reducer.reduceAssignmentTargetPropertyIdentifier(node, { binding: binding(), init: init == null ? null : init() });
|
||||
},
|
||||
|
||||
reduceAssignmentTargetPropertyProperty(node, { name, binding }) {
|
||||
return reducer.reduceAssignmentTargetPropertyProperty(node, { name: name(), binding: binding() });
|
||||
},
|
||||
|
||||
reduceAssignmentTargetWithDefault(node, { binding, init }) {
|
||||
return reducer.reduceAssignmentTargetWithDefault(node, { binding: binding(), init: init() });
|
||||
},
|
||||
|
||||
reduceAwaitExpression(node, { expression }) {
|
||||
return reducer.reduceAwaitExpression(node, { expression: expression() });
|
||||
},
|
||||
|
||||
reduceBinaryExpression(node, { left, right }) {
|
||||
return reducer.reduceBinaryExpression(node, { left: left(), right: right() });
|
||||
},
|
||||
|
||||
reduceBindingIdentifier(node) {
|
||||
return reducer.reduceBindingIdentifier(node);
|
||||
},
|
||||
|
||||
reduceBindingPropertyIdentifier(node, { binding, init }) {
|
||||
return reducer.reduceBindingPropertyIdentifier(node, { binding: binding(), init: init == null ? null : init() });
|
||||
},
|
||||
|
||||
reduceBindingPropertyProperty(node, { name, binding }) {
|
||||
return reducer.reduceBindingPropertyProperty(node, { name: name(), binding: binding() });
|
||||
},
|
||||
|
||||
reduceBindingWithDefault(node, { binding, init }) {
|
||||
return reducer.reduceBindingWithDefault(node, { binding: binding(), init: init() });
|
||||
},
|
||||
|
||||
reduceBlock(node, { statements }) {
|
||||
return reducer.reduceBlock(node, { statements: statements.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceBlockStatement(node, { block }) {
|
||||
return reducer.reduceBlockStatement(node, { block: block() });
|
||||
},
|
||||
|
||||
reduceBreakStatement(node) {
|
||||
return reducer.reduceBreakStatement(node);
|
||||
},
|
||||
|
||||
reduceCallExpression(node, { callee, arguments: _arguments }) {
|
||||
return reducer.reduceCallExpression(node, { callee: callee(), arguments: _arguments.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceCatchClause(node, { binding, body }) {
|
||||
return reducer.reduceCatchClause(node, { binding: binding(), body: body() });
|
||||
},
|
||||
|
||||
reduceClassDeclaration(node, { name, super: _super, elements }) {
|
||||
return reducer.reduceClassDeclaration(node, { name: name(), super: _super == null ? null : _super(), elements: elements.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceClassElement(node, { method }) {
|
||||
return reducer.reduceClassElement(node, { method: method() });
|
||||
},
|
||||
|
||||
reduceClassExpression(node, { name, super: _super, elements }) {
|
||||
return reducer.reduceClassExpression(node, { name: name == null ? null : name(), super: _super == null ? null : _super(), elements: elements.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceCompoundAssignmentExpression(node, { binding, expression }) {
|
||||
return reducer.reduceCompoundAssignmentExpression(node, { binding: binding(), expression: expression() });
|
||||
},
|
||||
|
||||
reduceComputedMemberAssignmentTarget(node, { object, expression }) {
|
||||
return reducer.reduceComputedMemberAssignmentTarget(node, { object: object(), expression: expression() });
|
||||
},
|
||||
|
||||
reduceComputedMemberExpression(node, { object, expression }) {
|
||||
return reducer.reduceComputedMemberExpression(node, { object: object(), expression: expression() });
|
||||
},
|
||||
|
||||
reduceComputedPropertyName(node, { expression }) {
|
||||
return reducer.reduceComputedPropertyName(node, { expression: expression() });
|
||||
},
|
||||
|
||||
reduceConditionalExpression(node, { test, consequent, alternate }) {
|
||||
return reducer.reduceConditionalExpression(node, { test: test(), consequent: consequent(), alternate: alternate() });
|
||||
},
|
||||
|
||||
reduceContinueStatement(node) {
|
||||
return reducer.reduceContinueStatement(node);
|
||||
},
|
||||
|
||||
reduceDataProperty(node, { name, expression }) {
|
||||
return reducer.reduceDataProperty(node, { name: name(), expression: expression() });
|
||||
},
|
||||
|
||||
reduceDebuggerStatement(node) {
|
||||
return reducer.reduceDebuggerStatement(node);
|
||||
},
|
||||
|
||||
reduceDirective(node) {
|
||||
return reducer.reduceDirective(node);
|
||||
},
|
||||
|
||||
reduceDoWhileStatement(node, { body, test }) {
|
||||
return reducer.reduceDoWhileStatement(node, { body: body(), test: test() });
|
||||
},
|
||||
|
||||
reduceEmptyStatement(node) {
|
||||
return reducer.reduceEmptyStatement(node);
|
||||
},
|
||||
|
||||
reduceExport(node, { declaration }) {
|
||||
return reducer.reduceExport(node, { declaration: declaration() });
|
||||
},
|
||||
|
||||
reduceExportAllFrom(node) {
|
||||
return reducer.reduceExportAllFrom(node);
|
||||
},
|
||||
|
||||
reduceExportDefault(node, { body }) {
|
||||
return reducer.reduceExportDefault(node, { body: body() });
|
||||
},
|
||||
|
||||
reduceExportFrom(node, { namedExports }) {
|
||||
return reducer.reduceExportFrom(node, { namedExports: namedExports.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceExportFromSpecifier(node) {
|
||||
return reducer.reduceExportFromSpecifier(node);
|
||||
},
|
||||
|
||||
reduceExportLocalSpecifier(node, { name }) {
|
||||
return reducer.reduceExportLocalSpecifier(node, { name: name() });
|
||||
},
|
||||
|
||||
reduceExportLocals(node, { namedExports }) {
|
||||
return reducer.reduceExportLocals(node, { namedExports: namedExports.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceExpressionStatement(node, { expression }) {
|
||||
return reducer.reduceExpressionStatement(node, { expression: expression() });
|
||||
},
|
||||
|
||||
reduceForAwaitStatement(node, { left, right, body }) {
|
||||
return reducer.reduceForAwaitStatement(node, { left: left(), right: right(), body: body() });
|
||||
},
|
||||
|
||||
reduceForInStatement(node, { left, right, body }) {
|
||||
return reducer.reduceForInStatement(node, { left: left(), right: right(), body: body() });
|
||||
},
|
||||
|
||||
reduceForOfStatement(node, { left, right, body }) {
|
||||
return reducer.reduceForOfStatement(node, { left: left(), right: right(), body: body() });
|
||||
},
|
||||
|
||||
reduceForStatement(node, { init, test, update, body }) {
|
||||
return reducer.reduceForStatement(node, { init: init == null ? null : init(), test: test == null ? null : test(), update: update == null ? null : update(), body: body() });
|
||||
},
|
||||
|
||||
reduceFormalParameters(node, { items, rest }) {
|
||||
return reducer.reduceFormalParameters(node, { items: items.map(n => n()), rest: rest == null ? null : rest() });
|
||||
},
|
||||
|
||||
reduceFunctionBody(node, { directives, statements }) {
|
||||
return reducer.reduceFunctionBody(node, { directives: directives.map(n => n()), statements: statements.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceFunctionDeclaration(node, { name, params, body }) {
|
||||
return reducer.reduceFunctionDeclaration(node, { name: name(), params: params(), body: body() });
|
||||
},
|
||||
|
||||
reduceFunctionExpression(node, { name, params, body }) {
|
||||
return reducer.reduceFunctionExpression(node, { name: name == null ? null : name(), params: params(), body: body() });
|
||||
},
|
||||
|
||||
reduceGetter(node, { name, body }) {
|
||||
return reducer.reduceGetter(node, { name: name(), body: body() });
|
||||
},
|
||||
|
||||
reduceIdentifierExpression(node) {
|
||||
return reducer.reduceIdentifierExpression(node);
|
||||
},
|
||||
|
||||
reduceIfStatement(node, { test, consequent, alternate }) {
|
||||
return reducer.reduceIfStatement(node, { test: test(), consequent: consequent(), alternate: alternate == null ? null : alternate() });
|
||||
},
|
||||
|
||||
reduceImport(node, { defaultBinding, namedImports }) {
|
||||
return reducer.reduceImport(node, { defaultBinding: defaultBinding == null ? null : defaultBinding(), namedImports: namedImports.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceImportNamespace(node, { defaultBinding, namespaceBinding }) {
|
||||
return reducer.reduceImportNamespace(node, { defaultBinding: defaultBinding == null ? null : defaultBinding(), namespaceBinding: namespaceBinding() });
|
||||
},
|
||||
|
||||
reduceImportSpecifier(node, { binding }) {
|
||||
return reducer.reduceImportSpecifier(node, { binding: binding() });
|
||||
},
|
||||
|
||||
reduceLabeledStatement(node, { body }) {
|
||||
return reducer.reduceLabeledStatement(node, { body: body() });
|
||||
},
|
||||
|
||||
reduceLiteralBooleanExpression(node) {
|
||||
return reducer.reduceLiteralBooleanExpression(node);
|
||||
},
|
||||
|
||||
reduceLiteralInfinityExpression(node) {
|
||||
return reducer.reduceLiteralInfinityExpression(node);
|
||||
},
|
||||
|
||||
reduceLiteralNullExpression(node) {
|
||||
return reducer.reduceLiteralNullExpression(node);
|
||||
},
|
||||
|
||||
reduceLiteralNumericExpression(node) {
|
||||
return reducer.reduceLiteralNumericExpression(node);
|
||||
},
|
||||
|
||||
reduceLiteralRegExpExpression(node) {
|
||||
return reducer.reduceLiteralRegExpExpression(node);
|
||||
},
|
||||
|
||||
reduceLiteralStringExpression(node) {
|
||||
return reducer.reduceLiteralStringExpression(node);
|
||||
},
|
||||
|
||||
reduceMethod(node, { name, params, body }) {
|
||||
return reducer.reduceMethod(node, { name: name(), params: params(), body: body() });
|
||||
},
|
||||
|
||||
reduceModule(node, { directives, items }) {
|
||||
return reducer.reduceModule(node, { directives: directives.map(n => n()), items: items.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceNewExpression(node, { callee, arguments: _arguments }) {
|
||||
return reducer.reduceNewExpression(node, { callee: callee(), arguments: _arguments.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceNewTargetExpression(node) {
|
||||
return reducer.reduceNewTargetExpression(node);
|
||||
},
|
||||
|
||||
reduceObjectAssignmentTarget(node, { properties, rest }) {
|
||||
return reducer.reduceObjectAssignmentTarget(node, { properties: properties.map(n => n()), rest: rest == null ? null : rest() });
|
||||
},
|
||||
|
||||
reduceObjectBinding(node, { properties, rest }) {
|
||||
return reducer.reduceObjectBinding(node, { properties: properties.map(n => n()), rest: rest == null ? null : rest() });
|
||||
},
|
||||
|
||||
reduceObjectExpression(node, { properties }) {
|
||||
return reducer.reduceObjectExpression(node, { properties: properties.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceReturnStatement(node, { expression }) {
|
||||
return reducer.reduceReturnStatement(node, { expression: expression == null ? null : expression() });
|
||||
},
|
||||
|
||||
reduceScript(node, { directives, statements }) {
|
||||
return reducer.reduceScript(node, { directives: directives.map(n => n()), statements: statements.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceSetter(node, { name, param, body }) {
|
||||
return reducer.reduceSetter(node, { name: name(), param: param(), body: body() });
|
||||
},
|
||||
|
||||
reduceShorthandProperty(node, { name }) {
|
||||
return reducer.reduceShorthandProperty(node, { name: name() });
|
||||
},
|
||||
|
||||
reduceSpreadElement(node, { expression }) {
|
||||
return reducer.reduceSpreadElement(node, { expression: expression() });
|
||||
},
|
||||
|
||||
reduceSpreadProperty(node, { expression }) {
|
||||
return reducer.reduceSpreadProperty(node, { expression: expression() });
|
||||
},
|
||||
|
||||
reduceStaticMemberAssignmentTarget(node, { object }) {
|
||||
return reducer.reduceStaticMemberAssignmentTarget(node, { object: object() });
|
||||
},
|
||||
|
||||
reduceStaticMemberExpression(node, { object }) {
|
||||
return reducer.reduceStaticMemberExpression(node, { object: object() });
|
||||
},
|
||||
|
||||
reduceStaticPropertyName(node) {
|
||||
return reducer.reduceStaticPropertyName(node);
|
||||
},
|
||||
|
||||
reduceSuper(node) {
|
||||
return reducer.reduceSuper(node);
|
||||
},
|
||||
|
||||
reduceSwitchCase(node, { test, consequent }) {
|
||||
return reducer.reduceSwitchCase(node, { test: test(), consequent: consequent.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceSwitchDefault(node, { consequent }) {
|
||||
return reducer.reduceSwitchDefault(node, { consequent: consequent.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceSwitchStatement(node, { discriminant, cases }) {
|
||||
return reducer.reduceSwitchStatement(node, { discriminant: discriminant(), cases: cases.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceSwitchStatementWithDefault(node, { discriminant, preDefaultCases, defaultCase, postDefaultCases }) {
|
||||
return reducer.reduceSwitchStatementWithDefault(node, { discriminant: discriminant(), preDefaultCases: preDefaultCases.map(n => n()), defaultCase: defaultCase(), postDefaultCases: postDefaultCases.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceTemplateElement(node) {
|
||||
return reducer.reduceTemplateElement(node);
|
||||
},
|
||||
|
||||
reduceTemplateExpression(node, { tag, elements }) {
|
||||
return reducer.reduceTemplateExpression(node, { tag: tag == null ? null : tag(), elements: elements.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceThisExpression(node) {
|
||||
return reducer.reduceThisExpression(node);
|
||||
},
|
||||
|
||||
reduceThrowStatement(node, { expression }) {
|
||||
return reducer.reduceThrowStatement(node, { expression: expression() });
|
||||
},
|
||||
|
||||
reduceTryCatchStatement(node, { body, catchClause }) {
|
||||
return reducer.reduceTryCatchStatement(node, { body: body(), catchClause: catchClause() });
|
||||
},
|
||||
|
||||
reduceTryFinallyStatement(node, { body, catchClause, finalizer }) {
|
||||
return reducer.reduceTryFinallyStatement(node, { body: body(), catchClause: catchClause == null ? null : catchClause(), finalizer: finalizer() });
|
||||
},
|
||||
|
||||
reduceUnaryExpression(node, { operand }) {
|
||||
return reducer.reduceUnaryExpression(node, { operand: operand() });
|
||||
},
|
||||
|
||||
reduceUpdateExpression(node, { operand }) {
|
||||
return reducer.reduceUpdateExpression(node, { operand: operand() });
|
||||
},
|
||||
|
||||
reduceVariableDeclaration(node, { declarators }) {
|
||||
return reducer.reduceVariableDeclaration(node, { declarators: declarators.map(n => n()) });
|
||||
},
|
||||
|
||||
reduceVariableDeclarationStatement(node, { declaration }) {
|
||||
return reducer.reduceVariableDeclarationStatement(node, { declaration: declaration() });
|
||||
},
|
||||
|
||||
reduceVariableDeclarator(node, { binding, init }) {
|
||||
return reducer.reduceVariableDeclarator(node, { binding: binding(), init: init == null ? null : init() });
|
||||
},
|
||||
|
||||
reduceWhileStatement(node, { test, body }) {
|
||||
return reducer.reduceWhileStatement(node, { test: test(), body: body() });
|
||||
},
|
||||
|
||||
reduceWithStatement(node, { object, body }) {
|
||||
return reducer.reduceWithStatement(node, { object: object(), body: body() });
|
||||
},
|
||||
|
||||
reduceYieldExpression(node, { expression }) {
|
||||
return reducer.reduceYieldExpression(node, { expression: expression == null ? null : expression() });
|
||||
},
|
||||
|
||||
reduceYieldGeneratorExpression(node, { expression }) {
|
||||
return reducer.reduceYieldGeneratorExpression(node, { expression: expression() });
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2014 Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import Spec from 'shift-spec';
|
||||
// import { version } from '../package.json'
|
||||
|
||||
// Loading uncached estraverse for changing estraverse.Syntax.
|
||||
import _estraverse from 'estraverse';
|
||||
|
||||
const estraverse = _estraverse.cloneEnvironment();
|
||||
|
||||
// Adjust estraverse members.
|
||||
|
||||
Object.keys(estraverse.Syntax)
|
||||
.filter((key) => key !== 'Property')
|
||||
.forEach((key) => {
|
||||
delete estraverse.Syntax[key];
|
||||
delete estraverse.VisitorKeys[key];
|
||||
});
|
||||
|
||||
Object.assign(
|
||||
estraverse.Syntax,
|
||||
Object.keys(Spec).reduce((result, key) => {
|
||||
result[key] = key;
|
||||
return result;
|
||||
}, {})
|
||||
);
|
||||
|
||||
Object.assign(
|
||||
estraverse.VisitorKeys,
|
||||
Object.keys(Spec).reduce((result, key) => {
|
||||
result[key] = Spec[key].fields.map((field) => field.name);
|
||||
return result;
|
||||
}, {})
|
||||
);
|
||||
|
||||
// estraverse.version = version;
|
||||
export default estraverse;
|
||||
|
||||
/* vim: set sw=4 ts=4 et tw=80 : */
|
||||
@@ -1,66 +0,0 @@
|
||||
import * as Tone from 'tone';
|
||||
import { State, TimeSpan } from '../../strudel.mjs';
|
||||
import { getPlayableNoteValue } from '../../util.mjs';
|
||||
import { evaluate } from './evaluate';
|
||||
|
||||
// this is a test to play back events with as less runtime code as possible..
|
||||
// the code asks for the number of seconds to prequery
|
||||
// after the querying is done, the events are scheduled
|
||||
// after the scheduling is done, the transport is started
|
||||
// nothing happens while tone.js runs except the schedule callback, which is a thin wrapper around triggerAttackRelease calls
|
||||
// so all glitches that appear here should have nothing to do with strudel and or the repl
|
||||
|
||||
async function playStatic(code) {
|
||||
Tone.getTransport().cancel();
|
||||
Tone.getTransport().stop();
|
||||
let start, took;
|
||||
const seconds = Number(prompt('How many seconds to run?')) || 60;
|
||||
start = performance.now();
|
||||
console.log('evaluating..');
|
||||
const { pattern: pat } = await evaluate(code);
|
||||
took = performance.now() - start;
|
||||
console.log('evaluate took', took, 'ms');
|
||||
console.log('querying..');
|
||||
start = performance.now();
|
||||
const events = pat
|
||||
?.query(new State(new TimeSpan(0, seconds)))
|
||||
?.filter((event) => event.part.begin.equals(event.whole.begin))
|
||||
?.map((event) => ({
|
||||
time: event.whole.begin.valueOf(),
|
||||
duration: event.whole.end.sub(event.whole.begin).valueOf(),
|
||||
value: event.value,
|
||||
context: event.context,
|
||||
}));
|
||||
took = performance.now() - start;
|
||||
console.log('query took', took, 'ms');
|
||||
console.log('scheduling..');
|
||||
start = performance.now();
|
||||
events.forEach((event) => {
|
||||
Tone.getTransport().schedule((time) => {
|
||||
try {
|
||||
const { onTrigger, velocity } = event.context;
|
||||
if (!onTrigger) {
|
||||
if (defaultSynth) {
|
||||
const note = getPlayableNoteValue(event);
|
||||
defaultSynth.triggerAttackRelease(note, event.duration, time, velocity);
|
||||
} else {
|
||||
throw new Error('no defaultSynth passed to useRepl.');
|
||||
}
|
||||
} else {
|
||||
onTrigger(time, event);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
err.message = 'unplayable event: ' + err?.message;
|
||||
console.error(err);
|
||||
}
|
||||
}, event.time);
|
||||
});
|
||||
took = performance.now() - start;
|
||||
console.log('scheduling took', took, 'ms');
|
||||
console.log('now starting!');
|
||||
|
||||
Tone.getTransport().start('+0.5');
|
||||
}
|
||||
|
||||
export default playStatic;
|
||||
@@ -1,89 +0,0 @@
|
||||
import { Note, Interval, Scale } from '@tonaljs/tonal';
|
||||
import { Pattern as _Pattern } from '../../strudel.mjs';
|
||||
import { mod, tokenizeNote } from '../../util.mjs';
|
||||
|
||||
const Pattern = _Pattern; // as any;
|
||||
|
||||
// transpose note inside scale by offset steps
|
||||
// function scaleTranspose(scale: string, offset: number, note: string) {
|
||||
export function scaleTranspose(scale, offset, note) {
|
||||
let [tonic, scaleName] = Scale.tokenize(scale);
|
||||
let { notes } = Scale.get(`${tonic} ${scaleName}`);
|
||||
notes = notes.map((note) => Note.get(note).pc); // use only pc!
|
||||
offset = Number(offset);
|
||||
if (isNaN(offset)) {
|
||||
throw new Error(`scale offset "${offset}" not a number`);
|
||||
}
|
||||
const { pc: fromPc, oct = 3 } = Note.get(note);
|
||||
const noteIndex = notes.indexOf(fromPc);
|
||||
if (noteIndex === -1) {
|
||||
throw new Error(`note "${note}" is not in scale "${scale}"`);
|
||||
}
|
||||
let i = noteIndex,
|
||||
o = oct,
|
||||
n = fromPc;
|
||||
const direction = Math.sign(offset);
|
||||
// TODO: find way to do this smarter
|
||||
while (Math.abs(i - noteIndex) < Math.abs(offset)) {
|
||||
i += direction;
|
||||
const index = mod(i, notes.length);
|
||||
if (direction < 0 && n[0] === 'C') {
|
||||
o += direction;
|
||||
}
|
||||
n = notes[index];
|
||||
if (direction > 0 && n[0] === 'C') {
|
||||
o += direction;
|
||||
}
|
||||
}
|
||||
return n + o;
|
||||
}
|
||||
|
||||
// Pattern.prototype._transpose = function (intervalOrSemitones: string | number) {
|
||||
Pattern.prototype._transpose = function (intervalOrSemitones) {
|
||||
return this._withEvent((event) => {
|
||||
const interval = !isNaN(Number(intervalOrSemitones))
|
||||
? Interval.fromSemitones(intervalOrSemitones /* as number */)
|
||||
: String(intervalOrSemitones);
|
||||
if (typeof event.value === 'number') {
|
||||
const semitones = typeof interval === 'string' ? Interval.semitones(interval) || 0 : interval;
|
||||
return event.withValue(() => event.value + semitones);
|
||||
}
|
||||
// TODO: move simplify to player to preserve enharmonics
|
||||
// tone.js doesn't understand multiple sharps flats e.g. F##3 has to be turned into G3
|
||||
return event.withValue(() => Note.simplify(Note.transpose(event.value, interval)));
|
||||
});
|
||||
};
|
||||
|
||||
// example: transpose(3).late(0.2) will be equivalent to compose(transpose(3), late(0.2))
|
||||
// TODO: add Pattern.define(name, function, options) that handles all the meta programming stuff
|
||||
// TODO: find out how to patternify this function when it's standalone
|
||||
// e.g. `stack(c3).superimpose(transpose(slowcat(7, 5)))` or
|
||||
// or even `stack(c3).superimpose(transpose.slowcat(7, 5))` or
|
||||
|
||||
Pattern.prototype._scaleTranspose = function (offset /* : number | string */) {
|
||||
return this._withEvent((event) => {
|
||||
if (!event.context.scale) {
|
||||
throw new Error('can only use scaleTranspose after .scale');
|
||||
}
|
||||
if (typeof event.value !== 'string') {
|
||||
throw new Error('can only use scaleTranspose with notes');
|
||||
}
|
||||
return event.withValue(() => scaleTranspose(event.context.scale, Number(offset), event.value));
|
||||
});
|
||||
};
|
||||
Pattern.prototype._scale = function (scale /* : string */) {
|
||||
return this._withEvent((event) => {
|
||||
let note = event.value;
|
||||
const asNumber = Number(note);
|
||||
if (!isNaN(asNumber)) {
|
||||
let [tonic, scaleName] = Scale.tokenize(scale);
|
||||
const { pc, oct = 3 } = Note.get(tonic);
|
||||
note = scaleTranspose(pc + ' ' + scaleName, asNumber, pc + oct);
|
||||
}
|
||||
return event.withValue(() => note).setContext({ ...event.context, scale });
|
||||
});
|
||||
};
|
||||
|
||||
Pattern.prototype.define('transpose', (a, pat) => pat.transpose(a), { composable: true, patternified: true });
|
||||
Pattern.prototype.define('scale', (a, pat) => pat.scale(a), { composable: true, patternified: true });
|
||||
Pattern.prototype.define('scaleTranspose', (a, pat) => pat.scaleTranspose(a), { composable: true, patternified: true });
|
||||
@@ -1,268 +0,0 @@
|
||||
import { Pattern as _Pattern } from '../../strudel.mjs';
|
||||
import {
|
||||
AutoFilter,
|
||||
Destination,
|
||||
Filter,
|
||||
Gain,
|
||||
isNote,
|
||||
Synth,
|
||||
PolySynth,
|
||||
MembraneSynth,
|
||||
MetalSynth,
|
||||
MonoSynth,
|
||||
AMSynth,
|
||||
DuoSynth,
|
||||
FMSynth,
|
||||
NoiseSynth,
|
||||
PluckSynth,
|
||||
Sampler,
|
||||
getDestination,
|
||||
Players,
|
||||
} from 'tone';
|
||||
import { Piano } from '@tonejs/piano';
|
||||
import { getPlayableNoteValue } from '../../util.mjs';
|
||||
|
||||
// "balanced" | "interactive" | "playback";
|
||||
// Tone.setContext(new Tone.Context({ latencyHint: 'playback', lookAhead: 1 }));
|
||||
export const defaultSynth = new PolySynth().chain(new Gain(0.5), getDestination());
|
||||
defaultSynth.set({
|
||||
oscillator: { type: 'triangle' },
|
||||
envelope: {
|
||||
release: 0.01,
|
||||
},
|
||||
});
|
||||
|
||||
// what about
|
||||
// https://www.charlie-roberts.com/gibberish/playground/
|
||||
|
||||
const Pattern = _Pattern as any;
|
||||
|
||||
// with this function, you can play the pattern with any tone synth
|
||||
Pattern.prototype.tone = function (instrument) {
|
||||
// instrument.toDestination();
|
||||
return this._withEvent((event) => {
|
||||
const onTrigger = (time, event) => {
|
||||
let note;
|
||||
let velocity = event.context?.velocity ?? 0.75;
|
||||
switch (instrument.constructor.name) {
|
||||
case 'PluckSynth':
|
||||
note = getPlayableNoteValue(event);
|
||||
instrument.triggerAttack(note, time);
|
||||
break;
|
||||
case 'NoiseSynth':
|
||||
instrument.triggerAttackRelease(event.duration, time); // noise has no value
|
||||
break;
|
||||
case 'Piano':
|
||||
note = getPlayableNoteValue(event);
|
||||
instrument.keyDown({ note, time, velocity });
|
||||
instrument.keyUp({ note, time: time + event.duration, velocity });
|
||||
break;
|
||||
case 'Sampler':
|
||||
note = getPlayableNoteValue(event);
|
||||
instrument.triggerAttackRelease(note, event.duration, time, velocity);
|
||||
break;
|
||||
case 'Players':
|
||||
if (!instrument.has(event.value)) {
|
||||
throw new Error(`name "${event.value}" not defined for players`);
|
||||
}
|
||||
const player = instrument.player(event.value);
|
||||
// velocity ?
|
||||
player.start(time);
|
||||
player.stop(time + event.duration);
|
||||
break;
|
||||
default:
|
||||
note = getPlayableNoteValue(event);
|
||||
instrument.triggerAttackRelease(note, event.duration, time, velocity);
|
||||
}
|
||||
};
|
||||
return event.setContext({ ...event.context, instrument, onTrigger });
|
||||
});
|
||||
};
|
||||
|
||||
Pattern.prototype.define('tone', (type, pat) => pat.tone(type), { composable: true, patternified: false });
|
||||
|
||||
// synth helpers
|
||||
export const amsynth = (options) => new AMSynth(options);
|
||||
export const duosynth = (options) => new DuoSynth(options);
|
||||
export const fmsynth = (options) => new FMSynth(options);
|
||||
export const membrane = (options) => new MembraneSynth(options);
|
||||
export const metal = (options) => new MetalSynth(options);
|
||||
export const monosynth = (options) => new MonoSynth(options);
|
||||
export const noise = (options) => new NoiseSynth(options);
|
||||
export const pluck = (options) => new PluckSynth(options);
|
||||
export const polysynth = (options) => new PolySynth(options);
|
||||
export const sampler = (options, baseUrl) =>
|
||||
new Promise((resolve) => {
|
||||
const s = new Sampler(options, () => resolve(s), baseUrl);
|
||||
});
|
||||
export const players = (options, baseUrl = '') => {
|
||||
options = !baseUrl
|
||||
? options
|
||||
: Object.fromEntries(Object.entries(options).map(([key, value]: any) => [key, baseUrl + value]));
|
||||
return new Promise((resolve) => {
|
||||
const s = new Players(options, () => resolve(s));
|
||||
});
|
||||
};
|
||||
export const synth = (options) => new Synth(options);
|
||||
export const piano = async (options = { velocities: 1 }) => {
|
||||
const p = new Piano(options);
|
||||
await p.load();
|
||||
return p;
|
||||
};
|
||||
|
||||
// effect helpers
|
||||
export const vol = (v) => new Gain(v);
|
||||
export const lowpass = (v) => new Filter(v, 'lowpass');
|
||||
export const highpass = (v) => new Filter(v, 'highpass');
|
||||
export const adsr = (a, d = 0.1, s = 0.4, r = 0.01) => ({ envelope: { attack: a, decay: d, sustain: s, release: r } });
|
||||
export const osc = (type) => ({ oscillator: { type } });
|
||||
export const out = () => getDestination();
|
||||
|
||||
/*
|
||||
|
||||
You are entering experimental zone
|
||||
|
||||
*/
|
||||
|
||||
// the following code is an attempt to minimize tonejs code.. it is still an experiment
|
||||
|
||||
const chainable = function (instr) {
|
||||
const _chain = instr.chain.bind(instr);
|
||||
let chained: any = [];
|
||||
instr.chain = (...args) => {
|
||||
chained = chained.concat(args);
|
||||
instr.disconnect(); // disconnect from destination / previous chain
|
||||
return _chain(...chained, getDestination());
|
||||
};
|
||||
// shortcuts: chaining multiple won't work forn now.. like filter(1000).gain(0.5). use chain + native Tone calls instead
|
||||
instr.filter = (freq = 1000, type: BiquadFilterType = 'lowpass') =>
|
||||
instr.chain(
|
||||
new Filter(freq, type) // .Q.setValueAtTime(q, time);
|
||||
);
|
||||
instr.gain = (gain: number = 0.9) => instr.chain(new Gain(gain));
|
||||
return instr;
|
||||
};
|
||||
|
||||
// helpers
|
||||
export const poly = (type) => {
|
||||
const s: any = new PolySynth(Synth, { oscillator: { type } }).toDestination();
|
||||
return chainable(s);
|
||||
};
|
||||
|
||||
Pattern.prototype._poly = function (type: any = 'triangle') {
|
||||
const instrumentConfig: any = {
|
||||
oscillator: { type },
|
||||
envelope: { attack: 0.01, decay: 0.01, sustain: 0.6, release: 0.01 },
|
||||
};
|
||||
if (!this.instrument) {
|
||||
// create only once to keep the js heap happy
|
||||
// this.instrument = new PolySynth(Synth, instrumentConfig).toDestination();
|
||||
this.instrument = poly(type);
|
||||
}
|
||||
return this._withEvent((event: any) => {
|
||||
const onTrigger = (time, event) => {
|
||||
this.instrument.set(instrumentConfig);
|
||||
this.instrument.triggerAttackRelease(event.value, event.duration, time);
|
||||
};
|
||||
return event.setContext({ ...event.context, instrumentConfig, onTrigger });
|
||||
});
|
||||
};
|
||||
|
||||
Pattern.prototype.define('poly', (type, pat) => pat.poly(type), { composable: true, patternified: true });
|
||||
|
||||
/*
|
||||
|
||||
You are entering danger zone
|
||||
|
||||
*/
|
||||
|
||||
// everything below is nice in theory, but not healthy for the JS heap, as nodes get recreated on every call
|
||||
|
||||
const getTrigger = (getChain: any, value: any) => (time: number, event: any) => {
|
||||
const chain = getChain(); // make sure this returns a node that is connected toDestination // time
|
||||
if (!isNote(value)) {
|
||||
throw new Error('not a note: ' + value);
|
||||
}
|
||||
chain.triggerAttackRelease(value, event.duration, time);
|
||||
setTimeout(() => {
|
||||
// setTimeout is a little bit better compared to Transport.scheduleOnce
|
||||
chain.dispose(); // mark for garbage collection
|
||||
}, event.duration * 2000);
|
||||
};
|
||||
|
||||
Pattern.prototype._synth = function (type: any = 'triangle') {
|
||||
return this._withEvent((event: any) => {
|
||||
const instrumentConfig: any = {
|
||||
oscillator: { type },
|
||||
envelope: { attack: 0.01, decay: 0.01, sustain: 0.6, release: 0.01 },
|
||||
};
|
||||
const getInstrument = () => {
|
||||
const instrument = new Synth();
|
||||
instrument.set(instrumentConfig);
|
||||
return instrument;
|
||||
};
|
||||
const onTrigger = getTrigger(() => getInstrument().toDestination(), event.value);
|
||||
return event.setContext({ ...event.context, getInstrument, instrumentConfig, onTrigger });
|
||||
});
|
||||
};
|
||||
|
||||
Pattern.prototype.adsr = function (attack = 0.01, decay = 0.01, sustain = 0.6, release = 0.01) {
|
||||
return this._withEvent((event: any) => {
|
||||
if (!event.context.getInstrument) {
|
||||
throw new Error('cannot chain adsr: need instrument first (like synth)');
|
||||
}
|
||||
const instrumentConfig = { ...event.context.instrumentConfig, envelope: { attack, decay, sustain, release } };
|
||||
const getInstrument = () => {
|
||||
const instrument = event.context.getInstrument();
|
||||
instrument.set(instrumentConfig);
|
||||
return instrument;
|
||||
};
|
||||
const onTrigger = getTrigger(() => getInstrument().toDestination(), event.value);
|
||||
return event.setContext({ ...event.context, getInstrument, instrumentConfig, onTrigger });
|
||||
});
|
||||
};
|
||||
|
||||
Pattern.prototype.chain = function (...effectGetters: any) {
|
||||
return this._withEvent((event: any) => {
|
||||
if (!event.context?.getInstrument) {
|
||||
throw new Error('cannot chain: need instrument first (like synth)');
|
||||
}
|
||||
const chain = (event.context.chain || []).concat(effectGetters);
|
||||
const getChain = () => {
|
||||
const effects = chain.map((getEffect: any) => getEffect());
|
||||
return event.context.getInstrument().chain(...effects, getDestination());
|
||||
};
|
||||
const onTrigger = getTrigger(getChain, event.value);
|
||||
return event.setContext({ ...event.context, getChain, onTrigger, chain });
|
||||
});
|
||||
};
|
||||
|
||||
export const autofilter =
|
||||
(freq = 1) =>
|
||||
() =>
|
||||
new AutoFilter(freq).start();
|
||||
|
||||
export const filter =
|
||||
(freq = 1, q = 1, type: BiquadFilterType = 'lowpass') =>
|
||||
() =>
|
||||
new Filter(freq, type); // .Q.setValueAtTime(q, time);
|
||||
|
||||
export const gain =
|
||||
(gain: number = 0.9) =>
|
||||
() =>
|
||||
new Gain(gain);
|
||||
|
||||
Pattern.prototype._gain = function (g: number) {
|
||||
return this.chain(gain(g));
|
||||
};
|
||||
Pattern.prototype._filter = function (freq: number, q: number, type: BiquadFilterType = 'lowpass') {
|
||||
return this.chain(filter(freq, q, type));
|
||||
};
|
||||
Pattern.prototype._autofilter = function (g: number) {
|
||||
return this.chain(autofilter(g));
|
||||
};
|
||||
|
||||
Pattern.prototype.define('synth', (type, pat) => pat.synth(type), { composable: true, patternified: true });
|
||||
Pattern.prototype.define('gain', (gain, pat) => pat.synth(gain), { composable: true, patternified: true });
|
||||
Pattern.prototype.define('filter', (cutoff, pat) => pat.filter(cutoff), { composable: true, patternified: true });
|
||||
Pattern.prototype.define('autofilter', (cutoff, pat) => pat.filter(cutoff), { composable: true, patternified: true });
|
||||
@@ -1,16 +0,0 @@
|
||||
import Tune from './tunejs.js';
|
||||
import { Pattern } from '../../strudel.mjs';
|
||||
|
||||
Pattern.prototype._tune = function (scale, tonic = 220) {
|
||||
const tune = new Tune();
|
||||
if (!tune.isValidScale(scale)) {
|
||||
throw new Error('not a valid tune.js scale name: "' + scale + '". See http://abbernie.github.io/tune/scales.html');
|
||||
}
|
||||
tune.loadScale(scale);
|
||||
tune.tonicize(tonic);
|
||||
return this._asNumber()._withEvent((event) => {
|
||||
return event.withValue(() => tune.note(event.value)).setContext({ ...event.context, type: 'frequency' });
|
||||
});
|
||||
};
|
||||
|
||||
Pattern.prototype.define('tune', (scale, pat) => pat.tune(scale), { composable: true, patternified: true });
|
||||
File diff suppressed because one or more lines are too long
@@ -1,670 +0,0 @@
|
||||
export const timeCatMini = `stack(
|
||||
"c3@3 [eb3, g3, [c4 d4]/2]",
|
||||
"c2 g2",
|
||||
"[eb4@5 [f4 eb4 d4]@3] [eb4 c4]/2".slow(8)
|
||||
)`;
|
||||
|
||||
export const timeCat = `stack(
|
||||
timeCat([3, c3], [1, stack(eb3, g3, cat(c4, d4).slow(2))]),
|
||||
cat(c2, g2),
|
||||
sequence(
|
||||
timeCat([5, eb4], [3, cat(f4, eb4, d4)]),
|
||||
cat(eb4, c4).slow(2)
|
||||
).slow(4)
|
||||
)`;
|
||||
|
||||
export const shapeShifted = `stack(
|
||||
sequence(
|
||||
e5, [b4, c5], d5, [c5, b4],
|
||||
a4, [a4, c5], e5, [d5, c5],
|
||||
b4, [r, c5], d5, e5,
|
||||
c5, a4, a4, r,
|
||||
[r, d5], [r, f5], a5, [g5, f5],
|
||||
e5, [r, c5], e5, [d5, c5],
|
||||
b4, [b4, c5], d5, e5,
|
||||
c5, a4, a4, r,
|
||||
).rev(),
|
||||
sequence(
|
||||
e2, e3, e2, e3, e2, e3, e2, e3,
|
||||
a2, a3, a2, a3, a2, a3, a2, a3,
|
||||
gs2, gs3, gs2, gs3, e2, e3, e2, e3,
|
||||
a2, a3, a2, a3, a2, a3, b1, c2,
|
||||
d2, d3, d2, d3, d2, d3, d2, d3,
|
||||
c2, c3, c2, c3, c2, c3, c2, c3,
|
||||
b1, b2, b1, b2, e2, e3, e2, e3,
|
||||
a1, a2, a1, a2, a1, a2, a1, a2,
|
||||
).rev()
|
||||
).slow(16)`;
|
||||
|
||||
export const tetrisWithFunctions = `stack(sequence(
|
||||
'e5', sequence('b4', 'c5'), 'd5', sequence('c5', 'b4'),
|
||||
'a4', sequence('a4', 'c5'), 'e5', sequence('d5', 'c5'),
|
||||
'b4', sequence(silence, 'c5'), 'd5', 'e5',
|
||||
'c5', 'a4', 'a4', silence,
|
||||
sequence(silence, 'd5'), sequence(silence, 'f5'), 'a5', sequence('g5', 'f5'),
|
||||
'e5', sequence(silence, 'c5'), 'e5', sequence('d5', 'c5'),
|
||||
'b4', sequence('b4', 'c5'), 'd5', 'e5',
|
||||
'c5', 'a4', 'a4', silence),
|
||||
sequence(
|
||||
'e2', 'e3', 'e2', 'e3', 'e2', 'e3', 'e2', 'e3',
|
||||
'a2', 'a3', 'a2', 'a3', 'a2', 'a3', 'a2', 'a3',
|
||||
'g#2', 'g#3', 'g#2', 'g#3', 'e2', 'e3', 'e2', 'e3',
|
||||
'a2', 'a3', 'a2', 'a3', 'a2', 'a3', 'b1', 'c2',
|
||||
'd2', 'd3', 'd2', 'd3', 'd2', 'd3', 'd2', 'd3',
|
||||
'c2', 'c3', 'c2', 'c3', 'c2', 'c3', 'c2', 'c3',
|
||||
'b1', 'b2', 'b1', 'b2', 'e2', 'e3', 'e2', 'e3',
|
||||
'a1', 'a2', 'a1', 'a2', 'a1', 'a2', 'a1', 'a2',
|
||||
)
|
||||
).slow(16)`;
|
||||
|
||||
export const tetris = `stack(
|
||||
cat(
|
||||
"e5 [b4 c5] d5 [c5 b4]",
|
||||
"a4 [a4 c5] e5 [d5 c5]",
|
||||
"b4 [~ c5] d5 e5",
|
||||
"c5 a4 a4 ~",
|
||||
"[~ d5] [~ f5] a5 [g5 f5]",
|
||||
"e5 [~ c5] e5 [d5 c5]",
|
||||
"b4 [b4 c5] d5 e5",
|
||||
"c5 a4 a4 ~"
|
||||
),
|
||||
cat(
|
||||
"e2 e3 e2 e3 e2 e3 e2 e3",
|
||||
"a2 a3 a2 a3 a2 a3 a2 a3",
|
||||
"g#2 g#3 g#2 g#3 e2 e3 e2 e3",
|
||||
"a2 a3 a2 a3 a2 a3 b1 c2",
|
||||
"d2 d3 d2 d3 d2 d3 d2 d3",
|
||||
"c2 c3 c2 c3 c2 c3 c2 c3",
|
||||
"b1 b2 b1 b2 e2 e3 e2 e3",
|
||||
"a1 a2 a1 a2 a1 a2 a1 a2",
|
||||
)
|
||||
).slow(16)`;
|
||||
|
||||
export const tetrisMini = `\`[[e5 [b4 c5] d5 [c5 b4]]
|
||||
[a4 [a4 c5] e5 [d5 c5]]
|
||||
[b4 [~ c5] d5 e5]
|
||||
[c5 a4 a4 ~]
|
||||
[[~ d5] [~ f5] a5 [g5 f5]]
|
||||
[e5 [~ c5] e5 [d5 c5]]
|
||||
[b4 [b4 c5] d5 e5]
|
||||
[c5 a4 a4 ~]],
|
||||
[[e2 e3]*4]
|
||||
[[a2 a3]*4]
|
||||
[[g#2 g#3]*2 [e2 e3]*2]
|
||||
[a2 a3 a2 a3 a2 a3 b1 c2]
|
||||
[[d2 d3]*4]
|
||||
[[c2 c3]*4]
|
||||
[[b1 b2]*2 [e2 e3]*2]
|
||||
[[a1 a2]*4]\`.slow(16)
|
||||
`;
|
||||
|
||||
export const whirlyStrudel = `sequence(e4, [b2, b3], c4)
|
||||
.every(4, fast(2))
|
||||
.every(3, slow(1.5))
|
||||
.fast(slowcat(1.25, 1, 1.5))
|
||||
.every(2, _ => sequence(e4, r, e3, d4, r))`;
|
||||
|
||||
export const swimming = `stack(
|
||||
cat(
|
||||
"~",
|
||||
"~",
|
||||
"~",
|
||||
"A5 [F5@2 C5] [D5@2 F5] F5",
|
||||
"[C5@2 F5] [F5@2 C6] A5 G5",
|
||||
"A5 [F5@2 C5] [D5@2 F5] F5",
|
||||
"[C5@2 F5] [Bb5 A5 G5] F5@2",
|
||||
"A5 [F5@2 C5] [D5@2 F5] F5",
|
||||
"[C5@2 F5] [F5@2 C6] A5 G5",
|
||||
"A5 [F5@2 C5] [D5@2 F5] F5",
|
||||
"[C5@2 F5] [Bb5 A5 G5] F5@2",
|
||||
"A5 [F5@2 C5] A5 F5",
|
||||
"Ab5 [F5@2 Ab5] G5@2",
|
||||
"A5 [F5@2 C5] A5 F5",
|
||||
"Ab5 [F5@2 C5] C6@2",
|
||||
"A5 [F5@2 C5] [D5@2 F5] F5",
|
||||
"[C5@2 F5] [Bb5 A5 G5] F5@2"
|
||||
),
|
||||
cat(
|
||||
"[F4,Bb4,D5] [[D4,G4,Bb4]@2 [Bb3,D4,F4]] [[G3,C4,E4]@2 [[Ab3,F4] [A3,Gb4]]] [Bb3,E4,G4]",
|
||||
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, Bb3, Db3] [F3, Bb3, Db3]]",
|
||||
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
|
||||
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
|
||||
"[~ [A3, C4, E4] [A3, C4, E4]] [~ [Ab3, C4, Eb4] [Ab3, C4, Eb4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [G3, C4, E4] [G3, C4, E4]]",
|
||||
"[~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
|
||||
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]",
|
||||
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
|
||||
"[~ [A3, C4, E4] [A3, C4, E4]] [~ [Ab3, C4, Eb4] [Ab3, C4, Eb4]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [G3, C4, E4] [G3, C4, E4]]",
|
||||
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
|
||||
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]",
|
||||
"[~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [A3, C4, F4] [A3, C4, F4]] [~ [A3, C4, F4] [A3, C4, F4]]",
|
||||
"[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]",
|
||||
"[~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [Bb3, D3, F4] [Bb3, D3, F4]] [~ [A3, C4, F4] [A3, C4, F4]] [~ [A3, C4, F4] [A3, C4, F4]]",
|
||||
"[~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [Ab3, B3, F4] [Ab3, B3, F4]] [~ [G3, Bb3, F4] [G3, Bb3, F4]] [~ [G3, Bb3, E4] [G3, Bb3, E4]]",
|
||||
"[~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, A3, C3] [F3, A3, C3]] [~ [F3, Bb3, D3] [F3, Bb3, D3]] [~ [F3, B3, D3] [F3, B3, D3]]",
|
||||
"[~ [F3, Bb3, D4] [F3, Bb3, D4]] [~ [F3, Bb3, C4] [F3, Bb3, C4]] [~ [F3, A3, C4] [F3, A3, C4]] [~ [F3, A3, C4] [F3, A3, C4]]"
|
||||
),
|
||||
cat(
|
||||
"[G3 G3 C3 E3]",
|
||||
"[F2 D2 G2 C2]",
|
||||
"[F2 D2 G2 C2]",
|
||||
"[F2 A2 Bb2 B2]",
|
||||
"[A2 Ab2 G2 C2]",
|
||||
"[F2 A2 Bb2 B2]",
|
||||
"[G2 C2 F2 F2]",
|
||||
"[F2 A2 Bb2 B2]",
|
||||
"[A2 Ab2 G2 C2]",
|
||||
"[F2 A2 Bb2 B2]",
|
||||
"[G2 C2 F2 F2]",
|
||||
"[Bb2 Bb2 A2 A2]",
|
||||
"[Ab2 Ab2 G2 [C2 D2 E2]]",
|
||||
"[Bb2 Bb2 A2 A2]",
|
||||
"[Ab2 Ab2 G2 [C2 D2 E2]]",
|
||||
"[F2 A2 Bb2 B2]",
|
||||
"[G2 C2 F2 F2]"
|
||||
)
|
||||
).slow(51);
|
||||
`;
|
||||
|
||||
export const giantSteps = `stack(
|
||||
// melody
|
||||
cat(
|
||||
"[F#5 D5] [B4 G4] Bb4 [B4 A4]",
|
||||
"[D5 Bb4] [G4 Eb4] F#4 [G4 F4]",
|
||||
"Bb4 [B4 A4] D5 [D#5 C#5]",
|
||||
"F#5 [G5 F5] Bb5 [F#5 F#5]",
|
||||
),
|
||||
// chords
|
||||
cat(
|
||||
"[B^7 D7] [G^7 Bb7] Eb^7 [Am7 D7]",
|
||||
"[G^7 Bb7] [Eb^7 F#7] B^7 [Fm7 Bb7]",
|
||||
"Eb^7 [Am7 D7] G^7 [C#m7 F#7]",
|
||||
"B^7 [Fm7 Bb7] Eb^7 [C#m7 F#7]"
|
||||
).voicings(['E3', 'G4']),
|
||||
// bass
|
||||
cat(
|
||||
"[B2 D2] [G2 Bb2] [Eb2 Bb3] [A2 D2]",
|
||||
"[G2 Bb2] [Eb2 F#2] [B2 F#2] [F2 Bb2]",
|
||||
"[Eb2 Bb2] [A2 D2] [G2 D2] [C#2 F#2]",
|
||||
"[B2 F#2] [F2 Bb2] [Eb2 Bb3] [C#2 F#2]"
|
||||
)
|
||||
).slow(20);`;
|
||||
|
||||
export const giantStepsReggae = `stack(
|
||||
// melody
|
||||
cat(
|
||||
"[F#5 D5] [B4 G4] Bb4 [B4 A4]",
|
||||
"[D5 Bb4] [G4 Eb4] F#4 [G4 F4]",
|
||||
"Bb4 [B4 A4] D5 [D#5 C#5]",
|
||||
"F#5 [G5 F5] Bb5 [F#5 [F#5 ~@3]]",
|
||||
),
|
||||
// chords
|
||||
cat(
|
||||
"[B^7 D7] [G^7 Bb7] Eb^7 [Am7 D7]",
|
||||
"[G^7 Bb7] [Eb^7 F#7] B^7 [Fm7 Bb7]",
|
||||
"Eb^7 [Am7 D7] G^7 [C#m7 F#7]",
|
||||
"B^7 [Fm7 Bb7] Eb^7 [C#m7 F#7]"
|
||||
)
|
||||
.struct("~ [x ~]".fast(4*8))
|
||||
.voicings(['E3', 'G4']),
|
||||
// bass
|
||||
cat(
|
||||
"[B2 D2] [G2 D2] [Eb2 Bb2] [A2 D2]",
|
||||
"[G2 Bb2] [Eb2 F#2] [B2 F#2] [F2 Bb2]",
|
||||
"[Eb2 Bb2] [A2 D2] [G2 D2] [C#2 F#2]",
|
||||
"[B2 F#2] [F2 Bb2] [Eb2 Bb2] [C#2 F#2]"
|
||||
)
|
||||
.struct("x ~".fast(4*8))
|
||||
).slow(25)`;
|
||||
|
||||
export const transposedChordsHacked = `stack(
|
||||
"c2 eb2 g2",
|
||||
"Cm7".voicings(['g2','c4']).slow(2)
|
||||
).transpose(
|
||||
slowcat(1, 2, 3, 2).slow(2)
|
||||
).transpose(5)`;
|
||||
|
||||
export const scaleTranspose = `stack(f2, f3, c4, ab4)
|
||||
.scale(sequence('F minor', 'F harmonic minor').slow(4))
|
||||
.scaleTranspose(sequence(0, -1, -2, -3).slow(4))
|
||||
.transpose(sequence(0, 1).slow(16))`;
|
||||
|
||||
export const struct = `stack(
|
||||
"c2 g2 a2 [e2@2 eb2] d2 a2 g2 [d2 ~ db2]",
|
||||
"[C^7 A7] [Dm7 G7]".struct("[x@2 x] [~@2 x] [~ x@2]@2 [x ~@2] ~ [~@2 x@4]@2")
|
||||
.voicings(['G3','A4'])
|
||||
).slow(4)`;
|
||||
|
||||
export const magicSofa = `stack(
|
||||
"<C^7 F^7 ~> <Dm7 G7 A7 ~>"
|
||||
.every(2, fast(2))
|
||||
.voicings(),
|
||||
"<c2 f2 g2> <d2 g2 a2 e2>"
|
||||
).slow(1).transpose(slowcat(0, 2, 3, 4))`;
|
||||
// below doesn't work anymore due to constructor cleanup
|
||||
// ).slow(1).transpose.slowcat(0, 2, 3, 4)`;
|
||||
|
||||
export const confusedPhone = `"[g2 ~@1.3] [c3 ~@1.3]"
|
||||
.superimpose(
|
||||
transpose(-12).late(0),
|
||||
transpose(7).late(0.1),
|
||||
transpose(10).late(0.2),
|
||||
transpose(12).late(0.3),
|
||||
transpose(24).late(0.4)
|
||||
)
|
||||
.scale(slowcat('C dorian', 'C mixolydian'))
|
||||
.scaleTranspose(slowcat(0,1,2,1))
|
||||
.slow(2)`;
|
||||
|
||||
export const zeldasRescue = `stack(
|
||||
// melody
|
||||
\`[B3@2 D4] [A3@2 [G3 A3]] [B3@2 D4] [A3]
|
||||
[B3@2 D4] [A4@2 G4] [D4@2 [C4 B3]] [A3]
|
||||
[B3@2 D4] [A3@2 [G3 A3]] [B3@2 D4] [A3]
|
||||
[B3@2 D4] [A4@2 G4] D5@2
|
||||
[D5@2 [C5 B4]] [[C5 B4] G4@2] [C5@2 [B4 A4]] [[B4 A4] E4@2]
|
||||
[D5@2 [C5 B4]] [[C5 B4] G4 C5] [G5] [~ ~ B3]\`,
|
||||
// bass
|
||||
\`[[C2 G2] E3@2] [[C2 G2] F#3@2] [[C2 G2] E3@2] [[C2 G2] F#3@2]
|
||||
[[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2]
|
||||
[[C2 G2] E3@2] [[C2 G2] F#3@2] [[C2 G2] E3@2] [[C2 G2] F#3@2]
|
||||
[[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2]
|
||||
[[F2 C3] E3@2] [[E2 B2] D3@2] [[D2 A2] C3@2] [[C2 G2] B2@2]
|
||||
[[F2 C3] E3@2] [[E2 B2] D3@2] [[Eb2 Bb2] Db3@2] [[D2 A2] C3 [F3,G2]]\`
|
||||
).transpose(12).slow(48).tone(
|
||||
new PolySynth().chain(
|
||||
new Gain(0.3),
|
||||
new Chorus(2, 2.5, 0.5).start(),
|
||||
new Freeverb(),
|
||||
getDestination())
|
||||
)`;
|
||||
|
||||
export const technoDrums = `stack(
|
||||
"c1*2".tone(new Tone.MembraneSynth().toDestination()),
|
||||
"~ x".tone(new Tone.NoiseSynth().toDestination()),
|
||||
"[~ c4]*2".tone(new Tone.MetalSynth().set({envelope:{decay:0.06,sustain:0}}).chain(new Gain(0.5),getDestination()))
|
||||
)`;
|
||||
|
||||
export const loungerave = `const delay = new FeedbackDelay(1/8, .2).chain(vol(0.5), out());
|
||||
const kick = new MembraneSynth().chain(vol(.8), out());
|
||||
const snare = new NoiseSynth().chain(vol(.8), out());
|
||||
const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out());
|
||||
const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out());
|
||||
const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out());
|
||||
|
||||
const drums = stack(
|
||||
"c1*2".tone(kick).mask("<x@7 ~>/8"),
|
||||
"~ <x!7 [x@3 x]>".tone(snare).mask("<x@7 ~>/4"),
|
||||
"[~ c4]*2".tone(hihat)
|
||||
);
|
||||
|
||||
const thru = (x) => x.transpose("<0 1>/8").transpose(1);
|
||||
const synths = stack(
|
||||
"<C2 Bb1 Ab1 [G1 [G2 G1]]>/2".struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2").edit(thru).tone(bass),
|
||||
"<Cm7 Bb7 Fm7 G7b9>/2".struct("~ [x@0.1 ~]").voicings().edit(thru).every(2, early(1/4)).tone(keys).mask("<x@7 ~>/8".early(1/4))
|
||||
)
|
||||
stack(
|
||||
drums,
|
||||
synths
|
||||
)`;
|
||||
|
||||
export const caverave = `const delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out());
|
||||
const kick = new MembraneSynth().chain(vol(.8), out());
|
||||
const snare = new NoiseSynth().chain(vol(.8), out());
|
||||
const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out());
|
||||
const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out());
|
||||
const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out());
|
||||
|
||||
const drums = stack(
|
||||
"c1*2".tone(kick).mask("<x@7 ~>/8"),
|
||||
"~ <x!7 [x@3 x]>".tone(snare).mask("<x@7 ~>/4"),
|
||||
"[~ c4]*2".tone(hihat)
|
||||
);
|
||||
|
||||
const thru = (x) => x.transpose("<0 1>/8").transpose(-1);
|
||||
const synths = stack(
|
||||
"<eb4 d4 c4 b3>/2".scale(timeCat([3,'C minor'],[1,'C melodic minor']).slow(8)).struct("[~ x]*2")
|
||||
.edit(
|
||||
scaleTranspose(0).early(0),
|
||||
scaleTranspose(2).early(1/8),
|
||||
scaleTranspose(7).early(1/4),
|
||||
scaleTranspose(8).early(3/8)
|
||||
).apply(thru).tone(keys).mask("<~ x>/16"),
|
||||
"<C2 Bb1 Ab1 [G1 [G2 G1]]>/2".struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2".fast(2)).apply(thru).tone(bass),
|
||||
"<Cm7 Bb7 Fm7 G7b13>/2".struct("~ [x@0.1 ~]".fast(2)).voicings().apply(thru).every(2, early(1/8)).tone(keys).mask("<x@7 ~>/8".early(1/4))
|
||||
)
|
||||
stack(
|
||||
drums.fast(2),
|
||||
synths
|
||||
).slow(2)`;
|
||||
|
||||
export const callcenterhero = `const bpm = 90;
|
||||
const lead = polysynth().set({...osc('sine4'),...adsr(.004)}).chain(vol(0.15),out())
|
||||
const bass = fmsynth({...osc('sawtooth6'),...adsr(0.05,.6,0.8,0.1)}).chain(vol(0.6), out());
|
||||
const s = scale(slowcat('F3 minor', 'Ab3 major', 'Bb3 dorian', 'C4 phrygian dominant').slow(4));
|
||||
stack(
|
||||
"0 2".struct("<x ~> [x ~]").apply(s).scaleTranspose(stack(0,2)).tone(lead),
|
||||
"<6 7 9 7>".struct("[~ [x ~]*2]*2").apply(s).scaleTranspose("[0,2] [2,4]".fast(2).every(4,rev)).tone(lead),
|
||||
"-14".struct("[~ x@0.8]*2".early(0.01)).apply(s).tone(bass),
|
||||
"c2*2".tone(membrane().chain(vol(0.6), out())),
|
||||
"~ c2".tone(noise().chain(vol(0.2), out())),
|
||||
"c4*4".tone(metal(adsr(0,.05,0)).chain(vol(0.03), out()))
|
||||
)
|
||||
.slow(120 / bpm)`;
|
||||
|
||||
export const primalEnemy = `const f = fast("<1 <2 [4 8]>>");
|
||||
stack(
|
||||
"c3,g3,c4".struct("[x ~]*2").apply(f).transpose("<0 <3 [5 [7 [9 [11 13]]]]>>"),
|
||||
"c2 [c2 ~]*2".tone(synth(osc('sawtooth8')).chain(vol(0.8),out())),
|
||||
"c1*2".tone(membrane().chain(vol(0.8),out()))
|
||||
).slow(1)`;
|
||||
|
||||
export const synthDrums = `stack(
|
||||
"c1*2".tone(membrane().chain(vol(0.8),out())),
|
||||
"~ c3".tone(noise().chain(vol(0.8),out())),
|
||||
"c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.015)).chain(vol(0.8),out()))
|
||||
)
|
||||
`;
|
||||
|
||||
export const sampleDrums = `const drums = await players({
|
||||
bd: 'bd/BT0A0D0.wav',
|
||||
sn: 'sn/ST0T0S3.wav',
|
||||
hh: 'hh/000_hh3closedhh.wav'
|
||||
}, 'https://loophole-letters.vercel.app/samples/tidal/')
|
||||
|
||||
stack(
|
||||
"<bd!3 bd(3,4,2)>",
|
||||
"hh*4",
|
||||
"~ <sn!3 sn(3,4,1)>"
|
||||
).tone(drums.chain(out()))
|
||||
`;
|
||||
|
||||
export const xylophoneCalling = `const t = x => x.scaleTranspose("<0 2 4 3>/4").transpose(-2)
|
||||
const s = x => x.scale(slowcat('C3 minor pentatonic','G3 minor pentatonic').slow(4))
|
||||
const delay = new FeedbackDelay(1/8, .6).chain(vol(0.1), out());
|
||||
const chorus = new Chorus(1,2.5,0.5).start();
|
||||
stack(
|
||||
// melody
|
||||
"<<10 7> <8 3>>/4".struct("x*3").apply(s)
|
||||
.scaleTranspose("<0 3 2> <1 4 3>")
|
||||
.superimpose(scaleTranspose(2).early(1/8))
|
||||
.apply(t).tone(polysynth().set({
|
||||
...osc('triangle4'),
|
||||
...adsr(0,.08,0)
|
||||
}).chain(vol(0.2).connect(delay),chorus,out())).mask("<~@3 x>/16".early(1/8)),
|
||||
// pad
|
||||
"[1,3]/4".scale('G3 minor pentatonic').apply(t).tone(polysynth().set({
|
||||
...osc('square2'),
|
||||
...adsr(0.1,.4,0.8)
|
||||
}).chain(vol(0.2),chorus,out())).mask("<~ x>/32"),
|
||||
// xylophone
|
||||
"c3,g3,c4".struct("<x*2 x>").fast("<1 <2!3 [4 8]>>").apply(s).scaleTranspose("<0 <1 [2 [3 <4 5>]]>>").apply(t).tone(polysynth().set({
|
||||
...osc('sawtooth4'),
|
||||
...adsr(0,.1,0)
|
||||
}).chain(vol(0.4).connect(delay),out())).mask("<x@3 ~>/16".early(1/8)),
|
||||
// bass
|
||||
"c2 [c2 ~]*2".scale('C hirajoshi').apply(t).tone(synth({
|
||||
...osc('sawtooth6'),
|
||||
...adsr(0,.03,.4,.1)
|
||||
}).chain(vol(0.4),out())),
|
||||
// kick
|
||||
"<c1!3 [c1 ~]*2>*2".tone(membrane().chain(vol(0.8),out())),
|
||||
// snare
|
||||
"~ <c3!7 [c3 c3*2]>".tone(noise().chain(vol(0.8),out())),
|
||||
// hihat
|
||||
"c3*4".transpose("[-24 0]*2").tone(metal(adsr(0,.02)).chain(vol(0.5).connect(delay),out()))
|
||||
).slow(1)`;
|
||||
|
||||
export const sowhatelse = `// mixer
|
||||
const mix = (key) => vol({
|
||||
chords: .2,
|
||||
lead: 0.8,
|
||||
bass: .4,
|
||||
snare: .95,
|
||||
kick: .9,
|
||||
hihat: .35,
|
||||
}[key]||0);
|
||||
const delay = new FeedbackDelay(1/6, .3).chain(vol(.7), out());
|
||||
const delay2 = new FeedbackDelay(1/6, .2).chain(vol(.15), out());
|
||||
const chorus = new Chorus(1,2.5,0.5).start();
|
||||
// instruments
|
||||
const instr = (instrument) => ({
|
||||
organ: polysynth().set({...osc('sawtooth4'), ...adsr(.01,.2,0)}).chain(mix('chords').connect(delay),out()),
|
||||
lead: polysynth().set({...osc('triangle4'),...adsr(0.01,.05,0)}).chain(mix('lead').connect(delay2), out()),
|
||||
bass: polysynth().set({...osc('sawtooth8'),...adsr(.02,.05,.3,.2)}).chain(mix('bass'),lowpass(3000), out()),
|
||||
pad: polysynth().set({...osc('square2'),...adsr(0.1,.4,0.8)}).chain(vol(0.15),chorus,out()),
|
||||
hihat: metal(adsr(0, .02, 0)).chain(mix('hihat'), out()),
|
||||
snare: noise(adsr(0, .15, 0.01)).chain(mix('snare'), lowpass(5000), out()),
|
||||
kick: membrane().chain(mix('kick'), out())
|
||||
}[instrument]);
|
||||
// harmony
|
||||
const t = transpose("<0 0 1 0>/8");
|
||||
const sowhat = scaleTranspose("0,3,6,9,11");
|
||||
// track
|
||||
stack(
|
||||
"[<0 4 [3 [2 1]]>]/4".struct("[x]*3").mask("[~ x ~]").scale('D5 dorian').off(1/6, scaleTranspose(-7)).off(1/3, scaleTranspose(-5)).apply(t).tone(instr('lead')).mask("<~ ~ x x>/8"),
|
||||
"<<e3 [~@2 a3]> <[d3 ~] [c3 f3] g3>>".scale('D dorian').apply(sowhat).apply(t).tone(instr('organ')).mask("<x x x ~>/8"),
|
||||
"<[d2 [d2 ~]*3]!3 <a1*2 c2*3 [a1 e2]>>".apply(t).tone(instr('bass')),
|
||||
"c1*6".tone(instr('hihat')),
|
||||
"~ c3".tone(instr('snare')),
|
||||
"<[c1@5 c1] <c1 [[c1@2 c1] ~] [c1 ~ c1] [c1!2 ~ c1!3]>>".tone(instr('kick')),
|
||||
"[2,4]/4".scale('D dorian').apply(t).tone(instr('pad')).mask("<x x x ~>/8")
|
||||
).fast(6/8)`;
|
||||
|
||||
export const barryHarris = `backgroundImage(
|
||||
'https://media.npr.org/assets/img/2017/02/03/barryharris_600dpi_wide-7eb49998aa1af377d62bb098041624c0a0d1a454.jpg',
|
||||
{style:'background-size:cover'})
|
||||
|
||||
"0,2,[7 6]"
|
||||
.add("<0 1 2 3 4 5 7 8>")
|
||||
.scale('C bebop major')
|
||||
.transpose("<0 1 2 1>/8")
|
||||
.slow(2)
|
||||
.tone((await piano()).toDestination())
|
||||
`;
|
||||
|
||||
export const blippyRhodes = `const delay = new FeedbackDelay(1/12, .4).chain(vol(0.3), out());
|
||||
|
||||
const drums = await players({
|
||||
bd: 'samples/tidal/bd/BT0A0D0.wav',
|
||||
sn: 'samples/tidal/sn/ST0T0S3.wav',
|
||||
hh: 'samples/tidal/hh/000_hh3closedhh.wav'
|
||||
}, 'https://loophole-letters.vercel.app/')
|
||||
|
||||
const rhodes = await sampler({
|
||||
E1: 'samples/rhodes/MK2Md2000.mp3',
|
||||
E2: 'samples/rhodes/MK2Md2012.mp3',
|
||||
E3: 'samples/rhodes/MK2Md2024.mp3',
|
||||
E4: 'samples/rhodes/MK2Md2036.mp3',
|
||||
E5: 'samples/rhodes/MK2Md2048.mp3',
|
||||
E6: 'samples/rhodes/MK2Md2060.mp3',
|
||||
E7: 'samples/rhodes/MK2Md2072.mp3'
|
||||
}, 'https://loophole-letters.vercel.app/')
|
||||
|
||||
const bass = synth(osc('sawtooth8')).chain(vol(.5),out())
|
||||
const scales = sequence('C major', 'C mixolydian', 'F lydian', ['F minor', slowcat('Db major','Db mixolydian')]).slow(4)
|
||||
|
||||
stack(
|
||||
"<bd sn> <hh hh*2 hh*3>"
|
||||
.tone(drums.chain(out())),
|
||||
"<g4 c5 a4 [ab4 <eb5 f5>]>"
|
||||
.scale(scales)
|
||||
.struct("x*8")
|
||||
.scaleTranspose("0 [-5,-2] -7 [-9,-2]")
|
||||
.legato(.3)
|
||||
.slow(2)
|
||||
.tone(rhodes.chain(vol(0.5).connect(delay), out())),
|
||||
//"<C^7 C7 F^7 [Fm7 <Db^7 Db7>]>".slow(2).voicings().struct("~ x").legato(.25).tone(rhodes),
|
||||
"<c2 c3 f2 [[F2 C2] db2]>"
|
||||
.legato("<1@3 [.3 1]>")
|
||||
.slow(2)
|
||||
.tone(bass),
|
||||
).fast(3/2)`;
|
||||
|
||||
export const wavyKalimba = `const delay = new FeedbackDelay(1/3, .5).chain(vol(.2), out());
|
||||
let kalimba = await sampler({
|
||||
C5: 'https://freesound.org/data/previews/536/536549_11935698-lq.mp3'
|
||||
})
|
||||
kalimba = kalimba.chain(vol(0.6).connect(delay),out());
|
||||
const scales = sequence('C major', 'C mixolydian', 'F lydian', ['F minor', 'Db major']).slow(4);
|
||||
|
||||
stack(
|
||||
"[0 2 4 6 9 2 0 -2]*3"
|
||||
.add("<0 2>/4")
|
||||
.scale(scales)
|
||||
.struct("x*8")
|
||||
.velocity("<.8 .3 .6>*8")
|
||||
.slow(2)
|
||||
.tone(kalimba),
|
||||
"<c2 c2 f2 [[F2 C2] db2]>"
|
||||
.scale(scales)
|
||||
.scaleTranspose("[0 <2 4>]*2")
|
||||
.struct("x*4")
|
||||
.velocity("<.8 .5>*4")
|
||||
.velocity(0.8)
|
||||
.slow(2)
|
||||
.tone(kalimba)
|
||||
)
|
||||
.legato("<.4 .8 1 1.2 1.4 1.6 1.8 2>/8")
|
||||
.fast(1)`;
|
||||
|
||||
export const jemblung = `const delay = new FeedbackDelay(1/8, .6).chain(vol(0.15), out());
|
||||
const snare = noise({type:'white',...adsr(0,0.2,0)}).chain(lowpass(5000),vol(1.8),out());
|
||||
const s = polysynth().set({...osc('sawtooth4'),...adsr(0.01,.2,.6,0.2)}).chain(vol(.23).connect(delay),out());
|
||||
stack(
|
||||
stack(
|
||||
"0 1 4 [3!2 5]".edit(
|
||||
// chords
|
||||
x=>x.add("0,3").duration("0.05!3 0.02"),
|
||||
// bass
|
||||
x=>x.add("-8").struct("x*8").duration(0.1)
|
||||
),
|
||||
// melody
|
||||
"12 11*3 12 ~".duration(0.005)
|
||||
)
|
||||
.add("<0 1>")
|
||||
.tune("jemblung2")
|
||||
//.mul(22/5).round().xen("22edo")
|
||||
//.mul(12/5).round().xen("12edo")
|
||||
.tone(s),
|
||||
// kick
|
||||
"[c2 ~]*2".duration(0.05).tone(membrane().chain(out())),
|
||||
// snare
|
||||
"[~ c1]*2".early(0.001).tone(snare),
|
||||
// hihat
|
||||
"c2*8".tone(noise().chain(highpass(6000),vol(0.5).connect(delay),out())),
|
||||
).slow(3)`;
|
||||
|
||||
export const risingEnemy = `stack(
|
||||
"2,6"
|
||||
.scale('F3 dorian')
|
||||
.transpose(sine2.struct("x*64").slow(4).mul(2).round())
|
||||
.fast(2)
|
||||
.struct("x x*3")
|
||||
.legato(".9 .3"),
|
||||
"0@3 -3*3".legato(".95@3 .4").scale('F2 dorian')
|
||||
)
|
||||
.transpose("<0 1 2 1>/2".early(0.5))
|
||||
.transpose(5)
|
||||
.fast(2 / 3)
|
||||
.tone((await piano()).toDestination())`;
|
||||
|
||||
export const festivalOfFingers = `const chords = "<Cm7 Fm7 G7 F#7>";
|
||||
stack(
|
||||
chords.voicings().struct("x(3,8,-1)").velocity(.5).off(1/7,x=>x.transpose(12).velocity(.2)),
|
||||
chords.rootNotes(2).struct("x(4,8,-2)"),
|
||||
chords.rootNotes(4)
|
||||
.scale(slowcat('C minor','F dorian','G dorian','F# mixolydian'))
|
||||
.struct("x(3,8,-2)".fast(2))
|
||||
.scaleTranspose("0 4 0 6".early(".125 .5")).layer(scaleTranspose("0,<2 [4,6] [5,7]>/4"))
|
||||
).slow(2)
|
||||
.velocity(sine.struct("x*8").add(3/5).mul(2/5).fast(8))
|
||||
.tone((await piano()).chain(out()))`;
|
||||
|
||||
export const festivalOfFingers2 = `const chords = "<Cm7 Fm7 G7 F#7 >";
|
||||
const scales = slowcat('C minor','F dorian','G dorian','F# mixolydian')
|
||||
stack(
|
||||
chords.voicings().struct("x(3,8,-1)").velocity(.5).off(1/7,x=>x.transpose(12).velocity(.2)),
|
||||
chords.rootNotes(2).struct("x(4,8)"),
|
||||
chords.rootNotes(4)
|
||||
.scale(scales)
|
||||
.struct("x(3,8,-2)".fast(2))
|
||||
.scaleTranspose("0 4 0 6".early(".125 .5")).layer(scaleTranspose("0,<2 [4,6] [5,7]>/3"))
|
||||
).slow(2).transpose(-1)
|
||||
.legato(cosine.struct("x*8").add(4/5).mul(4/5).fast(8))
|
||||
.velocity(sine.struct("x*8").add(3/5).mul(2/5).fast(8))
|
||||
.tone((await piano()).chain(out())).fast(3/4)`;
|
||||
|
||||
// iter, stut, stutWith
|
||||
export const undergroundPlumber = `backgroundImage('https://images.nintendolife.com/news/2016/08/video_exploring_the_funky_inspiration_for_the_super_mario_bros_underground_theme/large.jpg',{ className:'darken' })
|
||||
|
||||
const drums = await players({
|
||||
bd: 'bd/BT0A0D0.wav',
|
||||
sn: 'sn/ST0T0S3.wav',
|
||||
hh: 'hh/000_hh3closedhh.wav',
|
||||
cp: 'cp/HANDCLP0.wav',
|
||||
}, 'https://loophole-letters.vercel.app/samples/tidal/')
|
||||
stack(
|
||||
"<<bd*2 bd> sn> hh".fast(4).slow(2).tone(drums.chain(vol(.5),out())),
|
||||
stack(
|
||||
"[c2 a1 bb1 ~] ~"
|
||||
.stut(2, .6, 1/16)
|
||||
.legato(.4)
|
||||
.slow(2)
|
||||
.tone(synth({...osc('sawtooth7'),...adsr(0,.3,0)}).chain(out())),
|
||||
"[g2,[c3 eb3]]".iter(4)
|
||||
.stutWith(4, 1/8, (x,n)=>x.transpose(n*12).velocity(Math.pow(.4,n)))
|
||||
.legato(.1)
|
||||
)
|
||||
.transpose("<0@2 5 0 7 5 0 -5>/2")
|
||||
|
||||
)
|
||||
.fast(2/3)
|
||||
.pianoroll({minMidi:21,maxMidi:180, background:'transparent',inactive:'#3F8F90',active:'#DE3123'})`;
|
||||
|
||||
export const bridgeIsOver = `const breaks = (await players({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'})).chain(out())
|
||||
stack(
|
||||
stack(
|
||||
"c3*2 [[c3@1.4 bb2] ab2] gb2*2 <[[gb2@1.4 ab2] bb2] gb2>".legato(".5 1".fast(2)).velocity(.8),
|
||||
"0 ~".scale('c4 whole tone')
|
||||
.euclidLegato(3,8).slow(2).mask("x ~")
|
||||
.stutWith(8, 1/16, (x,n)=>x.scaleTranspose(n).velocity(Math.pow(.7,n)))
|
||||
.scaleTranspose("<0 1 2 3 4 3 2 1>")
|
||||
.fast(2)
|
||||
.velocity(.7)
|
||||
.legato(.5)
|
||||
.stut(3, .5, 1/8)
|
||||
).transpose(-1).tone((await piano()).chain(out())),
|
||||
"mad".slow(2).tone(breaks)
|
||||
).cpm(78).slow(4).pianoroll()
|
||||
`;
|
||||
|
||||
export const goodTimes = `const scale = slowcat('C3 dorian','Bb2 major').slow(4);
|
||||
stack(
|
||||
"2*4".add(12).scale(scale)
|
||||
.off(1/8,x=>x.scaleTranspose("2")).fast(2)
|
||||
.scaleTranspose("<0 1 2 1>").hush(),
|
||||
"<0 1 2 3>(3,8,2)"
|
||||
.scale(scale)
|
||||
.off(1/4,x=>x.scaleTranspose("2,4")),
|
||||
"<0 4>(5,8)".scale(scale).transpose(-12)
|
||||
)
|
||||
.velocity(".6 .7".fast(4))
|
||||
.legato("2")
|
||||
.scale(scale)
|
||||
.scaleTranspose("<0>".slow(4))
|
||||
.tone((await piano()).chain(out()))
|
||||
//.midi()
|
||||
.velocity(.8)
|
||||
.transpose(5)
|
||||
.slow(2)
|
||||
.pianoroll({maxMidi:100,minMidi:20})`;
|
||||
|
||||
export const echoPiano = `"<0 2 [4 6](3,4,1) 3*2>"
|
||||
.scale('D minor')
|
||||
.color('salmon')
|
||||
.off(1/4, x=>x.scaleTranspose(2).color('green'))
|
||||
.off(1/2, x=>x.scaleTranspose(6).color('steelblue'))
|
||||
.legato(.5)
|
||||
.echo(4, 1/8, .5)
|
||||
.tone((await piano()).chain(out()))
|
||||
.pianoroll()`;
|
||||
@@ -1,101 +0,0 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import * as Tone from 'tone';
|
||||
import useRepl from '../useRepl';
|
||||
import CodeMirror, { markEvent } from '../CodeMirror';
|
||||
import cx from '../cx';
|
||||
|
||||
const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone.Destination).set({
|
||||
oscillator: { type: 'triangle' },
|
||||
envelope: {
|
||||
release: 0.01,
|
||||
},
|
||||
});
|
||||
|
||||
// "balanced" | "interactive" | "playback";
|
||||
// Tone.setContext(new Tone.Context({ latencyHint: 'playback', lookAhead: 1 }));
|
||||
function MiniRepl({ tune, maxHeight = 500 }) {
|
||||
const [editor, setEditor] = useState<any>();
|
||||
const { code, setCode, activateCode, activeCode, setPattern, error, cycle, dirty, log, togglePlay, hash } = useRepl({
|
||||
tune,
|
||||
defaultSynth,
|
||||
autolink: false,
|
||||
onDraw: useCallback(markEvent(editor), [editor]),
|
||||
});
|
||||
const lines = code.split('\n').length;
|
||||
const height = Math.min(lines * 30 + 30, maxHeight);
|
||||
return (
|
||||
<div className="rounded-md overflow-hidden">
|
||||
<div className="flex justify-between bg-slate-700 border-t border-slate-500">
|
||||
<div className="flex">
|
||||
<button
|
||||
className={cx(
|
||||
'w-16 flex items-center justify-center p-1 bg-slate-700 border-r border-slate-500 text-white hover:bg-slate-600',
|
||||
cycle.started ? 'animate-pulse' : ''
|
||||
)}
|
||||
onClick={() => togglePlay()}
|
||||
>
|
||||
{!cycle.started ? (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
className={cx(
|
||||
'w-16 flex items-center justify-center p-1 border-slate-500 hover:bg-slate-600',
|
||||
dirty
|
||||
? 'bg-slate-700 border-r border-slate-500 text-white'
|
||||
: 'bg-slate-600 text-slate-400 cursor-not-allowed'
|
||||
)}
|
||||
onClick={() => activateCode()}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div className="text-right p-1 text-sm">{error && <span className="text-red-200">{error.message}</span>}</div>{' '}
|
||||
</div>
|
||||
<div className="flex space-y-0 overflow-auto" style={{ height }}>
|
||||
<CodeMirror
|
||||
className="w-full"
|
||||
value={code}
|
||||
editorDidMount={setEditor}
|
||||
options={{
|
||||
mode: 'javascript',
|
||||
theme: 'material',
|
||||
lineNumbers: true,
|
||||
}}
|
||||
onChange={(_: any, __: any, value: any) => setCode(value)}
|
||||
/>
|
||||
</div>
|
||||
{/* <div className="bg-slate-700 border-t border-slate-500 content-right pr-2 text-right">
|
||||
<a href={`https://strudel.tidalcycles.org/#${hash}`} className="text-white items-center inline-flex">
|
||||
<span>open in REPL</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z" />
|
||||
<path d="M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5V7h3a1 1 0 000-2H5z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default MiniRepl;
|
||||
@@ -1,28 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Tutorial from './tutorial.mdx';
|
||||
// import logo from '../logo.svg';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<div className="min-h-screen">
|
||||
<header className="flex-none flex justify-center w-full h-16 px-2 items-center border-b border-gray-200 bg-white">
|
||||
<div className="p-4 w-full max-w-3xl flex justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<img src={'https://tidalcycles.org/img/logo.svg'} className="Tidal-logo w-16 h-16" alt="logo" />
|
||||
<h1 className="text-2xl">Strudel Tutorial</h1>
|
||||
</div>
|
||||
{!window.location.href.includes('localhost') && (
|
||||
<div className="flex space-x-4">
|
||||
<a href="../">go to REPL</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
<main className="p-4 max-w-3xl prose">
|
||||
<Tutorial />
|
||||
</main>
|
||||
</div>
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
@@ -1,16 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="../../public/favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="./style.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="Strudel REPL" />
|
||||
<title>Strudel Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<script type="module" src="Tutorial.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,13 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.react-codemirror2,
|
||||
.CodeMirror {
|
||||
width: 100% !important;
|
||||
height: inherit !important;
|
||||
}
|
||||
|
||||
main {
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -1,748 +0,0 @@
|
||||
import MiniRepl from './MiniRepl';
|
||||
|
||||
# What is Strudel?
|
||||
|
||||
With Strudel, you can expressively write dynamic music pieces.
|
||||
It aims to be [Tidal Cycles](https://tidalcycles.org/) for JavaScript (started by the same author).
|
||||
|
||||
You don't need to know JavaScript or Tidal Cycles to make music with Strudel.
|
||||
|
||||
This interactive tutorial will guide you through the basics of Strudel.
|
||||
|
||||
The best place to actually make music with Strudel is the [Strudel REPL](https://strudel.tidalcycles.org/).
|
||||
|
||||
## Show me a Demo
|
||||
|
||||
To get a taste of what Strudel can do, check out this track:
|
||||
|
||||
<MiniRepl tune={`const delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out());
|
||||
const kick = new MembraneSynth().chain(vol(.8), out());
|
||||
const snare = new NoiseSynth().chain(vol(.8), out());
|
||||
const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out());
|
||||
const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out());
|
||||
const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out());
|
||||
const drums = stack(
|
||||
"c1*2".tone(kick).bypass("<0@7 1>/8"),
|
||||
"~ <x!7 [x@3 x]>".tone(snare).bypass("<0@7 1>/4"),
|
||||
"[~ c4]*2".tone(hihat)
|
||||
);
|
||||
const thru = (x) => x.transpose("<0 1>/8").transpose(-1);
|
||||
const synths = stack(
|
||||
"<eb4 d4 c4 b3>/2".scale(timeCat([3,'C minor'],[1,'C melodic minor']).slow(8)).struct("[~ x]\*2")
|
||||
.edit(
|
||||
scaleTranspose(0).early(0),
|
||||
scaleTranspose(2).early(1/8),
|
||||
scaleTranspose(7).early(1/4),
|
||||
scaleTranspose(8).early(3/8)
|
||||
).edit(thru).tone(keys).bypass("<1 0>/16"),
|
||||
"<C2 Bb1 Ab1 [G1 [G2 G1]]>/2".struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2".fast(2)).edit(thru).tone(bass),
|
||||
"<Cm7 Bb7 Fm7 G7b13>/2".struct("~ [x@0.1 ~]".fast(2)).voicings().edit(thru).every(2, early(1/8)).tone(keys).bypass("<0@7 1>/8".early(1/4))
|
||||
)
|
||||
stack(
|
||||
drums.fast(2),
|
||||
synths
|
||||
).slow(2);
|
||||
`}
|
||||
/>
|
||||
|
||||
[Open this track in the REPL](https://strudel.tidalcycles.org/#KCkgPT4gewogIGNvbnN0IGRlbGF5ID0gbmV3IEZlZWRiYWNrRGVsYXkoMS84LCAuNCkuY2hhaW4odm9sKDAuNSksIG91dCk7CiAgY29uc3Qga2ljayA9IG5ldyBNZW1icmFuZVN5bnRoKCkuY2hhaW4odm9sKC44KSwgb3V0KTsKICBjb25zdCBzbmFyZSA9IG5ldyBOb2lzZVN5bnRoKCkuY2hhaW4odm9sKC44KSwgb3V0KTsKICBjb25zdCBoaWhhdCA9IG5ldyBNZXRhbFN5bnRoKCkuc2V0KGFkc3IoMCwgLjA4LCAwLCAuMSkpLmNoYWluKHZvbCguMykuY29ubmVjdChkZWxheSksb3V0KTsKICBjb25zdCBiYXNzID0gbmV3IFN5bnRoKCkuc2V0KHsgLi4ub3NjKCdzYXd0b290aCcpLCAuLi5hZHNyKDAsIC4xLCAuNCkgfSkuY2hhaW4obG93cGFzcyg5MDApLCB2b2woLjUpLCBvdXQpOwogIGNvbnN0IGtleXMgPSBuZXcgUG9seVN5bnRoKCkuc2V0KHsgLi4ub3NjKCdzYXd0b290aCcpLCAuLi5hZHNyKDAsIC41LCAuMiwgLjcpIH0pLmNoYWluKGxvd3Bhc3MoMTIwMCksIHZvbCguNSksIG91dCk7CiAgCiAgY29uc3QgZHJ1bXMgPSBzdGFjaygKICAgICdjMSoyJy5tLnRvbmUoa2ljaykuYnlwYXNzKCc8MEA3IDE%2BLzgnLm0pLAogICAgJ34gPHghNyBbeEAzIHhdPicubS50b25lKHNuYXJlKS5ieXBhc3MoJzwwQDcgMT4vNCcubSksCiAgICAnW34gYzRdKjInLm0udG9uZShoaWhhdCkKICApOwogIAogIGNvbnN0IHRocnUgPSAoeCkgPT4geC50cmFuc3Bvc2UoJzwwIDE%2BLzgnLm0pLnRyYW5zcG9zZSgtMSk7CiAgY29uc3Qgc3ludGhzID0gc3RhY2soCiAgICAnPGViNCBkNCBjNCBiMz4vMicubS5zY2FsZSh0aW1lQ2F0KFszLCdDIG1pbm9yJ10sWzEsJ0MgbWVsb2RpYyBtaW5vciddKS5zbG93KDgpKS5ncm9vdmUoJ1t%2BIHhdKjInLm0pCiAgICAuZWRpdCgKICAgICAgc2NhbGVUcmFuc3Bvc2UoMCkuZWFybHkoMCksCiAgICAgIHNjYWxlVHJhbnNwb3NlKDIpLmVhcmx5KDEvOCksCiAgICAgIHNjYWxlVHJhbnNwb3NlKDcpLmVhcmx5KDEvNCksCiAgICAgIHNjYWxlVHJhbnNwb3NlKDgpLmVhcmx5KDMvOCkKICAgICkuZWRpdCh0aHJ1KS50b25lKGtleXMpLmJ5cGFzcygnPDEgMD4vMTYnLm0pLAogICAgJzxDMiBCYjEgQWIxIFtHMSBbRzIgRzFdXT4vMicubS5ncm9vdmUoJ1t4IFt%2BIHhdIDxbfiBbfiB4XV0hMyBbeCB4XT5AMl0vMicubS5mYXN0KDIpKS5lZGl0KHRocnUpLnRvbmUoYmFzcyksCiAgICAnPENtNyBCYjcgRm03IEc3YjEzPi8yJy5tLmdyb292ZSgnfiBbeEAwLjEgfl0nLm0uZmFzdCgyKSkudm9pY2luZ3MoKS5lZGl0KHRocnUpLmV2ZXJ5KDIsIGVhcmx5KDEvOCkpLnRvbmUoa2V5cykuYnlwYXNzKCc8MEA3IDE%2BLzgnLm0uZWFybHkoMS80KSkKICApCiAgcmV0dXJuIHN0YWNrKAogICAgZHJ1bXMuZmFzdCgyKSwgCiAgICBzeW50aHMKICApLnNsb3coMik7Cn0%3D)
|
||||
|
||||
## Disclaimer
|
||||
|
||||
- This project is still in its experimental state. In the future, parts of it might change significantly.
|
||||
- This tutorial is far from complete.
|
||||
|
||||
<br />
|
||||
|
||||
# Mini Notation
|
||||
|
||||
Similar to Tidal Cycles, Strudel has an embedded mini language that is designed to write rhythmic patterns in a short manner.
|
||||
Before diving deeper into the details, here is a flavor of how the mini language looks like:
|
||||
|
||||
<MiniRepl
|
||||
tune={`\`[
|
||||
[
|
||||
[e5 [b4 c5] d5 [c5 b4]]
|
||||
[a4 [a4 c5] e5 [d5 c5]]
|
||||
[b4 [~ c5] d5 e5]
|
||||
[c5 a4 a4 ~]
|
||||
[[~ d5] [~ f5] a5 [g5 f5]]
|
||||
[e5 [~ c5] e5 [d5 c5]]
|
||||
[b4 [b4 c5] d5 e5]
|
||||
[c5 a4 a4 ~]
|
||||
],[
|
||||
[[e2 e3]*4]
|
||||
[[a2 a3]*4]
|
||||
[[g#2 g#3]*2 [e2 e3]*2]
|
||||
[a2 a3 a2 a3 a2 a3 b1 c2]
|
||||
[[d2 d3]*4]
|
||||
[[c2 c3]*4]
|
||||
[[b1 b2]*2 [e2 e3]*2]
|
||||
[[a1 a2]*4]
|
||||
]
|
||||
]/16\``}
|
||||
/>
|
||||
|
||||
The snippet above is enclosed in backticks (`), which allows you to write multi-line strings.
|
||||
You can also use double quotes (") for single line mini notation.
|
||||
|
||||
## Notes
|
||||
|
||||
Notes are notated with the note letter, followed by the octave number. You can notate flats with `b` and sharps with `#`.
|
||||
|
||||
<MiniRepl tune={`"e5"`} />
|
||||
|
||||
Here, the same note is played over and over again, once a second. This one second is the default length of one so called "cycle".
|
||||
|
||||
By the way, you can edit the contents of the player, and press "update" to hear your change!
|
||||
You can also press "play" on the next player without needing to stop the last one.
|
||||
|
||||
## Sequences
|
||||
|
||||
We can play more notes by seperating them with spaces:
|
||||
|
||||
<MiniRepl tune={`"e5 b4 d5 c5"`} />
|
||||
|
||||
Here, those four notes are squashed into one cycle, so each note is a quarter second long.
|
||||
|
||||
## Division
|
||||
|
||||
We can slow the sequence down by enclosing it in brackets and dividing it by a number:
|
||||
|
||||
<MiniRepl tune={`"[e5 b4 d5 c5]/2"`} />
|
||||
|
||||
The division by two means that the sequence will be played over the course of two cycles.
|
||||
You can also use decimal numbers for any tempo you like.
|
||||
|
||||
## Angle Brackets
|
||||
|
||||
Using angle brackets, we can define the sequence length based on the number of children:
|
||||
|
||||
<MiniRepl tune={`"<e5 b4 d5 c5>"`} />
|
||||
|
||||
The above snippet is the same as:
|
||||
|
||||
<MiniRepl tune={`"[e5 b4 d5 c5]/4"`} />
|
||||
|
||||
The advantage of the angle brackets, is that we can add more children without needing to change the number at the end.
|
||||
|
||||
## Multiplication
|
||||
|
||||
Contrary to division, a sequence can be sped up by multiplying it by a number:
|
||||
|
||||
<MiniRepl tune={`"[e5 b4 d5 c5]*2"`} />
|
||||
|
||||
The multiplication by 2 here means that the sequence will play twice a cycle.
|
||||
|
||||
## Bracket Nesting
|
||||
|
||||
To create more interesting rhythms, you can nest sequences with brackets, like this:
|
||||
|
||||
<MiniRepl tune={`"e5 [b4 c5] d5 [c5 b4]"`} />
|
||||
|
||||
## Rests
|
||||
|
||||
The "~" represents a rest:
|
||||
|
||||
<MiniRepl tune={`"[b4 [~ c5] d5 e5]"`} />
|
||||
|
||||
## Parallel
|
||||
|
||||
Using commas, we can play chords:
|
||||
|
||||
<MiniRepl tune={`"g3,b3,e4"`} />
|
||||
|
||||
To play multiple chords in a sequence, we have to wrap them in brackets:
|
||||
|
||||
<MiniRepl tune={`"<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>"`} />
|
||||
|
||||
## Elongation
|
||||
|
||||
With the "@" symbol, we can specify temporal "weight" of a sequence child:
|
||||
|
||||
<MiniRepl tune={`"<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>"`} />
|
||||
|
||||
Here, the first chord has a weight of 2, making it twice the length of the other chords. The default weight is 1.
|
||||
|
||||
## Replication
|
||||
|
||||
Using "!" we can repeat without speeding up:
|
||||
|
||||
<MiniRepl tune={`"<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>"`} />
|
||||
|
||||
In essence, the `x!n` is like a shortcut for `[x*n]@n`.
|
||||
|
||||
## Mini Notation TODO
|
||||
|
||||
Compared to [tidal mini notation](https://tidalcycles.org/docs/patternlib/tutorials/mini_notation/), the following mini notation features are missing from Strudel:
|
||||
|
||||
- [x] Euclidean algorithm "c3(3,2,1)" TODO: document
|
||||
- [ ] Tie symbols "\_"
|
||||
- [ ] feet marking "."
|
||||
- [ ] random choice "|"
|
||||
- [ ] Random removal "?"
|
||||
- [ ] Polymetric sequences "{ ... }"
|
||||
- [ ] Fixed steps using "%"
|
||||
|
||||
<br />
|
||||
|
||||
# Core API
|
||||
|
||||
While the mini notation is powerful on its own, there is much more to discover.
|
||||
Internally, the mini notation will expand to use the actual functional JavaScript API.
|
||||
|
||||
## Notes
|
||||
|
||||
Notes are automatically available as variables:
|
||||
|
||||
<MiniRepl tune={`e4`} />
|
||||
|
||||
An important difference to the mini notation:
|
||||
For sharp notes, the letter "s" is used instead of "#", because JavaScript does not support "#" in a variable name.
|
||||
|
||||
The above is the same as:
|
||||
|
||||
<MiniRepl tune={`"e4"`} />
|
||||
|
||||
Using strings, you can also use "#".
|
||||
|
||||
## Functions that create Patterns
|
||||
|
||||
The following functions will return a pattern. We will see later what that means.
|
||||
|
||||
## pure(value)
|
||||
|
||||
To create a pattern from a value, you can wrap the value in pure:
|
||||
|
||||
<MiniRepl tune={`pure('e4')`} />
|
||||
|
||||
Most of the time, you won't need that function as input values of pattern creating functions are purified by default.
|
||||
|
||||
### cat(...values)
|
||||
|
||||
The given items are con**cat**enated spread evenly over one cycle:
|
||||
|
||||
<MiniRepl tune={`cat(e5, b4, d5, c5)`} />
|
||||
|
||||
The function **fastcat** does the same as **cat**.
|
||||
|
||||
### sequence(...values)
|
||||
|
||||
Like **cat**, but allows nesting with arrays:
|
||||
|
||||
<MiniRepl tune={`sequence(e5, [b4, c5], d5, [c5, b4])`} />
|
||||
|
||||
### stack(...values)
|
||||
|
||||
The given items are played at the same time at the same length:
|
||||
|
||||
<MiniRepl tune={`stack(g3,b3,e4)`} />
|
||||
|
||||
### slowcat(...values)
|
||||
|
||||
Like cat, but each item has the length of one cycle:
|
||||
|
||||
<MiniRepl tune={`slowcat(e5, b4, d5, c5)`} />
|
||||
|
||||
<!-- ## slowcatPrime ? -->
|
||||
|
||||
### Nesting functions
|
||||
|
||||
You can nest functions inside one another:
|
||||
|
||||
<MiniRepl
|
||||
tune={`slowcat(
|
||||
stack(g3,b3,e4),
|
||||
stack(a3,c3,e4),
|
||||
stack(b3,d3,fs4),
|
||||
stack(b3,e4,g4)
|
||||
)`}
|
||||
/>
|
||||
|
||||
The above is equivalent to
|
||||
|
||||
<MiniRepl tune={`"<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>"`} />
|
||||
|
||||
### timeCat(...[weight,value])
|
||||
|
||||
Like with "@" in mini notation, we can specify weights to the items in a sequence:
|
||||
|
||||
<MiniRepl tune={`timeCat([3,e3],[1, g3])`} />
|
||||
|
||||
<!-- ## polymeter
|
||||
|
||||
how to use?
|
||||
|
||||
<MiniRepl tune={`polymeter(3, e3, g3, b3)`} /> -->
|
||||
|
||||
### polyrhythm(...[...values])
|
||||
|
||||
Plays the given items at the same time, within the same length:
|
||||
|
||||
<MiniRepl tune={`polyrhythm([e3, g3], [e4, g4, b4])`} />
|
||||
|
||||
We can write the same with **stack** and **cat**:
|
||||
|
||||
<MiniRepl tune={`stack(cat(e3, g3), cat(e4, g4, b4))`} />
|
||||
|
||||
You can also use the shorthand **pr** instead of **polyrhythm**.
|
||||
|
||||
## Pattern modifier functions
|
||||
|
||||
The following functions modify a pattern.
|
||||
|
||||
### slow(factor)
|
||||
|
||||
Like "/" in mini notation, **slow** will slow down a pattern over the given number of cycles:
|
||||
|
||||
<MiniRepl tune={`cat(e5, b4, d5, c5).slow(2)`} />
|
||||
|
||||
The same in mini notation:
|
||||
|
||||
<MiniRepl tune={`"[e5 b4 d5 c5]/2"`} />
|
||||
|
||||
### fast(factor)
|
||||
|
||||
Like "\*" in mini notation, **fast** will play a pattern times the given number in one cycle:
|
||||
|
||||
<MiniRepl tune={`cat(e5, b4, d5, c5).fast(2)`} />
|
||||
|
||||
### early(cycles)
|
||||
|
||||
With early, you can nudge a pattern to start earlier in time:
|
||||
|
||||
<MiniRepl tune={`cat(e5, b4.early(0.5))`} />
|
||||
|
||||
### late(cycles)
|
||||
|
||||
Like early, but in the other direction:
|
||||
|
||||
<MiniRepl tune={`cat(e5, b4.late(0.5))`} />
|
||||
|
||||
<!-- TODO: shouldn't it sound different? -->
|
||||
|
||||
### rev()
|
||||
|
||||
Will reverse the pattern:
|
||||
|
||||
<MiniRepl tune={`cat(c3,d3,e3,f3).rev()`} />
|
||||
|
||||
### every(n, func)
|
||||
|
||||
Will apply the given function every n cycles:
|
||||
|
||||
<MiniRepl tune={`cat(e5, pure(b4).every(4, late(0.5)))`} />
|
||||
|
||||
<!-- TODO: should be able to do b4.every => like already possible with fast slow etc.. -->
|
||||
|
||||
Note that late is called directly. This is a shortcut for:
|
||||
|
||||
<MiniRepl tune={`cat(e5, pure(b4).every(4, x => x.late(0.5)))`} />
|
||||
|
||||
<!-- TODO: should the function really run the first cycle? -->
|
||||
|
||||
### add(n)
|
||||
|
||||
Adds the given number to each item in the pattern:
|
||||
|
||||
<MiniRepl tune={`"0 2 4".add("<0 3 4 0>").scale('C major')`} />
|
||||
|
||||
Here, the triad `0, 2, 4` is shifted by different amounts. Without add, the equivalent would be:
|
||||
|
||||
<MiniRepl tune={`"<[0 2 4] [3 5 7] [4 6 8] [0 2 4]>".scale('C major')`} />
|
||||
|
||||
You can also use add with notes:
|
||||
|
||||
<MiniRepl tune={`"c3 e3 g3".add("<0 5 7 0>")`} />
|
||||
|
||||
Behind the scenes, the notes are converted to midi numbers as soon before add is applied, which is equivalent to:
|
||||
|
||||
<MiniRepl tune={`"48 52 55".add("<0 5 7 0>")`} />
|
||||
|
||||
### sub(n)
|
||||
|
||||
Like add, but the given numbers are subtracted:
|
||||
|
||||
<MiniRepl tune={`"0 2 4".sub("<0 1 2 3>").scale('C4 minor')`} />
|
||||
|
||||
See add for more information.
|
||||
|
||||
### mul(n)
|
||||
|
||||
Multiplies each number by the given factor:
|
||||
|
||||
<MiniRepl tune={`"0,1,2".mul("<2 3 4 3>").scale('C4 minor')`} />
|
||||
|
||||
... is equivalent to:
|
||||
|
||||
<MiniRepl tune={`"<[0,2,4] [0,3,6] [0,4,8] [0,3,6]>".scale('C4 minor')`} />
|
||||
|
||||
This function is really useful in combination with signals:
|
||||
|
||||
<MiniRepl tune={`sine.struct("x*16").mul(7).round().scale('C major')`} />
|
||||
|
||||
Here, we sample a sine wave 16 times, and multiply each sample by 7. This way, we let values oscillate between 0 and 7.
|
||||
|
||||
### div(n)
|
||||
|
||||
Like mul, but dividing by the given number.
|
||||
|
||||
### round()
|
||||
|
||||
Rounds all values to the nearest integer:
|
||||
|
||||
<MiniRepl tune={`"0.5 1.5 2.5".round().scale('C major')`} />
|
||||
|
||||
### struct(binary_pat)
|
||||
|
||||
Applies the given structure to the pattern:
|
||||
|
||||
<MiniRepl tune={`"c3,eb3,g3".struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~").slow(4)`} />
|
||||
|
||||
This is also useful to sample signals:
|
||||
|
||||
<MiniRepl
|
||||
tune={`sine.struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~").mul(7).round()
|
||||
.scale('C minor').slow(4)`}
|
||||
/>
|
||||
|
||||
### when(binary_pat, func)
|
||||
|
||||
Applies the given function whenever the given pattern is in a true state.
|
||||
|
||||
<MiniRepl tune={`"c3 eb3 g3".when("<0 1>/2", sub(5))`} />
|
||||
|
||||
### superimpose(...func)
|
||||
|
||||
Superimposes the result of the given function(s) on top of the original pattern:
|
||||
|
||||
<MiniRepl tune={`"<c3 eb3 g3>".scale('C minor').superimpose(scaleTranspose("2,4"))`} />
|
||||
|
||||
### layer(...func)
|
||||
|
||||
Layers the result of the given function(s) on top of each other. Like superimpose, but the original pattern is not part of the result.
|
||||
|
||||
<MiniRepl tune={`"<c3 eb3 g3>".scale('C minor').layer(scaleTranspose("0,2,4"))`} />
|
||||
|
||||
### apply(func)
|
||||
|
||||
Like layer, but with a single function:
|
||||
|
||||
<MiniRepl tune={`"<c3 eb3 g3>".scale('C minor').apply(scaleTranspose("0,2,4"))`} />
|
||||
|
||||
### off(time, func)
|
||||
|
||||
Applies the given function by the given time offset:
|
||||
|
||||
<MiniRepl tune={`"c3 eb3 g3".off(1/8, add(7))`} />
|
||||
|
||||
### append(pat)
|
||||
|
||||
Appends the given pattern after the current pattern:
|
||||
|
||||
<MiniRepl tune={`"c4,eb4,g4".append("c4,f4,ab4")`} />
|
||||
|
||||
### stack(pat)
|
||||
|
||||
Stacks the given pattern to the current pattern:
|
||||
|
||||
<MiniRepl tune={`"c4,eb4,g4".stack("bb4,d5")`} />
|
||||
|
||||
## Tone API
|
||||
|
||||
To make the sounds more interesting, we can use Tone.js instruments ands effects.
|
||||
|
||||
[Show Source on Github](https://github.com/tidalcycles/strudel/blob/main/repl/src/tone.ts)
|
||||
|
||||
<MiniRepl
|
||||
tune={`stack(
|
||||
"[c5 c5 bb4 c5] [~ g4 ~ g4] [c5 f5 e5 c5] ~"
|
||||
.tone(synth(adsr(0,.1,0,0)).chain(out())),
|
||||
"[c2 c3]*8"
|
||||
.tone(synth({
|
||||
...osc('sawtooth'),
|
||||
...adsr(0,.1,0.4,0)
|
||||
}).chain(lowpass(300), out()))
|
||||
).slow(4)`}
|
||||
/>
|
||||
|
||||
### tone(instrument)
|
||||
|
||||
To change the instrument of a pattern, you can pass any [Tone.js Source](https://tonejs.github.io/docs/14.7.77/index.html) to .tone:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
|
||||
.tone(new FMSynth().toDestination())`}
|
||||
/>
|
||||
|
||||
While this works, it is a little bit verbose. To simplify things, all Tone Synths have a shortcut:
|
||||
|
||||
```js
|
||||
const amsynth = (options) => new AMSynth(options);
|
||||
const duosynth = (options) => new DuoSynth(options);
|
||||
const fmsynth = (options) => new FMSynth(options);
|
||||
const membrane = (options) => new MembraneSynth(options);
|
||||
const metal = (options) => new MetalSynth(options);
|
||||
const monosynth = (options) => new MonoSynth(options);
|
||||
const noise = (options) => new NoiseSynth(options);
|
||||
const pluck = (options) => new PluckSynth(options);
|
||||
const polysynth = (options) => new PolySynth(options);
|
||||
const synth = (options) => new Synth(options);
|
||||
const sampler = (options, baseUrl?) => new Sampler(options); // promisified, see below
|
||||
const players = (options, baseUrl?) => new Sampler(options); // promisified, see below
|
||||
```
|
||||
|
||||
### sampler
|
||||
|
||||
With sampler, you can create tonal instruments from samples:
|
||||
|
||||
<MiniRepl
|
||||
tune={`sampler({
|
||||
C5: 'https://freesound.org/data/previews/536/536549_11935698-lq.mp3'
|
||||
}).then(kalimba =>
|
||||
saw.struct("x*8").mul(16).round()
|
||||
.legato(4).scale('D dorian').slow(2)
|
||||
.tone(kalimba.toDestination())
|
||||
)`}
|
||||
/>
|
||||
|
||||
The sampler function promisifies [Tone.js Sampler](https://tonejs.github.io/docs/14.7.77/Sampler).
|
||||
|
||||
Note that this function currently only works with this promise notation, but in the future,
|
||||
it will be possible to use async instruments in a synchronous fashion.
|
||||
|
||||
### players
|
||||
|
||||
With players, you can create sound banks:
|
||||
|
||||
<MiniRepl
|
||||
tune={`players({
|
||||
bd: 'samples/tidal/bd/BT0A0D0.wav',
|
||||
sn: 'samples/tidal/sn/ST0T0S3.wav',
|
||||
hh: 'samples/tidal/hh/000_hh3closedhh.wav'
|
||||
}, 'https://loophole-letters.vercel.app/')
|
||||
.then(drums=>
|
||||
"bd hh sn hh".tone(drums.toDestination())
|
||||
)
|
||||
`}
|
||||
/>
|
||||
|
||||
The sampler function promisifies [Tone.js Players](https://tonejs.github.io/docs/14.7.77/Players).
|
||||
|
||||
Note that this function currently only works with this promise notation, but in the future,
|
||||
it will be possible to use async instruments in a synchronous fashion.
|
||||
|
||||
### out
|
||||
|
||||
Shortcut for Tone.Destination. Intended to be used with Tone's .chain:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
|
||||
.tone(membrane().chain(out()))`}
|
||||
/>
|
||||
|
||||
This alone is not really useful, so read on..
|
||||
|
||||
### vol(volume)
|
||||
|
||||
Helper that returns a Gain Node with the given volume. Intended to be used with Tone's .chain:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
|
||||
.tone(noise().chain(vol(0.5), out()))`}
|
||||
/>
|
||||
|
||||
### osc(type)
|
||||
|
||||
Helper to set the waveform of a synth, monosynth or polysynth:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
|
||||
.tone(synth(osc('sawtooth4')).chain(out()))`}
|
||||
/>
|
||||
|
||||
The base types are `sine`, `square`, `sawtooth`, `triangle`. You can also append a number between 1 and 32 to reduce the harmonic partials.
|
||||
|
||||
### lowpass(cutoff)
|
||||
|
||||
Helper that returns a Filter Node of type lowpass with the given cutoff. Intended to be used with Tone's .chain:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
|
||||
.tone(synth(osc('sawtooth')).chain(lowpass(800), out()))`}
|
||||
/>
|
||||
|
||||
### highpass(cutoff)
|
||||
|
||||
Helper that returns a Filter Node of type highpass with the given cutoff. Intended to be used with Tone's .chain:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
|
||||
.tone(synth(osc('sawtooth')).chain(highpass(2000), out()))`}
|
||||
/>
|
||||
|
||||
### adsr(attack, decay?, sustain?, release?)
|
||||
|
||||
Helper to set the envelope of a Tone.js instrument. Intended to be used with Tone's .set:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~".slow(4)
|
||||
.tone(synth(adsr(0,.1,0,0)).chain(out()))`}
|
||||
/>
|
||||
|
||||
### Experimental: Patternification
|
||||
|
||||
While the above methods work for static sounds, there is also the option to patternify tone methods.
|
||||
This is currently experimental, because the performance is not stable, and audio glitches will appear after some time.
|
||||
It would be great to get this to work without glitches though, because it is fun!
|
||||
|
||||
#### synth(type)
|
||||
|
||||
With .synth, you can create a synth with a variable wave type:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~"
|
||||
.synth("<sawtooth8 square8>").slow(4)`}
|
||||
/>
|
||||
|
||||
#### adsr(attack, decay?, sustain?, release?)
|
||||
|
||||
Chainable Envelope helper:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c5 c5 bb4 c5] [~ g4 ~ g4] [c5 f5 e5 c5] ~".slow(4)
|
||||
.synth('sawtooth16').adsr(0,.1,0,0)`}
|
||||
/>
|
||||
|
||||
Due to having more than one argument, this method is not patternified.
|
||||
|
||||
#### filter(cuttoff)
|
||||
|
||||
Patternified filter:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~"
|
||||
.synth('sawtooth16').filter("[500 2000]*8").slow(4)`}
|
||||
/>
|
||||
|
||||
#### gain(value)
|
||||
|
||||
Patternified gain:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"[c4 c4 bb3 c4] [~ g3 ~ g3] [c4 f4 e4 c4] ~"
|
||||
.synth('sawtooth16').gain("[.2 .8]*8").slow(4)`}
|
||||
/>
|
||||
|
||||
#### autofilter(value)
|
||||
|
||||
Patternified autofilter:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"c2 c3"
|
||||
.synth('sawtooth16').autofilter("<1 4 8>"")`}
|
||||
/>
|
||||
|
||||
## Tonal API
|
||||
|
||||
The Tonal API, uses [tonaljs](https://github.com/tonaljs/tonal) to provide helpers for musical operations.
|
||||
|
||||
### transpose(semitones)
|
||||
|
||||
Transposes all notes to the given number of semitones:
|
||||
|
||||
<MiniRepl tune={`"c2 c3".fast(2).transpose("<0 -2 5 3>".slow(2)).transpose(0)`} />
|
||||
|
||||
This method gets really exciting when we use it with a pattern as above.
|
||||
|
||||
Instead of numbers, scientific interval notation can be used as well:
|
||||
|
||||
<MiniRepl tune={`"c2 c3".fast(2).transpose("<1P -2M 4P 3m>".slow(2)).transpose(1)`} />
|
||||
|
||||
### scale(name)
|
||||
|
||||
Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like scaleTranpose.
|
||||
|
||||
<MiniRepl
|
||||
tune={`"0 2 4 6 4 2"
|
||||
.scale(slowcat('C2 major', 'C2 minor').slow(2))`}
|
||||
/>
|
||||
|
||||
Note that the scale root is octaved here. You can also omit the octave, then index zero will default to octave 3.
|
||||
|
||||
All the available scale names can be found [here](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts).
|
||||
|
||||
### scaleTranspose(steps)
|
||||
|
||||
Transposes notes inside the scale by the number of steps:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"-8 [2,4,6]"
|
||||
.scale('C4 bebop major')
|
||||
.scaleTranspose("<0 -1 -2 -3 -4 -5 -6 -4>")`}
|
||||
/>
|
||||
|
||||
### voicings(range?)
|
||||
|
||||
Turns chord symbols into voicings, using the smoothest voice leading possible:
|
||||
|
||||
<MiniRepl tune={`stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>")`} />
|
||||
|
||||
<!-- TODO: use voicing collection as first param + patternify. -->
|
||||
|
||||
### rootNotes(octave = 2)
|
||||
|
||||
Turns chord symbols into root notes of chords in given octave.
|
||||
|
||||
<MiniRepl tune={`"<C^7 A7b13 Dm7 G7>".rootNotes(3)`} />
|
||||
|
||||
Together with edit, struct and voicings, this can be used to create a basic backing track:
|
||||
|
||||
<MiniRepl
|
||||
tune={`"<C^7 A7b13 Dm7 G7>".edit(
|
||||
x => x.voicings(['d3','g4']).struct("~ x"),
|
||||
x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out()))
|
||||
)`}
|
||||
/>
|
||||
|
||||
<!-- TODO: use range instead of octave. -->
|
||||
<!-- TODO: find out why composition does not work -->
|
||||
|
||||
## Microtonal API
|
||||
|
||||
TODO
|
||||
|
||||
## MIDI API
|
||||
|
||||
Strudel also supports midi via [webmidi](https://npmjs.com/package/webmidi).
|
||||
|
||||
### midi(outputName?)
|
||||
|
||||
Make sure to have a midi device connected or to use an IAC Driver.
|
||||
If no outputName is given, it uses the first midi output it finds.
|
||||
|
||||
Midi is currently not supported by the mini repl used here, but you can [open the midi example in the repl](https://strudel.tidalcycles.org/#c3RhY2soIjxDXjcgQTcgRG03IEc3PiIubS52b2ljaW5ncygpLCAnPEMzIEEyIEQzIEcyPicubSkKICAubWlkaSgp).
|
||||
|
||||
In the REPL, you will se a log of the available MIDI devices.
|
||||
|
||||
<!--<MiniRepl
|
||||
tune={`stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>")
|
||||
.midi()`}
|
||||
/>-->
|
||||
|
||||
# Contributing
|
||||
|
||||
Contributions of any sort are very welcome! You can contribute by editing [this file](https://github.com/tidalcycles/strudel/blob/main/repl/src/tutorial/tutorial.mdx).
|
||||
All you need is a github account.
|
||||
|
||||
If you want to run the tutorial locally, you can clone the and run:
|
||||
|
||||
```sh
|
||||
cd repl && npm i && npm run tutorial
|
||||
```
|
||||
|
||||
If you want to contribute in another way, either
|
||||
|
||||
- [fork strudel repo on GitHub](https://github.com/tidalcycles/strudel)
|
||||
- [Join the Discord Channel](https://discord.gg/remJ6gQA)
|
||||
- [play with the Strudel REPL](https://strudel.tidalcycles.org/)
|
||||
Vendored
-27
@@ -1,27 +0,0 @@
|
||||
import type { State } from '../../strudel.mjs';
|
||||
|
||||
export declare interface Fraction {
|
||||
(v: number): Fraction;
|
||||
d: number;
|
||||
n: number;
|
||||
s: number;
|
||||
sub: (f: Fraction) => Fraction;
|
||||
sam: () => Fraction;
|
||||
equals: (f: Fraction) => boolean;
|
||||
}
|
||||
export declare interface TimeSpan {
|
||||
constructor: any; //?
|
||||
begin: Fraction;
|
||||
end: Fraction;
|
||||
}
|
||||
export declare interface Hap<T = any> {
|
||||
whole: TimeSpan;
|
||||
part: TimeSpan;
|
||||
value: T;
|
||||
context: any;
|
||||
show: () => string;
|
||||
}
|
||||
export declare interface Pattern<T = any> {
|
||||
query: (span: State) => Hap<T>[];
|
||||
fmap: (v: T) => T;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import * as Tone from 'tone';
|
||||
|
||||
export const hideHeader = () => {
|
||||
document.getElementById('header').style = 'display:none';
|
||||
};
|
||||
|
||||
function frame(callback) {
|
||||
if (window.strudelAnimation) {
|
||||
cancelAnimationFrame(window.strudelAnimation);
|
||||
}
|
||||
const animate = (animationTime) => {
|
||||
const toneTime = Tone.getTransport().seconds;
|
||||
callback(animationTime, toneTime);
|
||||
window.strudelAnimation = requestAnimationFrame(animate);
|
||||
};
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
export const backgroundImage = function (src, animateOptions = {}) {
|
||||
const container = document.getElementById('code');
|
||||
const bg = 'background-image:url(' + src + ');background-size:contain;';
|
||||
container.style = bg;
|
||||
const { className: initialClassName } = container;
|
||||
const handleOption = (option, value) => {
|
||||
({
|
||||
style: () => (container.style = bg + ';' + value),
|
||||
className: () => (container.className = value + ' ' + initialClassName),
|
||||
}[option]());
|
||||
};
|
||||
const funcOptions = Object.entries(animateOptions).filter(([_, v]) => typeof v === 'function');
|
||||
const stringOptions = Object.entries(animateOptions).filter(([_, v]) => typeof v === 'string');
|
||||
stringOptions.forEach(([option, value]) => handleOption(option, value));
|
||||
|
||||
if (funcOptions.length === 0) {
|
||||
return;
|
||||
}
|
||||
frame((_, t) =>
|
||||
funcOptions.forEach(([option, value]) => {
|
||||
handleOption(option, value(t));
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
export const cleanup = () => {
|
||||
const container = document.getElementById('code');
|
||||
if (container) {
|
||||
container.style = '';
|
||||
container.className = 'grow relative'; // has to match App.tsx
|
||||
}
|
||||
};
|
||||
@@ -1,87 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import type { ToneEventCallback } from 'tone';
|
||||
import * as Tone from 'tone';
|
||||
import { TimeSpan, State } from '../../strudel.mjs';
|
||||
import type { Hap } from './types';
|
||||
|
||||
export declare interface UseCycleProps {
|
||||
onEvent: ToneEventCallback<any>;
|
||||
onQuery?: (state: State) => Hap[];
|
||||
onSchedule?: (events: Hap[], cycle: number) => void;
|
||||
onDraw?: ToneEventCallback<any>;
|
||||
ready?: boolean; // if false, query will not be called on change props
|
||||
}
|
||||
|
||||
function useCycle(props: UseCycleProps) {
|
||||
// onX must use useCallback!
|
||||
const { onEvent, onQuery, onSchedule, ready = true, onDraw } = props;
|
||||
const [started, setStarted] = useState<boolean>(false);
|
||||
const cycleDuration = 1;
|
||||
const activeCycle = () => Math.floor(Tone.getTransport().seconds / cycleDuration);
|
||||
|
||||
// pull events with onQuery + count up to next cycle
|
||||
const query = (cycle = activeCycle()) => {
|
||||
const timespan = new TimeSpan(cycle, cycle + 1);
|
||||
const events = onQuery?.(new State(timespan)) || [];
|
||||
onSchedule?.(events, cycle);
|
||||
// cancel events after current query. makes sure no old events are player for rescheduled cycles
|
||||
// console.log('schedule', cycle);
|
||||
// query next cycle in the middle of the current
|
||||
const cancelFrom = timespan.begin.valueOf();
|
||||
Tone.getTransport().cancel(cancelFrom);
|
||||
// const queryNextTime = (cycle + 1) * cycleDuration - 0.1;
|
||||
const queryNextTime = (cycle + 1) * cycleDuration - 0.5;
|
||||
|
||||
// if queryNextTime would be before current time, execute directly (+0.1 for safety that it won't miss)
|
||||
const t = Math.max(Tone.getTransport().seconds, queryNextTime) + 0.1;
|
||||
Tone.getTransport().schedule(() => {
|
||||
query(cycle + 1);
|
||||
}, t);
|
||||
|
||||
// schedule events for next cycle
|
||||
events
|
||||
?.filter((event) => event.part.begin.equals(event.whole.begin))
|
||||
.forEach((event) => {
|
||||
Tone.getTransport().schedule((time) => {
|
||||
const toneEvent = {
|
||||
time: event.whole.begin.valueOf(),
|
||||
duration: event.whole.end.sub(event.whole.begin).valueOf(),
|
||||
value: event.value,
|
||||
context: event.context,
|
||||
};
|
||||
onEvent(time, toneEvent);
|
||||
Tone.Draw.schedule(() => {
|
||||
// do drawing or DOM manipulation here
|
||||
onDraw?.(time, toneEvent);
|
||||
}, time);
|
||||
}, event.part.begin.valueOf());
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
ready && query();
|
||||
}, [onEvent, onSchedule, onQuery, onDraw, ready]);
|
||||
|
||||
const start = async () => {
|
||||
setStarted(true);
|
||||
await Tone.start();
|
||||
Tone.getTransport().start('+0.1');
|
||||
};
|
||||
const stop = () => {
|
||||
Tone.getTransport().pause();
|
||||
setStarted(false);
|
||||
};
|
||||
const toggle = () => (started ? stop() : start());
|
||||
return {
|
||||
start,
|
||||
stop,
|
||||
onEvent,
|
||||
started,
|
||||
setStarted,
|
||||
toggle,
|
||||
query,
|
||||
activeCycle,
|
||||
};
|
||||
}
|
||||
|
||||
export default useCycle;
|
||||
@@ -1,11 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
function usePostMessage(listener) {
|
||||
useEffect(() => {
|
||||
window.addEventListener('message', listener);
|
||||
return () => window.removeEventListener('message', listener);
|
||||
}, [listener]);
|
||||
return (data) => window.postMessage(data, '*');
|
||||
}
|
||||
|
||||
export default usePostMessage;
|
||||
@@ -1,175 +0,0 @@
|
||||
import { useCallback, useState, useMemo } from 'react';
|
||||
import { getPlayableNoteValue } from '../../util.mjs';
|
||||
import { evaluate } from './evaluate';
|
||||
import type { Pattern } from './types';
|
||||
import useCycle from './useCycle';
|
||||
import usePostMessage from './usePostMessage';
|
||||
|
||||
let s4 = () => {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
};
|
||||
|
||||
function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw }: any) {
|
||||
const id = useMemo(() => s4(), []);
|
||||
const [code, setCode] = useState<string>(tune);
|
||||
const [activeCode, setActiveCode] = useState<string>();
|
||||
const [log, setLog] = useState('');
|
||||
const [error, setError] = useState<Error>();
|
||||
const [pending, setPending] = useState(false);
|
||||
const [hash, setHash] = useState('');
|
||||
const [pattern, setPattern] = useState<Pattern>();
|
||||
const dirty = code !== activeCode || error;
|
||||
const generateHash = () => encodeURIComponent(btoa(code));
|
||||
const activateCode = async (_code = code) => {
|
||||
if (activeCode && !dirty) {
|
||||
setError(undefined);
|
||||
cycle.start();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setPending(true);
|
||||
const parsed = await evaluate(_code);
|
||||
cycle.start();
|
||||
broadcast({ type: 'start', from: id });
|
||||
setPattern(() => parsed.pattern);
|
||||
if (autolink) {
|
||||
window.location.hash = '#' + encodeURIComponent(btoa(code));
|
||||
}
|
||||
setHash(generateHash());
|
||||
setError(undefined);
|
||||
setActiveCode(_code);
|
||||
setPending(false);
|
||||
} catch (err: any) {
|
||||
err.message = 'evaluation error: ' + err.message;
|
||||
console.warn(err);
|
||||
setError(err);
|
||||
}
|
||||
};
|
||||
const pushLog = (message: string) => setLog((log) => log + `${log ? '\n\n' : ''}${message}`);
|
||||
// logs events of cycle
|
||||
const logCycle = (_events: any, cycle: any) => {
|
||||
if (_events.length) {
|
||||
// pushLog(`# cycle ${cycle}\n` + _events.map((e: any) => e.show()).join('\n'));
|
||||
}
|
||||
};
|
||||
|
||||
// below block allows disabling the highlighting by including "strudel disable-highlighting" in the code (as comment)
|
||||
onDraw = useMemo(() => {
|
||||
if (activeCode && !activeCode.includes('strudel disable-highlighting')) {
|
||||
return onDraw;
|
||||
}
|
||||
}, [activeCode]);
|
||||
|
||||
// cycle hook to control scheduling
|
||||
const cycle = useCycle({
|
||||
onDraw,
|
||||
onEvent: useCallback(
|
||||
(time, event) => {
|
||||
try {
|
||||
onEvent?.(event);
|
||||
const { onTrigger, velocity } = event.context;
|
||||
if (!onTrigger) {
|
||||
if (defaultSynth) {
|
||||
const note = getPlayableNoteValue(event);
|
||||
defaultSynth.triggerAttackRelease(note, event.duration, time, velocity);
|
||||
} else {
|
||||
throw new Error('no defaultSynth passed to useRepl.');
|
||||
}
|
||||
/* console.warn('no instrument chosen', event);
|
||||
throw new Error(`no instrument chosen for ${JSON.stringify(event)}`); */
|
||||
} else {
|
||||
onTrigger(time, event);
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.warn(err);
|
||||
err.message = 'unplayable event: ' + err?.message;
|
||||
pushLog(err.message); // not with setError, because then we would have to setError(undefined) on next playable event
|
||||
}
|
||||
},
|
||||
[onEvent]
|
||||
),
|
||||
onQuery: useCallback(
|
||||
(state) => {
|
||||
try {
|
||||
return pattern?.query(state) || [];
|
||||
} catch (err: any) {
|
||||
console.warn(err);
|
||||
err.message = 'query error: ' + err.message;
|
||||
setError(err);
|
||||
return [];
|
||||
}
|
||||
},
|
||||
[pattern]
|
||||
),
|
||||
onSchedule: useCallback((_events, cycle) => logCycle(_events, cycle), [pattern]),
|
||||
ready: !!pattern && !!activeCode,
|
||||
});
|
||||
|
||||
const broadcast = usePostMessage(({ data: { from, type } }) => {
|
||||
if (type === 'start' && from !== id) {
|
||||
// console.log('message', from, type);
|
||||
cycle.setStarted(false);
|
||||
setActiveCode(undefined);
|
||||
}
|
||||
});
|
||||
|
||||
// set active pattern on ctrl+enter
|
||||
/* useLayoutEffect(() => {
|
||||
// TODO: make sure this is only fired when editor has focus
|
||||
const handleKeyPress = (e: any) => {
|
||||
if (e.ctrlKey || e.altKey) {
|
||||
switch (e.code) {
|
||||
case 'Enter':
|
||||
activateCode();
|
||||
!cycle.started && cycle.start();
|
||||
break;
|
||||
case 'Period':
|
||||
cycle.stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
document.addEventListener('keypress', handleKeyPress);
|
||||
return () => document.removeEventListener('keypress', handleKeyPress);
|
||||
}, [pattern, code]); */
|
||||
|
||||
/* useWebMidi({
|
||||
ready: useCallback(({ outputs }) => {
|
||||
pushLog(`WebMidi ready! Just add .midi(${outputs.map((o) => `'${o.name}'`).join(' | ')}) to the pattern. `);
|
||||
}, []),
|
||||
connected: useCallback(({ outputs }) => {
|
||||
pushLog(`Midi device connected! Available: ${outputs.map((o) => `'${o.name}'`).join(', ')}`);
|
||||
}, []),
|
||||
disconnected: useCallback(({ outputs }) => {
|
||||
pushLog(`Midi device disconnected! Available: ${outputs.map((o) => `'${o.name}'`).join(', ')}`);
|
||||
}, []),
|
||||
}); */
|
||||
|
||||
const togglePlay = () => {
|
||||
if (!cycle.started) {
|
||||
activateCode();
|
||||
} else {
|
||||
cycle.stop();
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
pending,
|
||||
code,
|
||||
setCode,
|
||||
pattern,
|
||||
error,
|
||||
cycle,
|
||||
setPattern,
|
||||
dirty,
|
||||
log,
|
||||
togglePlay,
|
||||
activateCode,
|
||||
activeCode,
|
||||
pushLog,
|
||||
hash,
|
||||
};
|
||||
}
|
||||
|
||||
export default useRepl;
|
||||
@@ -1,50 +0,0 @@
|
||||
import { Pattern as _Pattern, stack, Hap, reify } from '../../strudel.mjs';
|
||||
import _voicings from 'chord-voicings';
|
||||
const { dictionaryVoicing, minTopNoteDiff, lefthand } = _voicings;
|
||||
|
||||
const getVoicing = (chord, lastVoicing, range = ['F3', 'A4']) =>
|
||||
dictionaryVoicing({
|
||||
chord,
|
||||
dictionary: lefthand,
|
||||
range,
|
||||
picker: minTopNoteDiff,
|
||||
lastVoicing,
|
||||
});
|
||||
|
||||
const Pattern = _Pattern as any;
|
||||
|
||||
Pattern.prototype.fmapNested = function (func) {
|
||||
return new Pattern((span) =>
|
||||
this.query(span)
|
||||
.map((event) =>
|
||||
reify(func(event))
|
||||
.query(span)
|
||||
.map((hap) => new Hap(event.whole, event.part, hap.value, hap.context))
|
||||
)
|
||||
.flat()
|
||||
);
|
||||
};
|
||||
|
||||
Pattern.prototype.voicings = function (range) {
|
||||
let lastVoicing;
|
||||
if (!range?.length) {
|
||||
// allows to pass empty array, if too lazy to specify range
|
||||
range = ['F3', 'A4'];
|
||||
}
|
||||
return this.fmapNested((event) => {
|
||||
lastVoicing = getVoicing(event.value, lastVoicing, range);
|
||||
return stack(...lastVoicing)._withContext(() => ({
|
||||
locations: event.context.locations || [],
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
Pattern.prototype._rootNotes = function (octave = 2) {
|
||||
return this.fmap((value) => {
|
||||
const [_, root] = value.match(/^([a-gA-G][b#]?).*$/);
|
||||
return root + octave;
|
||||
});
|
||||
};
|
||||
|
||||
Pattern.prototype.define('voicings', (range, pat) => pat.voicings(range), { composable: true });
|
||||
Pattern.prototype.define('rootNotes', (oct, pat) => pat.rootNotes(oct), { composable: true, patternified: true });
|
||||
@@ -1,62 +0,0 @@
|
||||
import { Pattern } from '../../strudel.mjs';
|
||||
import { mod } from '../../util.mjs';
|
||||
|
||||
function edo(name) {
|
||||
if (!/^[1-9]+[0-9]*edo$/.test(name)) {
|
||||
throw new Error('not an edo scale: "' + name + '"');
|
||||
}
|
||||
const [_, divisions] = name.match(/^([1-9]+[0-9]*)edo$/);
|
||||
return Array.from({ length: divisions }, (_, i) => Math.pow(2, i / divisions));
|
||||
}
|
||||
|
||||
const presets = {
|
||||
'12ji': [1 / 1, 16 / 15, 9 / 8, 6 / 5, 5 / 4, 4 / 3, 45 / 32, 3 / 2, 8 / 5, 5 / 3, 16 / 9, 15 / 8],
|
||||
};
|
||||
|
||||
function withBase(freq, scale) {
|
||||
return scale.map((r) => r * freq);
|
||||
}
|
||||
|
||||
const defaultBase = 220;
|
||||
|
||||
function getXenScale(scale, indices) {
|
||||
if (typeof scale === 'string') {
|
||||
if (/^[1-9]+[0-9]*edo$/.test(scale)) {
|
||||
scale = edo(scale);
|
||||
} else if (presets[scale]) {
|
||||
scale = presets[scale];
|
||||
} else {
|
||||
throw new Error('unknown scale name: "' + scale + '"');
|
||||
}
|
||||
}
|
||||
scale = withBase(defaultBase, scale);
|
||||
if (!indices) {
|
||||
return scale;
|
||||
}
|
||||
return scale.filter((_, i) => indices.includes(i));
|
||||
}
|
||||
|
||||
function xenOffset(xenScale, offset, index = 0) {
|
||||
const i = mod(index + offset, xenScale.length);
|
||||
const oct = Math.floor(offset / xenScale.length);
|
||||
return xenScale[i] * Math.pow(2, oct);
|
||||
}
|
||||
|
||||
// scaleNameOrRatios: string || number[], steps?: number
|
||||
Pattern.prototype._xen = function (scaleNameOrRatios, steps) {
|
||||
return this._asNumber()._withEvent((event) => {
|
||||
const scale = getXenScale(scaleNameOrRatios);
|
||||
steps = steps || scale.length;
|
||||
const frequency = xenOffset(scale, event.value);
|
||||
return event.withValue(() => frequency).setContext({ ...event.context, type: 'frequency' });
|
||||
});
|
||||
};
|
||||
|
||||
Pattern.prototype.tuning = function (steps) {
|
||||
return this._asNumber()._withEvent((event) => {
|
||||
const frequency = xenOffset(steps, event.value);
|
||||
return event.withValue(() => frequency).setContext({ ...event.context, type: 'frequency' });
|
||||
});
|
||||
};
|
||||
Pattern.prototype.define('xen', (scale, pat) => pat.xen(scale), { composable: true, patternified: true });
|
||||
// Pattern.prototype.define('tuning', (scale, pat) => pat.xen(scale), { composable: true, patternified: false });
|
||||
@@ -1,8 +0,0 @@
|
||||
module.exports = {
|
||||
content: ['./public/**/*.html', './src/**/*.{js,jsx,ts,tsx,mdx}'],
|
||||
// specify other options here
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')],
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"include": ["src", "types", "public/hot.js", "tutorial"],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "preserve",
|
||||
"baseUrl": "./",
|
||||
/* paths - import rewriting/resolving */
|
||||
"paths": {
|
||||
// If you configured any Snowpack aliases, add them here.
|
||||
// Add this line to get types for streaming imports (packageOptions.source="remote"):
|
||||
// "*": [".snowpack/types/*"]
|
||||
// More info: https://www.snowpack.dev/guides/streaming-imports
|
||||
},
|
||||
/* noEmit - Snowpack builds (emits) files, not tsc. */
|
||||
"noEmit": true,
|
||||
/* Additional Options */
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"types": ["mocha", "snowpack-env"],
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"importsNotUsedAsValues": "error",
|
||||
"noImplicitAny": false
|
||||
}
|
||||
}
|
||||
Vendored
-59
@@ -1,59 +0,0 @@
|
||||
/* Use this file to declare any custom file extensions for importing */
|
||||
/* Use this folder to also add/extend a package d.ts file, if needed. */
|
||||
|
||||
/* CSS MODULES */
|
||||
declare module '*.module.css' {
|
||||
const classes: { [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
declare module '*.module.scss' {
|
||||
const classes: { [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
declare module '*.module.sass' {
|
||||
const classes: { [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
declare module '*.module.less' {
|
||||
const classes: { [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
declare module '*.module.styl' {
|
||||
const classes: { [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
/* CSS */
|
||||
declare module '*.css';
|
||||
declare module '*.scss';
|
||||
declare module '*.sass';
|
||||
declare module '*.less';
|
||||
declare module '*.styl';
|
||||
|
||||
/* IMAGES */
|
||||
declare module '*.svg' {
|
||||
const ref: string;
|
||||
export default ref;
|
||||
}
|
||||
declare module '*.bmp' {
|
||||
const ref: string;
|
||||
export default ref;
|
||||
}
|
||||
declare module '*.gif' {
|
||||
const ref: string;
|
||||
export default ref;
|
||||
}
|
||||
declare module '*.jpg' {
|
||||
const ref: string;
|
||||
export default ref;
|
||||
}
|
||||
declare module '*.jpeg' {
|
||||
const ref: string;
|
||||
export default ref;
|
||||
}
|
||||
declare module '*.png' {
|
||||
const ref: string;
|
||||
export default ref;
|
||||
}
|
||||
|
||||
/* CUSTOM: ADD YOUR OWN HERE */
|
||||
Reference in New Issue
Block a user