diff --git a/package.json b/package.json index 8f64528..7e804dc 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,9 @@ }, "devDependencies": { "@tauri-apps/cli": "^1.4.0", + "@types/audioworklet": "^0.0.49", "typescript": "^5.0.2", - "vite": "^4.4.5", - "@types/audioworklet": "^0.0.49" + "vite": "^4.4.5" }, "dependencies": { "@codemirror/lang-javascript": "^6.1.9", @@ -20,6 +20,9 @@ "@codemirror/theme-one-dark": "^6.1.2", "@replit/codemirror-vim": "^6.0.14", "@strudel.cycles/webaudio": "^0.8.2", + "acorn": "^8.10.0", + "acorn-walk": "^8.2.0", + "astring": "^1.8.6", "autoprefixer": "^10.4.14", "codemirror": "^6.0.1", "postcss": "^8.4.27", diff --git a/src/API.ts b/src/API.ts index e41b4fa..1f4f049 100644 --- a/src/API.ts +++ b/src/API.ts @@ -4,6 +4,9 @@ import { tryEvaluate } from "./Evaluator"; import { MidiConnection } from "./IO/MidiConnection"; // @ts-ignore import { webaudioOutput, samples } from '@strudel.cycles/webaudio'; +import { MiniLanguage } from "./Walker"; +import * as astring from 'astring'; + const sound = (value: any) => ({ value, context: {}, @@ -139,7 +142,6 @@ export class UserAPI { // would be 1.0, which is the current rate (very speedy). } - script(...args: number[]): void { /** * Evaluates 1-n local script(s) @@ -180,7 +182,6 @@ export class UserAPI { } cps = this.copyscript - // ============================================================= // MIDI related functions // ============================================================= @@ -208,7 +209,7 @@ export class UserAPI { } } - public note(note: number, channel: number, velocity: number, duration: number): void { + public note(note: number, channel: number = 0, velocity: number = 100, duration: number = 0.5): void { /** * Sends a MIDI note to the current MIDI output. * TODO: Fix note duration @@ -313,15 +314,7 @@ export class UserAPI { // Return current iterator value return this.iterators[name].value; } - it = this.iterator - - get _() { - return this.iterator('_'); - } - - get A() { - return this.iterator('A'); - } + $ = this.iterator // ============================================================= // Drunk mechanism @@ -466,7 +459,7 @@ export class UserAPI { * @param array - The array of values to pick from */ return array[this.app.clock.time_position.pulse % array.length] - } + } // ============================================================= // Randomness functions @@ -953,4 +946,10 @@ export class UserAPI { sound = async (values: object) => { webaudioOutput(sound(values), 0.00) } + + ast(code: string) { + const ast = MiniLanguage.parse(code, { ecmaVersion: 2020 }); + console.log(astring.generate(ast)) + return + } } diff --git a/src/Walker.ts b/src/Walker.ts new file mode 100644 index 0000000..3e88019 --- /dev/null +++ b/src/Walker.ts @@ -0,0 +1,66 @@ +import * as acorn from 'acorn'; +import * as walk from 'acorn-walk'; +import * as astring from 'astring'; + +// Create a custom Acorn plugin +function myPlugin(Parser: typeof acorn.Parser): any { + return class extends Parser { + parseLiteral(...args: Parameters) { + const node = super.parseLiteral(...args); + + // Check if the literal is a string and if it's wrapped in single quotes + if (typeof node.value === 'string' && this.input.slice(node.start, node.end).startsWith("'")) { + const transformed = this.transformMyString(node.value); + + // Replace the Literal node with an ArrayExpression node + return { + type: 'SpreadElement', + argument: { + type: 'ArrayExpression', + elements: transformed.map(value => ({ + type: 'Literal', + value, + raw: value.toString() + })) + }, + start: node.start, + end: node.end + }; + } + + return node; + } + + transformMyString(string: string): number[] { + const matches = string.match(/\d+!*\d*/g); + const values: number[] = []; + + matches?.forEach(match => { + const parts = match.split('!'); + const number = parseInt(parts[0]); + const times = parts[1] ? parseInt(parts[1]) : 1; + + for (let i = 0; i < times; i++) { + values.push(number); + } + }); + + return values; + } + }; +} + +export const MiniLanguage = acorn.Parser.extend(myPlugin); + +// Sample code +// const code = ` +// const a = '3!4 5'; // This should become const a = [...[3,3,3,3,5]]; +// `; + +// Parse the code +// const ast = MiniLanguage.parse(code, { ecmaVersion: 2020 }); + +// Convert the transformed AST back into source code +// const newCode = astring.generate(ast); + +// console.log(newCode); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index d30bf8e..aa64bd2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -451,6 +451,16 @@ resolved "https://registry.npmjs.org/@types/audioworklet/-/audioworklet-0.0.49.tgz" integrity sha512-Njo9vdkdTPwBTplwWgIXQk7Xoo5xAErxOfNXoq5pYHcYOZ1Yyp4M23TfeavaLZ+qqQo3y9xIigfWckizkyCKSw== +acorn-walk@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.10.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" @@ -469,6 +479,11 @@ arg@^5.0.2: resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== +astring@^1.8.6: + version "1.8.6" + resolved "https://registry.yarnpkg.com/astring/-/astring-1.8.6.tgz#2c9c157cf1739d67561c56ba896e6948f6b93731" + integrity sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg== + automation-events@^6.0.8: version "6.0.8" resolved "https://registry.npmjs.org/automation-events/-/automation-events-6.0.8.tgz"