@devaloop/devalang 0.0.1-alpha.16-hotfix.1 → 0.0.1-alpha.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cargo/config.toml +2 -0
- package/.devalang +6 -10
- package/.github/workflows/ci.yml +19 -8
- package/Cargo.toml +18 -2
- package/README.md +80 -33
- package/docs/CHANGELOG.md +56 -0
- package/docs/ROADMAP.md +6 -3
- package/examples/index.deva +52 -35
- package/out-tsc/bin/index.d.ts +2 -0
- package/out-tsc/core/functions/index.d.ts +37 -0
- package/out-tsc/core/functions/index.js +76 -0
- package/out-tsc/core/index.d.ts +6 -0
- package/out-tsc/core/index.js +22 -0
- package/out-tsc/core/types/index.d.ts +4 -0
- package/out-tsc/core/types/index.js +20 -0
- package/out-tsc/core/types/plugin.d.ts +18 -0
- package/out-tsc/core/types/plugin.js +2 -0
- package/out-tsc/core/types/result.d.ts +27 -0
- package/out-tsc/core/types/result.js +2 -0
- package/out-tsc/core/types/statement.d.ts +106 -0
- package/out-tsc/core/types/statement.js +2 -0
- package/out-tsc/core/types/value.d.ts +43 -0
- package/out-tsc/core/types/value.js +2 -0
- package/out-tsc/index.d.ts +7 -0
- package/out-tsc/index.js +41 -2
- package/out-tsc/pkg/devalang_core.d.ts +7 -0
- package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +33 -0
- package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
- package/out-tsc/scripts/copy-wasm-dts.js +73 -0
- package/out-tsc/scripts/postinstall.d.ts +1 -0
- package/out-tsc/scripts/postinstall.js +33 -23
- package/out-tsc/scripts/version/bump.d.ts +1 -0
- package/out-tsc/scripts/version/fetch.d.ts +1 -0
- package/out-tsc/scripts/version/index.d.ts +1 -0
- package/out-tsc/scripts/version/sync.d.ts +1 -0
- package/package.json +16 -4
- package/project-version.json +3 -3
- package/rust/cli/bank/api.rs +122 -0
- package/rust/cli/bank/commands.rs +275 -0
- package/rust/cli/bank/mod.rs +29 -0
- package/rust/cli/build/commands.rs +97 -0
- package/rust/cli/build/mod.rs +2 -0
- package/rust/cli/build/process.rs +146 -0
- package/rust/cli/{check.rs → check/mod.rs} +18 -31
- package/rust/cli/discover/commands.rs +253 -0
- package/rust/cli/discover/config.rs +111 -0
- package/rust/cli/discover/fs.rs +19 -0
- package/rust/cli/discover/install.rs +103 -0
- package/rust/cli/discover/metadata.rs +48 -0
- package/rust/cli/discover/mod.rs +5 -0
- package/rust/cli/{init.rs → init/commands.rs} +88 -87
- package/rust/cli/init/mod.rs +1 -0
- package/rust/{installer → cli/install}/addon.rs +5 -9
- package/rust/cli/install/bank.rs +53 -0
- package/rust/cli/{install.rs → install/commands.rs} +9 -9
- package/rust/{installer → cli/install}/mod.rs +2 -3
- package/rust/cli/install/plugin.rs +61 -0
- package/rust/cli/{login.rs → login/commands.rs} +8 -11
- package/rust/cli/login/mod.rs +1 -0
- package/rust/cli/mod.rs +2 -3
- package/rust/cli/{driver.rs → parser.rs} +19 -2
- package/rust/cli/play/commands.rs +324 -0
- package/rust/cli/play/io.rs +17 -0
- package/rust/cli/play/mod.rs +5 -0
- package/rust/cli/play/process.rs +150 -0
- package/rust/cli/play/realtime.rs +91 -0
- package/rust/cli/play/utils.rs +23 -0
- package/rust/cli/telemetry/commands.rs +22 -0
- package/rust/cli/telemetry/event_creator.rs +80 -0
- package/rust/cli/telemetry/mod.rs +3 -0
- package/rust/cli/telemetry/send.rs +51 -0
- package/rust/cli/{template.rs → template/commands.rs} +1 -1
- package/rust/cli/template/mod.rs +1 -0
- package/rust/cli/{update.rs → update/commands.rs} +6 -6
- package/rust/cli/update/mod.rs +1 -0
- package/rust/config/driver.rs +57 -72
- package/rust/config/mod.rs +1 -2
- package/rust/config/ops.rs +26 -0
- package/rust/config/settings.rs +60 -50
- package/rust/core/audio/engine/helpers.rs +146 -0
- package/rust/core/audio/engine/mod.rs +7 -0
- package/rust/core/audio/engine/sample.rs +298 -0
- package/rust/core/audio/engine/synth.rs +310 -0
- package/rust/core/audio/evaluator.rs +15 -12
- package/rust/core/audio/interpreter/arrow_call.rs +99 -24
- package/rust/core/audio/interpreter/call.rs +81 -60
- package/rust/core/audio/interpreter/condition.rs +3 -2
- package/rust/core/audio/interpreter/driver.rs +206 -151
- package/rust/core/audio/interpreter/let_.rs +1 -1
- package/rust/core/audio/interpreter/load.rs +2 -1
- package/rust/core/audio/interpreter/loop_.rs +7 -6
- package/rust/core/audio/interpreter/sleep.rs +2 -1
- package/rust/core/audio/interpreter/spawn.rs +45 -57
- package/rust/core/audio/interpreter/tempo.rs +31 -10
- package/rust/core/audio/interpreter/trigger.rs +2 -2
- package/rust/core/audio/loader/trigger.rs +4 -7
- package/rust/core/audio/player.rs +6 -0
- package/rust/core/audio/renderer.rs +5 -7
- package/rust/core/audio/special/env.rs +3 -1
- package/rust/core/audio/special/math.rs +4 -4
- package/rust/core/audio/special/modulator.rs +2 -2
- package/rust/core/builder/mod.rs +9 -3
- package/rust/core/debugger/lexer.rs +1 -1
- package/rust/core/debugger/mod.rs +6 -0
- package/rust/core/debugger/module.rs +4 -4
- package/rust/core/debugger/preprocessor.rs +1 -1
- package/rust/core/debugger/store.rs +2 -2
- package/rust/core/error/mod.rs +189 -0
- package/rust/core/lexer/handler/arrow.rs +1 -1
- package/rust/core/lexer/handler/at.rs +1 -1
- package/rust/core/lexer/handler/brace.rs +2 -2
- package/rust/core/lexer/handler/colon.rs +1 -1
- package/rust/core/lexer/handler/comment.rs +1 -1
- package/rust/core/lexer/handler/dot.rs +1 -1
- package/rust/core/lexer/handler/driver.rs +1 -1
- package/rust/core/lexer/handler/identifier.rs +1 -1
- package/rust/core/lexer/handler/mod.rs +1 -2
- package/rust/core/lexer/handler/number.rs +1 -1
- package/rust/core/lexer/handler/operator.rs +1 -1
- package/rust/core/lexer/handler/parenthesis.rs +2 -2
- package/rust/core/lexer/handler/slash.rs +1 -1
- package/rust/core/lexer/handler/string.rs +1 -1
- package/rust/core/lexer/mod.rs +22 -12
- package/rust/core/lexer/token.rs +90 -97
- package/rust/core/mod.rs +0 -1
- package/rust/core/parser/driver.rs +66 -13
- package/rust/core/parser/handler/arrow_call.rs +28 -8
- package/rust/core/parser/handler/at.rs +55 -21
- package/rust/core/parser/handler/bank.rs +14 -4
- package/rust/core/parser/handler/condition.rs +6 -3
- package/rust/core/parser/handler/dot.rs +2 -1
- package/rust/core/parser/handler/identifier/automate.rs +13 -16
- package/rust/core/parser/handler/identifier/call.rs +4 -4
- package/rust/core/parser/handler/identifier/emit.rs +9 -5
- package/rust/core/parser/handler/identifier/function.rs +20 -7
- package/rust/core/parser/handler/identifier/group.rs +11 -7
- package/rust/core/parser/handler/identifier/let_.rs +24 -9
- package/rust/core/parser/handler/identifier/mod.rs +6 -5
- package/rust/core/parser/handler/identifier/on.rs +16 -7
- package/rust/core/parser/handler/identifier/print.rs +6 -9
- package/rust/core/parser/handler/identifier/sleep.rs +12 -5
- package/rust/core/parser/handler/identifier/spawn.rs +4 -4
- package/rust/core/parser/handler/identifier/synth.rs +79 -9
- package/rust/core/parser/handler/loop_.rs +39 -14
- package/rust/core/parser/handler/tempo.rs +9 -5
- package/rust/core/parser/mod.rs +0 -1
- package/rust/core/parser/statement.rs +6 -137
- package/rust/core/plugin/loader.rs +41 -27
- package/rust/core/plugin/runner.rs +68 -17
- package/rust/core/preprocessor/loader.rs +155 -33
- package/rust/core/preprocessor/processor.rs +2 -2
- package/rust/core/preprocessor/resolver/bank.rs +6 -8
- package/rust/core/preprocessor/resolver/call.rs +20 -24
- package/rust/core/preprocessor/resolver/condition.rs +6 -8
- package/rust/core/preprocessor/resolver/driver.rs +14 -16
- package/rust/core/preprocessor/resolver/function.rs +6 -6
- package/rust/core/preprocessor/resolver/group.rs +6 -8
- package/rust/core/preprocessor/resolver/loop_.rs +8 -10
- package/rust/core/preprocessor/resolver/spawn.rs +19 -23
- package/rust/core/preprocessor/resolver/synth.rs +6 -8
- package/rust/core/preprocessor/resolver/tempo.rs +6 -8
- package/rust/core/preprocessor/resolver/trigger.rs +22 -19
- package/rust/core/preprocessor/resolver/value.rs +99 -4
- package/rust/core/store/export.rs +28 -28
- package/rust/core/store/function.rs +6 -0
- package/rust/core/store/global.rs +7 -1
- package/rust/core/store/import.rs +28 -28
- package/rust/core/store/variable.rs +1 -1
- package/rust/core/utils/mod.rs +0 -1
- package/rust/lib.rs +102 -9
- package/rust/main.rs +156 -45
- package/rust/types/Cargo.toml +8 -0
- package/rust/types/src/addons.rs +55 -0
- package/rust/types/src/ast.rs +198 -0
- package/rust/types/src/config.rs +74 -0
- package/rust/types/src/lib.rs +12 -0
- package/rust/types/src/telemetry.rs +85 -0
- package/rust/utils/Cargo.toml +23 -0
- package/rust/utils/{error.rs → src/error.rs} +186 -200
- package/rust/utils/src/file.rs +94 -0
- package/rust/utils/src/first_usage.rs +97 -0
- package/rust/utils/{mod.rs → src/lib.rs} +1 -1
- package/rust/utils/{logger.rs → src/logger.rs} +17 -12
- package/rust/utils/src/path.rs +88 -0
- package/rust/utils/src/signature.rs +41 -0
- package/rust/utils/{spinner.rs → src/spinner.rs} +3 -5
- package/rust/utils/src/version.rs +27 -0
- package/rust/utils/{watcher.rs → src/watcher.rs} +13 -1
- package/rust/web/api.rs +5 -0
- package/rust/web/cdn.rs +34 -0
- package/templates/minimal/README.md +98 -54
- package/templates/welcome/README.md +98 -54
- package/templates/welcome/src/index.deva +56 -8
- package/templates/welcome/src/variables.deva +2 -4
- package/tests/rust/TODO.md +0 -0
- package/tests/typescript/index.spec.ts +136 -0
- package/tests/typescript/playhead.spec.ts +36 -0
- package/tests/typescript/render_e2e.spec.ts +77 -0
- package/tsconfig.json +1 -1
- package/typescript/core/functions/index.ts +83 -0
- package/typescript/core/index.ts +6 -0
- package/typescript/core/types/index.ts +4 -0
- package/typescript/core/types/plugin.ts +19 -0
- package/typescript/core/types/result.ts +29 -0
- package/typescript/core/types/statement.ts +47 -0
- package/typescript/core/types/value.ts +29 -0
- package/typescript/index.ts +7 -2
- package/typescript/pkg/devalang_core.d.ts +4 -0
- package/typescript/scripts/copy-wasm-dts.ts +41 -0
- package/typescript/scripts/postinstall.ts +45 -32
- package/rust/cli/bank.rs +0 -462
- package/rust/cli/build.rs +0 -252
- package/rust/cli/generator.rs +0 -1
- package/rust/cli/play.rs +0 -1123
- package/rust/cli/telemetry.rs +0 -19
- package/rust/common/api.rs +0 -5
- package/rust/common/cdn.rs +0 -5
- package/rust/config/loader.rs +0 -165
- package/rust/config/stats.rs +0 -257
- package/rust/core/audio/engine.rs +0 -696
- package/rust/core/shared/bank.rs +0 -21
- package/rust/core/shared/duration.rs +0 -9
- package/rust/core/shared/mod.rs +0 -3
- package/rust/core/shared/value.rs +0 -35
- package/rust/core/utils/validation.rs +0 -35
- package/rust/installer/bank.rs +0 -62
- package/rust/installer/plugin.rs +0 -54
- package/rust/installer/utils.rs +0 -56
- package/rust/utils/file.rs +0 -38
- package/rust/utils/first_usage.rs +0 -76
- package/rust/utils/signature.rs +0 -19
- package/rust/utils/telemetry.rs +0 -292
- package/rust/utils/version.rs +0 -15
- /package/rust/{common → web}/mod.rs +0 -0
- /package/rust/{common → web}/sso.rs +0 -0
|
@@ -1,19 +1,10 @@
|
|
|
1
|
+
use devalang_types::{PluginExport, PluginInfo as SharedPluginInfo};
|
|
2
|
+
use devalang_utils::path as path_utils;
|
|
1
3
|
use serde::Deserialize;
|
|
2
|
-
use std::path::Path;
|
|
3
4
|
use toml::Value as TomlValue;
|
|
4
5
|
|
|
5
6
|
#[derive(Debug, Deserialize, Clone)]
|
|
6
|
-
|
|
7
|
-
pub name: String,
|
|
8
|
-
pub version: Option<String>,
|
|
9
|
-
pub description: Option<String>,
|
|
10
|
-
pub author: Option<String>,
|
|
11
|
-
#[serde(skip)]
|
|
12
|
-
pub exports: Vec<ExportEntry>,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
#[derive(Debug, Deserialize, Clone)]
|
|
16
|
-
pub struct ExportEntry {
|
|
7
|
+
struct LocalExportEntry {
|
|
17
8
|
pub name: String,
|
|
18
9
|
#[serde(rename = "type")]
|
|
19
10
|
pub kind: String,
|
|
@@ -22,24 +13,29 @@ pub struct ExportEntry {
|
|
|
22
13
|
}
|
|
23
14
|
|
|
24
15
|
#[derive(Debug, Deserialize, Clone)]
|
|
25
|
-
|
|
26
|
-
pub plugin:
|
|
16
|
+
struct LocalPluginFile {
|
|
17
|
+
pub plugin: LocalPluginInfo,
|
|
27
18
|
#[serde(default)]
|
|
28
|
-
pub export: Vec<
|
|
19
|
+
pub export: Vec<LocalExportEntry>,
|
|
29
20
|
}
|
|
30
21
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
#[derive(Debug, Deserialize, Clone)]
|
|
23
|
+
struct LocalPluginInfo {
|
|
24
|
+
pub name: String,
|
|
25
|
+
pub version: Option<String>,
|
|
26
|
+
pub description: Option<String>,
|
|
27
|
+
pub author: Option<String>,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
pub fn load_plugin(author: &str, name: &str) -> Result<(SharedPluginInfo, Vec<u8>), String> {
|
|
31
|
+
let root = path_utils::get_deva_dir()?;
|
|
32
|
+
let plugin_dir_preferred = root.join("plugins").join(format!("{}.{}", author, name));
|
|
37
33
|
let toml_path_preferred = plugin_dir_preferred.join("plugin.toml");
|
|
38
34
|
let wasm_path_preferred_bg = plugin_dir_preferred.join(format!("{}_bg.wasm", name));
|
|
39
35
|
let wasm_path_preferred_plain = plugin_dir_preferred.join(format!("{}.wasm", name));
|
|
40
36
|
|
|
41
37
|
// Legacy layout (fallback): ./.deva/plugin/<author>/<name>/
|
|
42
|
-
let plugin_dir_fallback = root.join("
|
|
38
|
+
let plugin_dir_fallback = root.join("plugins").join(author).join(name);
|
|
43
39
|
let toml_path_fallback = plugin_dir_fallback.join("plugin.toml");
|
|
44
40
|
let wasm_path_fallback_bg = plugin_dir_fallback.join(format!("{}_bg.wasm", name));
|
|
45
41
|
let wasm_path_fallback_plain = plugin_dir_fallback.join(format!("{}.wasm", name));
|
|
@@ -74,20 +70,38 @@ pub fn load_plugin(author: &str, name: &str) -> Result<(PluginInfo, Vec<u8>), St
|
|
|
74
70
|
|
|
75
71
|
let toml_content = std::fs::read_to_string(&toml_path)
|
|
76
72
|
.map_err(|e| format!("Failed to read '{}': {}", toml_path.display(), e))?;
|
|
77
|
-
let plugin_file:
|
|
73
|
+
let plugin_file: LocalPluginFile = toml::from_str(&toml_content)
|
|
78
74
|
.map_err(|e| format!("Failed to parse '{}': {}", toml_path.display(), e))?;
|
|
79
75
|
|
|
80
76
|
let wasm_bytes = std::fs::read(&wasm_path)
|
|
81
77
|
.map_err(|e| format!("Failed to read '{}': {}", wasm_path.display(), e))?;
|
|
82
78
|
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
// Map local parsed plugin info to shared PluginInfo
|
|
80
|
+
let mut exports: Vec<PluginExport> = Vec::new();
|
|
81
|
+
for e in plugin_file.export.iter() {
|
|
82
|
+
exports.push(PluginExport {
|
|
83
|
+
name: e.name.clone(),
|
|
84
|
+
kind: e.kind.clone(),
|
|
85
|
+
default: e.default.clone(),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let info = SharedPluginInfo {
|
|
90
|
+
author: plugin_file
|
|
91
|
+
.plugin
|
|
92
|
+
.author
|
|
93
|
+
.unwrap_or_else(|| author.to_string()),
|
|
94
|
+
name: plugin_file.plugin.name.clone(),
|
|
95
|
+
version: plugin_file.plugin.version.clone(),
|
|
96
|
+
description: plugin_file.plugin.description.clone(),
|
|
97
|
+
exports,
|
|
98
|
+
};
|
|
85
99
|
|
|
86
100
|
Ok((info, wasm_bytes))
|
|
87
101
|
}
|
|
88
102
|
|
|
89
103
|
/// Load a plugin from dot notation: "author.name"
|
|
90
|
-
pub fn load_plugin_from_dot(dot: &str) -> Result<(
|
|
104
|
+
pub fn load_plugin_from_dot(dot: &str) -> Result<(SharedPluginInfo, Vec<u8>), String> {
|
|
91
105
|
let mut parts = dot.split('.');
|
|
92
106
|
let author = parts
|
|
93
107
|
.next()
|
|
@@ -101,7 +115,7 @@ pub fn load_plugin_from_dot(dot: &str) -> Result<(PluginInfo, Vec<u8>), String>
|
|
|
101
115
|
load_plugin(author, name)
|
|
102
116
|
}
|
|
103
117
|
|
|
104
|
-
pub fn load_plugin_from_uri(uri: &str) -> Result<(
|
|
118
|
+
pub fn load_plugin_from_uri(uri: &str) -> Result<(SharedPluginInfo, Vec<u8>), String> {
|
|
105
119
|
if !uri.starts_with("devalang://plugin/") {
|
|
106
120
|
return Err("Invalid plugin URI".into());
|
|
107
121
|
}
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
2
4
|
use wasmtime::{Engine, Instance, Linker, Module, Store, TypedFunc};
|
|
3
5
|
|
|
6
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
7
|
+
type RenderFunc = TypedFunc<(i32, i32, f32, f32, i32, i32, i32), ()>;
|
|
8
|
+
|
|
9
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
4
10
|
pub struct WasmPluginRunner {
|
|
5
11
|
engine: Engine,
|
|
6
12
|
}
|
|
7
13
|
|
|
14
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
15
|
+
impl Default for WasmPluginRunner {
|
|
16
|
+
fn default() -> Self {
|
|
17
|
+
Self::new()
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#[cfg(not(target_arch = "wasm32"))]
|
|
8
22
|
impl WasmPluginRunner {
|
|
9
23
|
pub fn new() -> Self {
|
|
10
24
|
let engine = Engine::default();
|
|
@@ -18,38 +32,32 @@ impl WasmPluginRunner {
|
|
|
18
32
|
let mut store = Store::new(&self.engine, ());
|
|
19
33
|
let linker = Linker::new(&self.engine);
|
|
20
34
|
|
|
21
|
-
// Instantiate
|
|
22
35
|
let instance = linker
|
|
23
36
|
.instantiate(&mut store, &module)
|
|
24
37
|
.map_err(|e| format!("Failed to instantiate wasm: {e}"))?;
|
|
25
38
|
|
|
26
|
-
// Get exports
|
|
27
39
|
let memory = instance
|
|
28
40
|
.get_memory(&mut store, "memory")
|
|
29
41
|
.ok_or_else(|| "WASM memory export not found".to_string())?;
|
|
30
42
|
|
|
31
|
-
// wasm-bindgen usually exports a function taking (ptr: i32, len: i32) to represent &mut [f32]
|
|
32
43
|
let func = instance
|
|
33
44
|
.get_typed_func::<(i32, i32), ()>(&mut store, "process")
|
|
34
45
|
.map_err(|_| "Exported function `process(i32,i32)` not found".to_string())?;
|
|
35
46
|
|
|
36
|
-
|
|
37
|
-
let byte_len = (buffer.len() * std::mem::size_of::<f32>()) as i32;
|
|
47
|
+
let byte_len = std::mem::size_of_val(buffer) as i32;
|
|
38
48
|
let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
|
|
39
49
|
let mem_slice = memory
|
|
40
50
|
.data_mut(&mut store)
|
|
41
51
|
.get_mut(ptr as usize..(ptr as usize) + (byte_len as usize))
|
|
42
52
|
.ok_or_else(|| "Failed to get memory slice".to_string())?;
|
|
43
|
-
|
|
53
|
+
|
|
44
54
|
let src_bytes =
|
|
45
55
|
unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const u8, byte_len as usize) };
|
|
46
56
|
mem_slice.copy_from_slice(src_bytes);
|
|
47
57
|
|
|
48
|
-
// Call process
|
|
49
58
|
func.call(&mut store, (ptr, buffer.len() as i32))
|
|
50
59
|
.map_err(|e| format!("Error calling `process`: {e}"))?;
|
|
51
60
|
|
|
52
|
-
// Copy back
|
|
53
61
|
let mem_slice_after = memory
|
|
54
62
|
.data(&store)
|
|
55
63
|
.get(ptr as usize..(ptr as usize) + (byte_len as usize))
|
|
@@ -62,8 +70,6 @@ impl WasmPluginRunner {
|
|
|
62
70
|
Ok(())
|
|
63
71
|
}
|
|
64
72
|
|
|
65
|
-
/// Render a note by invoking either `render_note_<name>` or a generic `render_note(ptr,len,freq,amp,duration_ms,sample_rate,channels)`.
|
|
66
|
-
/// The buffer is interleaved stereo if channels=2. The buffer is modified in place.
|
|
67
73
|
pub fn render_note_in_place(
|
|
68
74
|
&self,
|
|
69
75
|
wasm_bytes: &[u8],
|
|
@@ -90,7 +96,7 @@ impl WasmPluginRunner {
|
|
|
90
96
|
.ok_or_else(|| "WASM memory export not found".to_string())?;
|
|
91
97
|
|
|
92
98
|
// Try specific function first
|
|
93
|
-
let mut func_opt: Option<
|
|
99
|
+
let mut func_opt: Option<RenderFunc> = None;
|
|
94
100
|
if let Some(name) = synth_name {
|
|
95
101
|
let specific = format!("render_note_{}", name);
|
|
96
102
|
if let Ok(f) = instance
|
|
@@ -113,7 +119,7 @@ impl WasmPluginRunner {
|
|
|
113
119
|
func_opt.ok_or_else(|| "Exported function `render_note` not found".to_string())?;
|
|
114
120
|
|
|
115
121
|
// Copy host buffer into wasm memory
|
|
116
|
-
let byte_len =
|
|
122
|
+
let byte_len = std::mem::size_of_val(buffer) as i32;
|
|
117
123
|
let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
|
|
118
124
|
let mem_slice = memory
|
|
119
125
|
.data_mut(&mut store)
|
|
@@ -207,7 +213,7 @@ impl WasmPluginRunner {
|
|
|
207
213
|
}
|
|
208
214
|
|
|
209
215
|
// Try specific or generic render function
|
|
210
|
-
let mut func_opt: Option<
|
|
216
|
+
let mut func_opt: Option<RenderFunc> = None;
|
|
211
217
|
if let Some(name) = synth_name {
|
|
212
218
|
let specific = format!("render_note_{}", name);
|
|
213
219
|
if let Ok(f) = instance
|
|
@@ -228,7 +234,7 @@ impl WasmPluginRunner {
|
|
|
228
234
|
func_opt.ok_or_else(|| "Exported function `render_note` not found".to_string())?;
|
|
229
235
|
|
|
230
236
|
// Copy host buffer into wasm memory
|
|
231
|
-
let byte_len =
|
|
237
|
+
let byte_len = std::mem::size_of_val(buffer) as i32;
|
|
232
238
|
let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
|
|
233
239
|
let mem_slice = memory
|
|
234
240
|
.data_mut(&mut store)
|
|
@@ -283,10 +289,10 @@ impl WasmPluginRunner {
|
|
|
283
289
|
// Fallback: grow memory and use end of memory as scratch space
|
|
284
290
|
let current_len = memory.data_size(&mut *store);
|
|
285
291
|
let need = size;
|
|
286
|
-
let pages_needed = (
|
|
292
|
+
let pages_needed = (current_len + need).div_ceil(0x10000) as u64; // 64KiB pages
|
|
287
293
|
let current_pages = memory.size(&mut *store);
|
|
288
|
-
if pages_needed >
|
|
289
|
-
let to_grow = pages_needed -
|
|
294
|
+
if pages_needed > current_pages {
|
|
295
|
+
let to_grow = pages_needed - current_pages;
|
|
290
296
|
memory
|
|
291
297
|
.grow(&mut *store, to_grow)
|
|
292
298
|
.map_err(|e| format!("memory.grow failed: {e}"))?;
|
|
@@ -294,3 +300,48 @@ impl WasmPluginRunner {
|
|
|
294
300
|
Ok(current_len)
|
|
295
301
|
}
|
|
296
302
|
}
|
|
303
|
+
|
|
304
|
+
// Provide a minimal stub for wasm32 target so the crate compiles there.
|
|
305
|
+
#[cfg(target_arch = "wasm32")]
|
|
306
|
+
pub struct WasmPluginRunner;
|
|
307
|
+
|
|
308
|
+
#[cfg(target_arch = "wasm32")]
|
|
309
|
+
impl WasmPluginRunner {
|
|
310
|
+
pub fn new() -> Self {
|
|
311
|
+
WasmPluginRunner
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
pub fn process_in_place(&self, _wasm_bytes: &[u8], _buffer: &mut [f32]) -> Result<(), String> {
|
|
315
|
+
Err("Wasm plugin execution is not available in wasm builds".to_string())
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
pub fn render_note_in_place(
|
|
319
|
+
&self,
|
|
320
|
+
_wasm_bytes: &[u8],
|
|
321
|
+
_buffer: &mut [f32],
|
|
322
|
+
_synth_name: Option<&str>,
|
|
323
|
+
_freq: f32,
|
|
324
|
+
_amp: f32,
|
|
325
|
+
_duration_ms: i32,
|
|
326
|
+
_sample_rate: i32,
|
|
327
|
+
_channels: i32,
|
|
328
|
+
) -> Result<(), String> {
|
|
329
|
+
Err("Wasm plugin rendering is not available in wasm builds".to_string())
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
pub fn render_note_with_params_in_place(
|
|
333
|
+
&self,
|
|
334
|
+
_wasm_bytes: &[u8],
|
|
335
|
+
_buffer: &mut [f32],
|
|
336
|
+
_synth_name: Option<&str>,
|
|
337
|
+
_freq: f32,
|
|
338
|
+
_amp: f32,
|
|
339
|
+
_duration_ms: i32,
|
|
340
|
+
_sample_rate: i32,
|
|
341
|
+
_channels: i32,
|
|
342
|
+
_params_num: &HashMap<String, f32>,
|
|
343
|
+
_params_str: Option<&HashMap<String, String>>,
|
|
344
|
+
) -> Result<(), String> {
|
|
345
|
+
Err("Wasm plugin rendering is not available in wasm builds".to_string())
|
|
346
|
+
}
|
|
347
|
+
}
|
|
@@ -1,24 +1,25 @@
|
|
|
1
|
+
#[cfg(feature = "cli")]
|
|
1
2
|
use crate::core::preprocessor::resolver::driver::{
|
|
2
3
|
resolve_all_modules, resolve_and_flatten_all_modules,
|
|
3
4
|
};
|
|
5
|
+
#[cfg(feature = "cli")]
|
|
4
6
|
use crate::core::utils::path::resolve_relative_path;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
statement::{Statement, StatementKind},
|
|
13
|
-
},
|
|
14
|
-
plugin::loader::load_plugin,
|
|
15
|
-
preprocessor::{module::Module, processor::process_modules},
|
|
16
|
-
shared::{bank::BankFile, value::Value},
|
|
17
|
-
store::global::GlobalStore,
|
|
18
|
-
utils::path::normalize_path,
|
|
7
|
+
#[cfg_attr(not(feature = "cli"), allow(unused_imports))]
|
|
8
|
+
use crate::core::{
|
|
9
|
+
error::ErrorHandler,
|
|
10
|
+
lexer::{Lexer, token::Token},
|
|
11
|
+
parser::{
|
|
12
|
+
driver::Parser,
|
|
13
|
+
statement::{Statement, StatementKind},
|
|
19
14
|
},
|
|
20
|
-
|
|
15
|
+
plugin::loader::load_plugin,
|
|
16
|
+
preprocessor::{module::Module, processor::process_modules},
|
|
17
|
+
store::global::GlobalStore,
|
|
18
|
+
utils::path::normalize_path,
|
|
21
19
|
};
|
|
20
|
+
use devalang_types::{BankFile, Value};
|
|
21
|
+
#[cfg(feature = "cli")]
|
|
22
|
+
use devalang_utils::logger::{LogLevel, Logger};
|
|
22
23
|
use std::{collections::HashMap, path::Path};
|
|
23
24
|
|
|
24
25
|
pub struct ModuleLoader {
|
|
@@ -38,7 +39,7 @@ impl ModuleLoader {
|
|
|
38
39
|
Self {
|
|
39
40
|
entry: entry.to_string(),
|
|
40
41
|
output: output.to_string(),
|
|
41
|
-
base_dir
|
|
42
|
+
base_dir,
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
|
|
@@ -50,9 +51,12 @@ impl ModuleLoader {
|
|
|
50
51
|
) -> Self {
|
|
51
52
|
let normalized_entry_path = normalize_path(entry_path);
|
|
52
53
|
|
|
53
|
-
let mut module = Module::new(
|
|
54
|
+
let mut module = Module::new(entry_path);
|
|
54
55
|
module.content = content.to_string();
|
|
55
56
|
|
|
57
|
+
// Insert a module stub containing the provided content into the
|
|
58
|
+
// global store. This is used by the WASM APIs and tests which
|
|
59
|
+
// operate on in-memory sources instead of files on disk.
|
|
56
60
|
global_store.insert_module(normalized_entry_path.to_string(), module);
|
|
57
61
|
|
|
58
62
|
Self {
|
|
@@ -145,6 +149,17 @@ impl ModuleLoader {
|
|
|
145
149
|
return Err(format!("Failed to inject bank triggers: {}", e));
|
|
146
150
|
}
|
|
147
151
|
|
|
152
|
+
// Insert the updated module into the global store before processing so
|
|
153
|
+
// process_modules can operate on it and populate variable_table, imports,
|
|
154
|
+
// and other derived structures.
|
|
155
|
+
global_store
|
|
156
|
+
.modules
|
|
157
|
+
.insert(self.entry.clone(), updated_module.clone());
|
|
158
|
+
|
|
159
|
+
// Process modules to populate module.variable_table, import/export tables,
|
|
160
|
+
// and other derived structures so runtime execution can resolve groups/synths.
|
|
161
|
+
process_modules(self, global_store);
|
|
162
|
+
|
|
148
163
|
for (plugin_name, alias) in self.extract_plugin_uses(&updated_module.statements) {
|
|
149
164
|
self.load_plugin_and_register(&mut updated_module, &plugin_name, &alias, global_store);
|
|
150
165
|
}
|
|
@@ -153,10 +168,32 @@ impl ModuleLoader {
|
|
|
153
168
|
let mut error_handler = ErrorHandler::new();
|
|
154
169
|
error_handler.detect_from_statements(&mut parser, &updated_module.statements);
|
|
155
170
|
|
|
156
|
-
// Final step :
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
171
|
+
// Final step : also expose module-level variables and functions into the global store
|
|
172
|
+
// so runtime evaluation (render_audio) can find group/synth definitions.
|
|
173
|
+
// Use the module instance that was actually processed by `process_modules`
|
|
174
|
+
// (it lives in `global_store.modules`) because `updated_module` is a local
|
|
175
|
+
// clone and won't contain the mutations applied by `process_modules`.
|
|
176
|
+
if let Some(stored_module) = global_store.modules.get(&self.entry) {
|
|
177
|
+
global_store
|
|
178
|
+
.variables
|
|
179
|
+
.variables
|
|
180
|
+
.extend(stored_module.variable_table.variables.clone());
|
|
181
|
+
global_store
|
|
182
|
+
.functions
|
|
183
|
+
.functions
|
|
184
|
+
.extend(stored_module.function_table.functions.clone());
|
|
185
|
+
} else {
|
|
186
|
+
// Fallback to the local updated_module if for any reason the module
|
|
187
|
+
// wasn't inserted into the store (defensive programming).
|
|
188
|
+
global_store
|
|
189
|
+
.variables
|
|
190
|
+
.variables
|
|
191
|
+
.extend(updated_module.variable_table.variables.clone());
|
|
192
|
+
global_store
|
|
193
|
+
.functions
|
|
194
|
+
.functions
|
|
195
|
+
.extend(updated_module.function_table.functions.clone());
|
|
196
|
+
}
|
|
160
197
|
|
|
161
198
|
Ok(())
|
|
162
199
|
}
|
|
@@ -193,7 +230,14 @@ impl ModuleLoader {
|
|
|
193
230
|
}
|
|
194
231
|
|
|
195
232
|
let lexer = Lexer::new();
|
|
196
|
-
let tokens = lexer.lex_tokens(&path)
|
|
233
|
+
let tokens = match lexer.lex_tokens(&path) {
|
|
234
|
+
Ok(t) => t,
|
|
235
|
+
Err(e) => {
|
|
236
|
+
let logger = Logger::new();
|
|
237
|
+
logger.log_message(LogLevel::Error, &format!("Failed to lex '{}': {}", path, e));
|
|
238
|
+
return HashMap::new();
|
|
239
|
+
}
|
|
240
|
+
};
|
|
197
241
|
|
|
198
242
|
let mut parser = Parser::new();
|
|
199
243
|
parser.set_current_module(path.clone());
|
|
@@ -295,10 +339,17 @@ impl ModuleLoader {
|
|
|
295
339
|
bank_name: &str,
|
|
296
340
|
alias_override: Option<String>,
|
|
297
341
|
) -> Result<Module, String> {
|
|
298
|
-
let default_alias = bank_name
|
|
342
|
+
let default_alias = bank_name
|
|
343
|
+
.split('.')
|
|
344
|
+
.next_back()
|
|
345
|
+
.unwrap_or(bank_name)
|
|
346
|
+
.to_string();
|
|
299
347
|
let alias_ref = alias_override.as_deref().unwrap_or(&default_alias);
|
|
300
348
|
|
|
301
|
-
let bank_path =
|
|
349
|
+
let bank_path = match devalang_utils::path::get_deva_dir() {
|
|
350
|
+
Ok(dir) => dir.join("banks").join(bank_name),
|
|
351
|
+
Err(_) => Path::new("./.deva").join("banks").join(bank_name),
|
|
352
|
+
};
|
|
302
353
|
let bank_toml_path = bank_path.join("bank.toml");
|
|
303
354
|
|
|
304
355
|
if !bank_toml_path.exists() {
|
|
@@ -314,9 +365,18 @@ impl ModuleLoader {
|
|
|
314
365
|
let mut bank_map = HashMap::new();
|
|
315
366
|
|
|
316
367
|
for bank_trigger in parsed_bankfile.triggers.unwrap_or_default() {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
368
|
+
// Use the configured path from the bank file as the entity reference so
|
|
369
|
+
// that bank entries can point to files or nested paths. Clean common
|
|
370
|
+
// local prefixes like "./" to keep the URI tidy.
|
|
371
|
+
let entity_ref = bank_trigger
|
|
372
|
+
.path
|
|
373
|
+
.clone()
|
|
374
|
+
.replace("\\", "/")
|
|
375
|
+
.replace("./", "");
|
|
376
|
+
let bank_trigger_path = format!("devalang://bank/{}/{}", bank_name, entity_ref);
|
|
377
|
+
|
|
378
|
+
// Keep the trigger key as declared (bank_trigger.name) but expose its
|
|
379
|
+
// value as a devalang://bank URI pointing to the configured path.
|
|
320
380
|
bank_map.insert(
|
|
321
381
|
bank_trigger.name.clone(),
|
|
322
382
|
Value::String(bank_trigger_path.clone()),
|
|
@@ -344,6 +404,7 @@ impl ModuleLoader {
|
|
|
344
404
|
Ok(module.clone())
|
|
345
405
|
}
|
|
346
406
|
|
|
407
|
+
#[cfg_attr(not(feature = "cli"), allow(dead_code))]
|
|
347
408
|
fn extract_bank_decls(&self, statements: &[Statement]) -> Vec<(String, Option<String>)> {
|
|
348
409
|
let mut banks = Vec::new();
|
|
349
410
|
|
|
@@ -371,7 +432,7 @@ impl ModuleLoader {
|
|
|
371
432
|
if let StatementKind::Use { name, alias } = &stmt.kind {
|
|
372
433
|
let alias_name = alias
|
|
373
434
|
.clone()
|
|
374
|
-
.unwrap_or_else(|| name.split('.').
|
|
435
|
+
.unwrap_or_else(|| name.split('.').next_back().unwrap_or(name).to_string());
|
|
375
436
|
plugins.push((name.clone(), alias_name));
|
|
376
437
|
}
|
|
377
438
|
}
|
|
@@ -415,16 +476,19 @@ impl ModuleLoader {
|
|
|
415
476
|
let expected_uri = format!("devalang://plugin/{}.{}", author, name);
|
|
416
477
|
|
|
417
478
|
// Detect local presence (preferred and legacy layouts)
|
|
418
|
-
let root =
|
|
419
|
-
|
|
479
|
+
let root = match devalang_utils::path::get_deva_dir() {
|
|
480
|
+
Ok(dir) => dir,
|
|
481
|
+
Err(_) => Path::new("./.deva").to_path_buf(),
|
|
482
|
+
};
|
|
483
|
+
let plugin_dir_preferred = root.join("plugins").join(format!("{}.{}", author, name));
|
|
420
484
|
let toml_path_preferred = plugin_dir_preferred.join("plugin.toml");
|
|
421
|
-
let plugin_dir_fallback = root.join("
|
|
485
|
+
let plugin_dir_fallback = root.join("plugins").join(author).join(name);
|
|
422
486
|
let toml_path_fallback = plugin_dir_fallback.join("plugin.toml");
|
|
423
487
|
let exists_locally = toml_path_preferred.exists() || toml_path_fallback.exists();
|
|
424
488
|
|
|
425
489
|
if exists_locally {
|
|
426
490
|
// Load config and verify plugin is declared
|
|
427
|
-
let cfg_opt = load_config(None);
|
|
491
|
+
let cfg_opt = crate::config::ops::load_config(None);
|
|
428
492
|
let mut declared = false;
|
|
429
493
|
if let Some(cfg) = cfg_opt {
|
|
430
494
|
if let Some(list) = cfg.plugins {
|
|
@@ -457,6 +521,11 @@ impl ModuleLoader {
|
|
|
457
521
|
module
|
|
458
522
|
.variable_table
|
|
459
523
|
.set(alias.to_string(), Value::String(uri.clone()));
|
|
524
|
+
// Also expose alias at global level so runtime can resolve it
|
|
525
|
+
global_store
|
|
526
|
+
.variables
|
|
527
|
+
.set(alias.to_string(), Value::String(uri.clone()));
|
|
528
|
+
|
|
460
529
|
if let Some((plugin_info, _)) =
|
|
461
530
|
global_store.plugins.get(&format!("{}:{}", author, name))
|
|
462
531
|
{
|
|
@@ -504,7 +573,60 @@ impl ModuleLoader {
|
|
|
504
573
|
Value::String(format!("{}.{}", alias, exp.name)),
|
|
505
574
|
);
|
|
506
575
|
}
|
|
507
|
-
_ => {
|
|
576
|
+
_ => {
|
|
577
|
+
// Fallback: if default is present, map it to a Value dynamically
|
|
578
|
+
if let Some(def) = &exp.default {
|
|
579
|
+
let val = match def {
|
|
580
|
+
toml::Value::String(s) => Value::String(s.clone()),
|
|
581
|
+
toml::Value::Integer(i) => Value::Number(*i as f32),
|
|
582
|
+
toml::Value::Float(f) => Value::Number(*f as f32),
|
|
583
|
+
toml::Value::Boolean(b) => Value::Boolean(*b),
|
|
584
|
+
toml::Value::Array(arr) => Value::Array(
|
|
585
|
+
arr.iter()
|
|
586
|
+
.map(|v| match v {
|
|
587
|
+
toml::Value::String(s) => {
|
|
588
|
+
Value::String(s.clone())
|
|
589
|
+
}
|
|
590
|
+
toml::Value::Integer(i) => {
|
|
591
|
+
Value::Number(*i as f32)
|
|
592
|
+
}
|
|
593
|
+
toml::Value::Float(f) => {
|
|
594
|
+
Value::Number(*f as f32)
|
|
595
|
+
}
|
|
596
|
+
toml::Value::Boolean(b) => Value::Boolean(*b),
|
|
597
|
+
_ => Value::Null,
|
|
598
|
+
})
|
|
599
|
+
.collect(),
|
|
600
|
+
),
|
|
601
|
+
toml::Value::Table(t) => {
|
|
602
|
+
let mut m = std::collections::HashMap::new();
|
|
603
|
+
for (k, v) in t.iter() {
|
|
604
|
+
let vv = match v {
|
|
605
|
+
toml::Value::String(s) => {
|
|
606
|
+
Value::String(s.clone())
|
|
607
|
+
}
|
|
608
|
+
toml::Value::Integer(i) => {
|
|
609
|
+
Value::Number(*i as f32)
|
|
610
|
+
}
|
|
611
|
+
toml::Value::Float(f) => {
|
|
612
|
+
Value::Number(*f as f32)
|
|
613
|
+
}
|
|
614
|
+
toml::Value::Boolean(b) => Value::Boolean(*b),
|
|
615
|
+
_ => Value::Null,
|
|
616
|
+
};
|
|
617
|
+
m.insert(k.clone(), vv);
|
|
618
|
+
}
|
|
619
|
+
Value::Map(m)
|
|
620
|
+
}
|
|
621
|
+
_ => Value::Null,
|
|
622
|
+
};
|
|
623
|
+
if val != Value::Null {
|
|
624
|
+
module
|
|
625
|
+
.variable_table
|
|
626
|
+
.set(format!("{}.{}", alias, exp.name), val);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
508
630
|
}
|
|
509
631
|
}
|
|
510
632
|
}
|
|
@@ -3,10 +3,10 @@ use std::{collections::HashMap, path::Path};
|
|
|
3
3
|
use crate::core::{
|
|
4
4
|
parser::statement::StatementKind,
|
|
5
5
|
preprocessor::loader::ModuleLoader,
|
|
6
|
-
shared::value::Value,
|
|
7
6
|
store::global::GlobalStore,
|
|
8
7
|
utils::path::{normalize_path, resolve_relative_path},
|
|
9
8
|
};
|
|
9
|
+
use devalang_types::Value;
|
|
10
10
|
|
|
11
11
|
pub fn process_modules(_module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
12
12
|
for module in global_store.modules.values_mut() {
|
|
@@ -46,7 +46,7 @@ pub fn process_modules(_module_loader: &ModuleLoader, global_store: &mut GlobalS
|
|
|
46
46
|
StatementKind::Load { source, alias } => {
|
|
47
47
|
let module_dir = Path::new(&module.path).parent().unwrap_or(Path::new(""));
|
|
48
48
|
|
|
49
|
-
let resolved_path = normalize_path(
|
|
49
|
+
let resolved_path = normalize_path(module_dir.join(source));
|
|
50
50
|
|
|
51
51
|
module
|
|
52
52
|
.variable_table
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
use crate::{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
shared::value::Value,
|
|
6
|
-
store::global::GlobalStore,
|
|
7
|
-
},
|
|
8
|
-
utils::logger::Logger,
|
|
1
|
+
use crate::core::{
|
|
2
|
+
parser::statement::{Statement, StatementKind},
|
|
3
|
+
preprocessor::module::Module,
|
|
4
|
+
store::global::GlobalStore,
|
|
9
5
|
};
|
|
6
|
+
use devalang_types::Value;
|
|
7
|
+
use devalang_utils::logger::Logger;
|
|
10
8
|
|
|
11
9
|
pub fn resolve_bank(
|
|
12
10
|
stmt: &Statement,
|