@devaloop/devalang 0.0.1-alpha.9 → 0.0.1-beta.2
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 -1
- package/.github/workflows/ci.yml +103 -0
- package/Cargo.toml +81 -48
- package/README.md +137 -154
- package/docs/CHANGELOG.md +428 -1
- package/docs/CONTRIBUTING.md +101 -0
- package/docs/ROADMAP.md +14 -7
- package/docs/TODO.md +16 -15
- package/examples/automation.deva +42 -0
- package/examples/bank.deva +7 -0
- package/examples/bus.deva +10 -0
- package/examples/duration.deva +9 -0
- package/examples/effect.deva +2 -0
- package/examples/events.deva +12 -0
- package/examples/filter.deva +11 -0
- package/examples/function.deva +15 -0
- package/examples/index.deva +57 -12
- package/examples/lfo.deva +9 -0
- package/examples/loop.deva +5 -12
- package/examples/pattern.deva +8 -0
- package/examples/plugin.deva +16 -0
- package/examples/synth.deva +11 -1
- package/examples/synth_types.deva +17 -0
- package/examples/variables.deva +1 -1
- package/out-tsc/bin/index.d.ts +2 -0
- package/out-tsc/bin/index.js +51 -7
- package/out-tsc/core/functions/index.d.ts +42 -0
- package/out-tsc/core/functions/index.js +87 -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 +42 -1
- package/out-tsc/pkg/devalang_core.d.ts +15 -0
- package/out-tsc/pkg/devalang_core.js +65 -0
- package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +34 -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 +83 -0
- 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 +28 -7
- package/project-version.json +4 -4
- package/rust/cli/bank/api.rs +122 -0
- package/rust/cli/bank/commands.rs +306 -0
- package/rust/cli/bank/mod.rs +29 -0
- package/rust/cli/build/commands.rs +153 -0
- package/rust/cli/build/mod.rs +2 -0
- package/rust/cli/build/process.rs +165 -0
- package/rust/cli/check/mod.rs +208 -0
- 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} +32 -23
- package/rust/cli/init/mod.rs +1 -0
- package/rust/cli/install/addon.rs +118 -0
- package/rust/cli/install/bank.rs +72 -0
- package/rust/cli/install/commands.rs +35 -0
- package/rust/cli/install/mod.rs +4 -0
- package/rust/cli/install/plugin.rs +80 -0
- package/rust/cli/login/commands.rs +124 -0
- package/rust/cli/login/mod.rs +1 -0
- package/rust/cli/mod.rs +9 -202
- package/rust/cli/parser.rs +359 -0
- package/rust/cli/play/commands.rs +375 -0
- package/rust/cli/play/io.rs +17 -0
- package/rust/cli/play/mod.rs +5 -0
- package/rust/cli/play/process.rs +159 -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} +17 -5
- package/rust/cli/template/mod.rs +1 -0
- package/rust/cli/update/commands.rs +6 -0
- package/rust/cli/update/mod.rs +1 -0
- package/rust/config/driver.rs +112 -0
- package/rust/config/mod.rs +3 -16
- package/rust/config/ops.rs +26 -0
- package/rust/config/settings.rs +101 -0
- package/rust/core/audio/engine/driver.rs +220 -0
- package/rust/core/audio/engine/export.rs +169 -0
- package/rust/core/audio/engine/helpers.rs +178 -0
- package/rust/core/audio/engine/mod.rs +56 -0
- package/rust/core/audio/engine/notes/dsp.rs +85 -0
- package/rust/core/audio/engine/notes/mod.rs +44 -0
- package/rust/core/audio/engine/notes/params.rs +294 -0
- package/rust/core/audio/engine/sample/insert.rs +199 -0
- package/rust/core/audio/engine/sample/mod.rs +40 -0
- package/rust/core/audio/engine/sample/padding.rs +170 -0
- package/rust/core/audio/evaluator/condition.rs +61 -0
- package/rust/core/audio/evaluator/mod.rs +9 -0
- package/rust/core/audio/evaluator/numeric.rs +152 -0
- package/rust/core/audio/evaluator/rhs.rs +16 -0
- package/rust/core/audio/evaluator/string_expr.rs +94 -0
- package/rust/core/audio/interpreter/driver.rs +574 -216
- package/rust/core/audio/interpreter/mod.rs +2 -12
- package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +175 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +384 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +2 -0
- package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +316 -0
- package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +3 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +192 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +24 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +116 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +97 -0
- package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +100 -0
- package/rust/core/audio/interpreter/statements/automate.rs +16 -0
- package/rust/core/audio/interpreter/statements/call.rs +295 -0
- package/rust/core/audio/interpreter/{condition.rs → statements/condition.rs} +72 -69
- package/rust/core/audio/interpreter/statements/function.rs +24 -0
- package/rust/core/audio/interpreter/statements/let_.rs +36 -0
- package/rust/core/audio/interpreter/statements/load.rs +17 -0
- package/rust/core/audio/interpreter/statements/loop_.rs +115 -0
- package/rust/core/audio/interpreter/statements/mod.rs +12 -0
- package/rust/core/audio/interpreter/statements/sleep.rs +28 -0
- package/rust/core/audio/interpreter/statements/spawn.rs +253 -0
- package/rust/core/audio/interpreter/statements/tempo.rs +40 -0
- package/rust/core/audio/interpreter/statements/trigger.rs +239 -0
- package/rust/core/audio/loader/mod.rs +1 -1
- package/rust/core/audio/loader/trigger.rs +98 -52
- package/rust/core/audio/mod.rs +2 -2
- package/rust/core/audio/player.rs +28 -12
- package/rust/core/audio/special/easing.rs +189 -0
- package/rust/core/audio/special/env.rs +45 -0
- package/rust/core/audio/special/math.rs +134 -0
- package/rust/core/audio/special/mod.rs +9 -0
- package/rust/core/audio/special/modulator.rs +143 -0
- package/rust/core/builder/mod.rs +129 -80
- package/rust/core/debugger/lexer.rs +4 -4
- package/rust/core/debugger/logs.rs +52 -0
- package/rust/core/debugger/mod.rs +11 -2
- package/rust/core/debugger/preprocessor.rs +4 -4
- package/rust/core/debugger/store.rs +38 -25
- package/rust/core/error/mod.rs +221 -12
- package/rust/core/lexer/driver.rs +59 -0
- package/rust/core/lexer/handler/arrow.rs +62 -11
- package/rust/core/lexer/handler/at.rs +5 -5
- package/rust/core/lexer/handler/brace.rs +11 -11
- package/rust/core/lexer/handler/colon.rs +5 -5
- package/rust/core/lexer/handler/comment.rs +3 -3
- package/rust/core/lexer/handler/dot.rs +6 -6
- package/rust/core/lexer/handler/driver.rs +143 -32
- package/rust/core/lexer/handler/identifier.rs +11 -5
- package/rust/core/lexer/handler/indent.rs +18 -4
- package/rust/core/lexer/handler/mod.rs +6 -5
- package/rust/core/lexer/handler/newline.rs +3 -3
- package/rust/core/lexer/handler/number.rs +5 -5
- package/rust/core/lexer/handler/operator.rs +5 -3
- package/rust/core/lexer/handler/parenthesis.rs +41 -0
- package/rust/core/lexer/handler/slash.rs +21 -0
- package/rust/core/lexer/handler/string.rs +3 -3
- package/rust/core/lexer/mod.rs +1 -49
- package/rust/core/lexer/token.rs +17 -12
- package/rust/core/mod.rs +9 -10
- package/rust/core/parser/driver/block.rs +111 -0
- package/rust/core/parser/driver/cursor.rs +82 -0
- package/rust/core/parser/driver/driver_impl.rs +139 -0
- package/rust/core/parser/driver/mod.rs +6 -0
- package/rust/core/parser/driver/parse_array.rs +120 -0
- package/rust/core/parser/driver/parse_map.rs +223 -0
- package/rust/core/parser/driver/parser.rs +160 -0
- package/rust/core/parser/handler/arrow_call.rs +277 -126
- package/rust/core/parser/handler/at.rs +142 -25
- package/rust/core/parser/handler/bank.rs +83 -20
- package/rust/core/parser/handler/condition.rs +14 -5
- package/rust/core/parser/handler/dot.rs +111 -75
- package/rust/core/parser/handler/identifier/automate.rs +254 -0
- package/rust/core/parser/handler/identifier/call.rs +74 -24
- package/rust/core/parser/handler/identifier/emit.rs +70 -0
- package/rust/core/parser/handler/identifier/function.rs +113 -0
- package/rust/core/parser/handler/identifier/group.rs +28 -14
- package/rust/core/parser/handler/identifier/let_.rs +61 -21
- package/rust/core/parser/handler/identifier/mod.rs +24 -20
- package/rust/core/parser/handler/identifier/on.rs +107 -0
- package/rust/core/parser/handler/identifier/print.rs +49 -0
- package/rust/core/parser/handler/identifier/sleep.rs +77 -14
- package/rust/core/parser/handler/identifier/spawn.rs +81 -31
- package/rust/core/parser/handler/identifier/synth.rs +102 -32
- package/rust/core/parser/handler/loop_.rs +144 -22
- package/rust/core/parser/handler/mod.rs +6 -5
- package/rust/core/parser/handler/pattern.rs +74 -0
- package/rust/core/parser/handler/tempo.rs +67 -9
- package/rust/core/parser/mod.rs +3 -4
- package/rust/core/parser/statement.rs +6 -92
- package/rust/core/plugin/loader.rs +137 -0
- package/rust/core/plugin/mod.rs +2 -0
- package/rust/core/plugin/runner/mod.rs +11 -0
- package/rust/core/plugin/runner/non_wasm.rs +297 -0
- package/rust/core/plugin/runner/wasm32.rs +43 -0
- package/rust/core/preprocessor/loader/inject.rs +278 -0
- package/rust/core/preprocessor/loader/loader_helpers.rs +110 -0
- package/rust/core/preprocessor/loader/mod.rs +235 -0
- package/rust/core/preprocessor/mod.rs +4 -4
- package/rust/core/preprocessor/module.rs +55 -50
- package/rust/core/preprocessor/processor/handlers.rs +107 -0
- package/rust/core/preprocessor/processor/mod.rs +1 -0
- package/rust/core/preprocessor/resolver/bank.rs +14 -12
- package/rust/core/preprocessor/resolver/call.rs +106 -105
- package/rust/core/preprocessor/resolver/condition.rs +13 -10
- package/rust/core/preprocessor/resolver/driver.rs +145 -48
- package/rust/core/preprocessor/resolver/function.rs +69 -0
- package/rust/core/preprocessor/resolver/group.rs +122 -61
- package/rust/core/preprocessor/resolver/let_.rs +13 -12
- package/rust/core/preprocessor/resolver/loop_.rs +240 -13
- package/rust/core/preprocessor/resolver/mod.rs +8 -6
- package/rust/core/preprocessor/resolver/pattern.rs +83 -0
- package/rust/core/preprocessor/resolver/spawn.rs +83 -42
- package/rust/core/preprocessor/resolver/synth.rs +15 -11
- package/rust/core/preprocessor/resolver/tempo.rs +13 -14
- package/rust/core/preprocessor/resolver/trigger.rs +32 -28
- package/rust/core/preprocessor/resolver/value.rs +111 -13
- package/rust/core/store/global.rs +57 -39
- package/rust/core/store/mod.rs +0 -3
- package/rust/lib.rs +323 -117
- package/rust/main.rs +388 -65
- package/rust/types/Cargo.toml +11 -0
- package/rust/types/src/addons.rs +55 -0
- package/rust/types/src/ast.rs +202 -0
- package/rust/types/src/config.rs +84 -0
- package/rust/types/src/lib.rs +15 -0
- package/rust/types/src/plugin.rs +20 -0
- package/rust/types/src/store.rs +139 -0
- package/rust/types/src/telemetry.rs +85 -0
- package/rust/utils/Cargo.toml +26 -0
- package/rust/utils/src/error.rs +186 -0
- 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} +6 -3
- package/rust/utils/{logger.rs → src/logger.rs} +94 -17
- package/rust/utils/src/path.rs +129 -0
- package/rust/utils/src/signature.rs +41 -0
- package/rust/utils/{spinner.rs → src/spinner.rs} +7 -8
- package/rust/utils/src/version.rs +27 -0
- package/rust/utils/{watcher.rs → src/watcher.rs} +17 -4
- package/rust/web/api.rs +5 -0
- package/rust/web/cdn.rs +34 -0
- package/rust/web/mod.rs +3 -0
- package/rust/web/sso.rs +5 -0
- package/templates/minimal/README.md +143 -127
- package/templates/welcome/README.md +143 -127
- package/templates/welcome/src/index.deva +56 -8
- package/templates/welcome/src/variables.deva +2 -4
- package/tests/integration.rs +21 -0
- package/tests/rust/cli_check_build.rs +21 -0
- package/tests/rust/cli_help.rs +12 -0
- package/tests/rust/cli_template_list.rs +10 -0
- package/tests/rust/cli_version.rs +11 -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 +12 -10
- package/typescript/bin/index.ts +19 -5
- package/typescript/core/functions/index.ts +94 -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 +8 -1
- package/typescript/pkg/devalang_core.d.ts +4 -0
- package/typescript/pkg/devalang_core.ts +65 -0
- package/typescript/scripts/copy-wasm-dts.ts +41 -0
- package/typescript/scripts/postinstall.ts +85 -0
- package/typescript/scripts/version/bump.ts +0 -1
- package/typescript/scripts/version/index.ts +0 -1
- package/docs/COMMANDS.md +0 -85
- package/docs/CONFIG.md +0 -30
- package/docs/SYNTAX.md +0 -210
- package/out-tsc/bin/devalang.exe +0 -0
- package/out-tsc/scripts/postbuild.js +0 -11
- package/rust/cli/build.rs +0 -137
- package/rust/cli/check.rs +0 -117
- package/rust/cli/play.rs +0 -193
- package/rust/config/loader.rs +0 -13
- package/rust/core/audio/engine.rs +0 -203
- package/rust/core/audio/evaluator.rs +0 -31
- package/rust/core/audio/interpreter/arrow_call.rs +0 -129
- package/rust/core/audio/interpreter/call.rs +0 -64
- package/rust/core/audio/interpreter/let_.rs +0 -19
- package/rust/core/audio/interpreter/load.rs +0 -18
- package/rust/core/audio/interpreter/loop_.rs +0 -67
- package/rust/core/audio/interpreter/sleep.rs +0 -36
- package/rust/core/audio/interpreter/spawn.rs +0 -66
- package/rust/core/audio/interpreter/tempo.rs +0 -16
- package/rust/core/audio/interpreter/trigger.rs +0 -69
- package/rust/core/audio/renderer.rs +0 -54
- package/rust/core/parser/driver.rs +0 -331
- package/rust/core/preprocessor/loader.rs +0 -193
- package/rust/core/preprocessor/processor.rs +0 -76
- package/rust/core/shared/duration.rs +0 -8
- package/rust/core/shared/mod.rs +0 -2
- package/rust/core/shared/value.rs +0 -18
- package/rust/core/store/export.rs +0 -28
- package/rust/core/store/import.rs +0 -28
- package/rust/core/store/variable.rs +0 -28
- package/rust/core/utils/mod.rs +0 -2
- package/rust/core/utils/path.rs +0 -31
- package/rust/core/utils/validation.rs +0 -37
- package/rust/utils/file.rs +0 -35
- package/rust/utils/signature.rs +0 -17
- package/rust/utils/version.rs +0 -15
- package/typescript/scripts/postbuild.ts +0 -8
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
2
|
|
|
3
|
-
use crate::{
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
resolver::{ driver::resolve_statement, value::resolve_value },
|
|
9
|
-
},
|
|
10
|
-
shared::value::Value,
|
|
11
|
-
store::global::GlobalStore,
|
|
3
|
+
use crate::core::{
|
|
4
|
+
parser::statement::{Statement, StatementKind},
|
|
5
|
+
preprocessor::{
|
|
6
|
+
module::Module,
|
|
7
|
+
resolver::{driver::resolve_statement, value::resolve_value},
|
|
12
8
|
},
|
|
13
|
-
|
|
9
|
+
store::global::GlobalStore,
|
|
14
10
|
};
|
|
11
|
+
use devalang_types::Value;
|
|
12
|
+
use devalang_utils::logger::Logger;
|
|
15
13
|
|
|
16
14
|
pub fn resolve_loop(
|
|
17
15
|
stmt: &Statement,
|
|
18
16
|
module: &Module,
|
|
19
17
|
path: &str,
|
|
20
|
-
global_store: &mut GlobalStore
|
|
18
|
+
global_store: &mut GlobalStore,
|
|
21
19
|
) -> Statement {
|
|
22
20
|
let logger = Logger::new();
|
|
23
21
|
|
|
@@ -32,14 +30,243 @@ pub fn resolve_loop(
|
|
|
32
30
|
resolved_map.insert(key.clone(), resolve_value(val, module, global_store));
|
|
33
31
|
}
|
|
34
32
|
|
|
33
|
+
// Foreach form takes precedence if present
|
|
34
|
+
if let (Some(Value::Identifier(var_name)), Some(array_val)) =
|
|
35
|
+
(resolved_map.get("foreach"), resolved_map.get("array"))
|
|
36
|
+
{
|
|
37
|
+
// Normalize array_val into an iterable Array
|
|
38
|
+
let resolved_array = match array_val {
|
|
39
|
+
Value::Array(items) => Value::Array(
|
|
40
|
+
items
|
|
41
|
+
.iter()
|
|
42
|
+
.map(|v| resolve_value(v, module, global_store))
|
|
43
|
+
.collect(),
|
|
44
|
+
),
|
|
45
|
+
Value::Number(n) => {
|
|
46
|
+
// Iterate 0..n-1
|
|
47
|
+
let count = (*n).max(0.0) as usize;
|
|
48
|
+
let mut items = Vec::with_capacity(count);
|
|
49
|
+
for i in 0..count {
|
|
50
|
+
items.push(Value::Number(i as f32));
|
|
51
|
+
}
|
|
52
|
+
Value::Array(items)
|
|
53
|
+
}
|
|
54
|
+
Value::String(s) => {
|
|
55
|
+
// Try to parse a simple comma-separated list: "a,b,c" -> ["a","b","c"]
|
|
56
|
+
// If numeric string: iterate 0..n-1
|
|
57
|
+
if let Ok(n) = s.parse::<f32>() {
|
|
58
|
+
let count = n.max(0.0) as usize;
|
|
59
|
+
let mut items = Vec::with_capacity(count);
|
|
60
|
+
for i in 0..count {
|
|
61
|
+
items.push(Value::Number(i as f32));
|
|
62
|
+
}
|
|
63
|
+
Value::Array(items)
|
|
64
|
+
} else if s.contains(',') {
|
|
65
|
+
let parts: Vec<Value> = s
|
|
66
|
+
.split(',')
|
|
67
|
+
.map(|p| Value::String(p.trim().to_string()))
|
|
68
|
+
.collect();
|
|
69
|
+
Value::Array(parts)
|
|
70
|
+
} else {
|
|
71
|
+
// Fallback: iterate characters
|
|
72
|
+
let parts: Vec<Value> =
|
|
73
|
+
s.chars().map(|c| Value::String(c.to_string())).collect();
|
|
74
|
+
Value::Array(parts)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
Value::Identifier(name) => {
|
|
78
|
+
// Resolve identifier from module variables (already resolved map above)
|
|
79
|
+
let v = if let Some(v) = module.variable_table.get(name) {
|
|
80
|
+
v.clone()
|
|
81
|
+
} else {
|
|
82
|
+
Value::Null
|
|
83
|
+
};
|
|
84
|
+
match v {
|
|
85
|
+
Value::Array(items) => Value::Array(
|
|
86
|
+
items
|
|
87
|
+
.iter()
|
|
88
|
+
.map(|v| resolve_value(v, module, global_store))
|
|
89
|
+
.collect(),
|
|
90
|
+
),
|
|
91
|
+
Value::Number(n) => {
|
|
92
|
+
let count = n.max(0.0) as usize;
|
|
93
|
+
let mut items = Vec::with_capacity(count);
|
|
94
|
+
for i in 0..count {
|
|
95
|
+
items.push(Value::Number(i as f32));
|
|
96
|
+
}
|
|
97
|
+
Value::Array(items)
|
|
98
|
+
}
|
|
99
|
+
Value::String(s) => {
|
|
100
|
+
if let Ok(n) = s.parse::<f32>() {
|
|
101
|
+
let count = n.max(0.0) as usize;
|
|
102
|
+
let mut items = Vec::with_capacity(count);
|
|
103
|
+
for i in 0..count {
|
|
104
|
+
items.push(Value::Number(i as f32));
|
|
105
|
+
}
|
|
106
|
+
Value::Array(items)
|
|
107
|
+
} else if s.contains(',') {
|
|
108
|
+
let parts: Vec<Value> = s
|
|
109
|
+
.split(',')
|
|
110
|
+
.map(|p| Value::String(p.trim().to_string()))
|
|
111
|
+
.collect();
|
|
112
|
+
Value::Array(parts)
|
|
113
|
+
} else {
|
|
114
|
+
let parts: Vec<Value> =
|
|
115
|
+
s.chars().map(|c| Value::String(c.to_string())).collect();
|
|
116
|
+
Value::Array(parts)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
other => {
|
|
120
|
+
error_value(
|
|
121
|
+
&logger,
|
|
122
|
+
module,
|
|
123
|
+
stmt,
|
|
124
|
+
&format!(
|
|
125
|
+
"Foreach identifier '{}' resolves to unsupported value: {:?}",
|
|
126
|
+
name, other
|
|
127
|
+
),
|
|
128
|
+
);
|
|
129
|
+
Value::Array(vec![])
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
other => {
|
|
134
|
+
// Resolve and normalize if possible
|
|
135
|
+
let v = resolve_value(other, module, global_store);
|
|
136
|
+
match v {
|
|
137
|
+
Value::Array(items) => Value::Array(items),
|
|
138
|
+
Value::Number(n) => {
|
|
139
|
+
let count = n.max(0.0) as usize;
|
|
140
|
+
let mut items = Vec::with_capacity(count);
|
|
141
|
+
for i in 0..count {
|
|
142
|
+
items.push(Value::Number(i as f32));
|
|
143
|
+
}
|
|
144
|
+
Value::Array(items)
|
|
145
|
+
}
|
|
146
|
+
Value::String(s) => {
|
|
147
|
+
if let Ok(n) = s.parse::<f32>() {
|
|
148
|
+
let count = n.max(0.0) as usize;
|
|
149
|
+
let mut items = Vec::with_capacity(count);
|
|
150
|
+
for i in 0..count {
|
|
151
|
+
items.push(Value::Number(i as f32));
|
|
152
|
+
}
|
|
153
|
+
Value::Array(items)
|
|
154
|
+
} else if s.contains(',') {
|
|
155
|
+
let parts: Vec<Value> = s
|
|
156
|
+
.split(',')
|
|
157
|
+
.map(|p| Value::String(p.trim().to_string()))
|
|
158
|
+
.collect();
|
|
159
|
+
Value::Array(parts)
|
|
160
|
+
} else {
|
|
161
|
+
let parts: Vec<Value> =
|
|
162
|
+
s.chars().map(|c| Value::String(c.to_string())).collect();
|
|
163
|
+
Value::Array(parts)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
other => {
|
|
167
|
+
error_value(
|
|
168
|
+
&logger,
|
|
169
|
+
module,
|
|
170
|
+
stmt,
|
|
171
|
+
&format!("Unsupported foreach array value: {:?}", other),
|
|
172
|
+
);
|
|
173
|
+
Value::Array(vec![])
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
let body_value = match resolved_map.get("body") {
|
|
180
|
+
Some(Value::Block(stmts)) => {
|
|
181
|
+
let resolved = stmts
|
|
182
|
+
.iter()
|
|
183
|
+
.map(|s| resolve_statement(s, module, path, global_store))
|
|
184
|
+
.collect();
|
|
185
|
+
Value::Block(resolved)
|
|
186
|
+
}
|
|
187
|
+
_ => {
|
|
188
|
+
error_value(&logger, module, stmt, "Invalid or missing loop body");
|
|
189
|
+
Value::Block(vec![])
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
let mut final_map = HashMap::new();
|
|
194
|
+
final_map.insert("foreach".to_string(), Value::Identifier(var_name.clone()));
|
|
195
|
+
final_map.insert("array".to_string(), resolved_array);
|
|
196
|
+
final_map.insert("body".to_string(), body_value);
|
|
197
|
+
|
|
198
|
+
return Statement {
|
|
199
|
+
kind: StatementKind::Loop,
|
|
200
|
+
value: Value::Map(final_map),
|
|
201
|
+
..stmt.clone()
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
35
205
|
let iterator_value = match resolved_map.get("iterator") {
|
|
36
206
|
Some(Value::Number(n)) => Value::Number(*n),
|
|
207
|
+
Some(Value::String(s)) => {
|
|
208
|
+
if let Ok(n) = s.parse::<f32>() {
|
|
209
|
+
Value::Number(n)
|
|
210
|
+
} else {
|
|
211
|
+
error_value(
|
|
212
|
+
&logger,
|
|
213
|
+
module,
|
|
214
|
+
stmt,
|
|
215
|
+
&format!("Loop iterator string not numeric: '{}'", s),
|
|
216
|
+
);
|
|
217
|
+
Value::Number(1.0)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
Some(Value::Identifier(name)) => {
|
|
221
|
+
// Try resolving from module vars (may be number or numeric string)
|
|
222
|
+
if let Some(v) = module.variable_table.get(name) {
|
|
223
|
+
match v {
|
|
224
|
+
Value::Number(n) => Value::Number(*n),
|
|
225
|
+
Value::String(s) => {
|
|
226
|
+
if let Ok(n) = s.parse::<f32>() {
|
|
227
|
+
Value::Number(n)
|
|
228
|
+
} else {
|
|
229
|
+
error_value(
|
|
230
|
+
&logger,
|
|
231
|
+
module,
|
|
232
|
+
stmt,
|
|
233
|
+
&format!(
|
|
234
|
+
"Loop iterator '{}' resolves to non-numeric string: '{}'",
|
|
235
|
+
name, s
|
|
236
|
+
),
|
|
237
|
+
);
|
|
238
|
+
Value::Number(1.0)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
other => {
|
|
242
|
+
error_value(
|
|
243
|
+
&logger,
|
|
244
|
+
module,
|
|
245
|
+
stmt,
|
|
246
|
+
&format!(
|
|
247
|
+
"Loop iterator '{}' resolves to non-number: {:?}",
|
|
248
|
+
name, other
|
|
249
|
+
),
|
|
250
|
+
);
|
|
251
|
+
Value::Number(1.0)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
} else {
|
|
255
|
+
error_value(
|
|
256
|
+
&logger,
|
|
257
|
+
module,
|
|
258
|
+
stmt,
|
|
259
|
+
&format!("Loop iterator identifier '{}' not found", name),
|
|
260
|
+
);
|
|
261
|
+
Value::Number(1.0)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
37
264
|
Some(other) => {
|
|
38
265
|
error_value(
|
|
39
266
|
&logger,
|
|
40
267
|
module,
|
|
41
268
|
stmt,
|
|
42
|
-
&format!("Loop iterator must be a number, found: {:?}", other)
|
|
269
|
+
&format!("Loop iterator must be a number, found: {:?}", other),
|
|
43
270
|
);
|
|
44
271
|
Value::Number(1.0)
|
|
45
272
|
}
|
|
@@ -49,7 +276,7 @@ pub fn resolve_loop(
|
|
|
49
276
|
}
|
|
50
277
|
};
|
|
51
278
|
|
|
52
|
-
let body_value = match resolved_map.
|
|
279
|
+
let body_value = match resolved_map.get("body") {
|
|
53
280
|
Some(Value::Block(stmts)) => {
|
|
54
281
|
let resolved = stmts
|
|
55
282
|
.iter()
|
|
@@ -2,13 +2,15 @@ pub mod driver;
|
|
|
2
2
|
|
|
3
3
|
pub mod value;
|
|
4
4
|
|
|
5
|
-
pub mod trigger;
|
|
6
|
-
pub mod loop_;
|
|
7
5
|
pub mod bank;
|
|
8
|
-
pub mod
|
|
9
|
-
pub mod group;
|
|
6
|
+
pub mod call;
|
|
10
7
|
pub mod condition;
|
|
8
|
+
pub mod function;
|
|
9
|
+
pub mod group;
|
|
10
|
+
pub mod let_;
|
|
11
|
+
pub mod loop_;
|
|
12
|
+
pub mod pattern;
|
|
11
13
|
pub mod spawn;
|
|
12
|
-
pub mod call;
|
|
13
14
|
pub mod synth;
|
|
14
|
-
pub mod
|
|
15
|
+
pub mod tempo;
|
|
16
|
+
pub mod trigger;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
parser::statement::{Statement, StatementKind},
|
|
3
|
+
preprocessor::module::Module,
|
|
4
|
+
store::global::GlobalStore,
|
|
5
|
+
};
|
|
6
|
+
use devalang_types::Value;
|
|
7
|
+
use devalang_utils::logger::{LogLevel, Logger};
|
|
8
|
+
|
|
9
|
+
pub fn resolve_pattern(
|
|
10
|
+
stmt: &Statement,
|
|
11
|
+
module: &Module,
|
|
12
|
+
path: &str,
|
|
13
|
+
global_store: &mut GlobalStore,
|
|
14
|
+
) -> Statement {
|
|
15
|
+
let logger = Logger::new();
|
|
16
|
+
|
|
17
|
+
// Expecting pattern name stored on the Statement.kind; value may contain the string
|
|
18
|
+
if let StatementKind::Pattern { name, target } = &stmt.kind {
|
|
19
|
+
// Ensure name doesn't already exist
|
|
20
|
+
if global_store.variables.variables.contains_key(name) {
|
|
21
|
+
logger.log_error_with_stacktrace(
|
|
22
|
+
&format!("Pattern identifier '{}' already exists", name),
|
|
23
|
+
path,
|
|
24
|
+
);
|
|
25
|
+
return Statement {
|
|
26
|
+
kind: StatementKind::Error {
|
|
27
|
+
message: format!("Pattern '{}' already exists", name),
|
|
28
|
+
},
|
|
29
|
+
..stmt.clone()
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Resolve potential target and pattern string value
|
|
34
|
+
let resolved_value = resolve_value(&stmt.value, module, global_store);
|
|
35
|
+
|
|
36
|
+
// Build a map to store the pattern definition
|
|
37
|
+
let mut map = std::collections::HashMap::new();
|
|
38
|
+
map.insert("identifier".to_string(), Value::String(name.clone()));
|
|
39
|
+
if let Some(t) = target {
|
|
40
|
+
map.insert("target".to_string(), Value::String(t.clone()));
|
|
41
|
+
}
|
|
42
|
+
// Keep raw pattern in 'pattern' key
|
|
43
|
+
map.insert("pattern".to_string(), resolved_value.clone());
|
|
44
|
+
|
|
45
|
+
let resolved_stmt = Statement {
|
|
46
|
+
kind: StatementKind::Pattern {
|
|
47
|
+
name: name.clone(),
|
|
48
|
+
target: target.clone(),
|
|
49
|
+
},
|
|
50
|
+
value: resolved_value,
|
|
51
|
+
..stmt.clone()
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Store into global variables as a Statement
|
|
55
|
+
global_store.variables.variables.insert(
|
|
56
|
+
name.clone(),
|
|
57
|
+
Value::Statement(Box::new(resolved_stmt.clone())),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return resolved_stmt;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
logger.log_message(
|
|
64
|
+
LogLevel::Warning,
|
|
65
|
+
"resolve_pattern called on non-pattern statement",
|
|
66
|
+
);
|
|
67
|
+
stmt.clone()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn resolve_value(value: &Value, module: &Module, global_store: &mut GlobalStore) -> Value {
|
|
71
|
+
// reuse driver::resolve_value logic; simple local resolution for pattern value
|
|
72
|
+
match value {
|
|
73
|
+
Value::String(s) => Value::String(s.clone()),
|
|
74
|
+
Value::Map(m) => {
|
|
75
|
+
let mut resolved = std::collections::HashMap::new();
|
|
76
|
+
for (k, v) in m {
|
|
77
|
+
resolved.insert(k.clone(), resolve_value(v, module, global_store));
|
|
78
|
+
}
|
|
79
|
+
Value::Map(resolved)
|
|
80
|
+
}
|
|
81
|
+
other => other.clone(),
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -1,58 +1,99 @@
|
|
|
1
|
-
use crate::{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
module::Module,
|
|
6
|
-
resolver::driver::resolve_statement,
|
|
7
|
-
resolver::value::resolve_value,
|
|
8
|
-
},
|
|
9
|
-
shared::value::Value,
|
|
10
|
-
store::global::GlobalStore,
|
|
11
|
-
},
|
|
12
|
-
utils::logger::{ Logger, LogLevel },
|
|
1
|
+
use crate::core::{
|
|
2
|
+
parser::statement::{Statement, StatementKind},
|
|
3
|
+
preprocessor::module::Module,
|
|
4
|
+
store::global::GlobalStore,
|
|
13
5
|
};
|
|
6
|
+
use devalang_types::Value;
|
|
7
|
+
use devalang_utils::logger::{LogLevel, Logger};
|
|
14
8
|
|
|
15
9
|
pub fn resolve_spawn(
|
|
16
10
|
stmt: &Statement,
|
|
11
|
+
name: String,
|
|
12
|
+
args: Vec<Value>,
|
|
17
13
|
module: &Module,
|
|
18
|
-
|
|
19
|
-
global_store: &mut GlobalStore
|
|
14
|
+
_path: &str,
|
|
15
|
+
global_store: &mut GlobalStore,
|
|
20
16
|
) -> Statement {
|
|
21
17
|
let logger = Logger::new();
|
|
22
18
|
|
|
23
|
-
|
|
19
|
+
// If it's a function
|
|
20
|
+
if let Some(func) = global_store.functions.functions.get(&name) {
|
|
21
|
+
let mut resolved_map = std::collections::HashMap::new();
|
|
22
|
+
resolved_map.insert("name".to_string(), Value::String(name.clone()));
|
|
23
|
+
resolved_map.insert("args".to_string(), Value::Array(args.clone()));
|
|
24
|
+
resolved_map.insert("body".to_string(), Value::Block(func.body.clone()));
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.collect();
|
|
32
|
-
map.insert("body".to_string(), Value::Block(resolved_block));
|
|
33
|
-
}
|
|
26
|
+
return Statement {
|
|
27
|
+
kind: StatementKind::Spawn { name, args },
|
|
28
|
+
value: Value::Map(resolved_map),
|
|
29
|
+
..stmt.clone()
|
|
30
|
+
};
|
|
31
|
+
}
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
// If it's a group stored in variables
|
|
34
|
+
if let Some(Value::Statement(stmt_box)) = global_store.variables.variables.get(&name) {
|
|
35
|
+
if let StatementKind::Group = stmt_box.kind {
|
|
36
|
+
if let Value::Map(map) = &stmt_box.value {
|
|
37
|
+
if let Some(Value::Block(body)) = map.get("body") {
|
|
38
|
+
let mut resolved_map = std::collections::HashMap::new();
|
|
39
|
+
resolved_map.insert("identifier".to_string(), Value::String(name.clone()));
|
|
40
|
+
resolved_map.insert("args".to_string(), Value::Array(args.clone()));
|
|
41
|
+
resolved_map.insert("body".to_string(), Value::Block(body.clone()));
|
|
42
|
+
|
|
43
|
+
return Statement {
|
|
44
|
+
kind: StatementKind::Spawn { name, args },
|
|
45
|
+
value: Value::Map(resolved_map),
|
|
46
|
+
..stmt.clone()
|
|
47
|
+
};
|
|
48
|
+
}
|
|
39
49
|
}
|
|
40
50
|
}
|
|
51
|
+
// Pattern case (make spawn accept patterns stored as variables)
|
|
52
|
+
if let StatementKind::Pattern { .. } = stmt_box.kind {
|
|
53
|
+
let mut resolved_map = std::collections::HashMap::new();
|
|
54
|
+
resolved_map.insert("identifier".to_string(), Value::String(name.clone()));
|
|
55
|
+
// pattern value may be a string or a map stored on the statement
|
|
56
|
+
match &stmt_box.value {
|
|
57
|
+
Value::String(s) => {
|
|
58
|
+
resolved_map.insert("pattern".to_string(), Value::String(s.clone()));
|
|
59
|
+
}
|
|
60
|
+
Value::Map(m) => {
|
|
61
|
+
if let Some(val) = m.get("pattern") {
|
|
62
|
+
resolved_map.insert("pattern".to_string(), val.clone());
|
|
63
|
+
}
|
|
64
|
+
if let Some(val) = m.get("target") {
|
|
65
|
+
resolved_map.insert("target".to_string(), val.clone());
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
_ => {}
|
|
69
|
+
}
|
|
70
|
+
resolved_map.insert("args".to_string(), Value::Array(args.clone()));
|
|
41
71
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
LogLevel::Error,
|
|
46
|
-
&format!("Expected a map in spawn statement\n → at {stacktrace}")
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
Statement {
|
|
50
|
-
kind: StatementKind::Error {
|
|
51
|
-
message: "Invalid spawn value".to_string(),
|
|
52
|
-
},
|
|
53
|
-
value: Value::Null,
|
|
72
|
+
return Statement {
|
|
73
|
+
kind: StatementKind::Spawn { name, args },
|
|
74
|
+
value: Value::Map(resolved_map),
|
|
54
75
|
..stmt.clone()
|
|
55
|
-
}
|
|
76
|
+
};
|
|
56
77
|
}
|
|
57
78
|
}
|
|
58
|
-
|
|
79
|
+
|
|
80
|
+
// Otherwise, log an error
|
|
81
|
+
let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
|
|
82
|
+
logger.log_message(
|
|
83
|
+
LogLevel::Error,
|
|
84
|
+
&format!(
|
|
85
|
+
"Function or group '{}' not found for spawn\n → at {stacktrace}",
|
|
86
|
+
name
|
|
87
|
+
),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
Statement {
|
|
91
|
+
kind: StatementKind::Error {
|
|
92
|
+
message: format!("Function or group '{}' not found for spawn", name),
|
|
93
|
+
},
|
|
94
|
+
value: Value::Null,
|
|
95
|
+
..stmt.clone()
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// (removed unused helpers get_group_body, error_stmt)
|
|
@@ -1,29 +1,33 @@
|
|
|
1
|
-
use crate::{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
shared::value::Value,
|
|
6
|
-
store::global::GlobalStore,
|
|
7
|
-
},
|
|
8
|
-
utils::logger::{ LogLevel, Logger },
|
|
1
|
+
use crate::core::{
|
|
2
|
+
parser::statement::{Statement, StatementKind},
|
|
3
|
+
preprocessor::{module::Module, resolver::driver::resolve_statement},
|
|
4
|
+
store::global::GlobalStore,
|
|
9
5
|
};
|
|
6
|
+
use devalang_types::Value;
|
|
7
|
+
use devalang_utils::logger::{LogLevel, Logger};
|
|
10
8
|
|
|
11
9
|
pub fn resolve_synth(
|
|
12
10
|
stmt: &Statement,
|
|
13
11
|
module: &Module,
|
|
14
12
|
path: &str,
|
|
15
|
-
global_store: &mut GlobalStore
|
|
13
|
+
global_store: &mut GlobalStore,
|
|
16
14
|
) -> Statement {
|
|
17
15
|
let logger = Logger::new();
|
|
18
16
|
|
|
19
17
|
let Value::Map(synth_map) = &stmt.value else {
|
|
20
|
-
return type_error(
|
|
18
|
+
return type_error(
|
|
19
|
+
&logger,
|
|
20
|
+
module,
|
|
21
|
+
stmt,
|
|
22
|
+
"Expected a map in synth statement".to_string(),
|
|
23
|
+
);
|
|
21
24
|
};
|
|
22
25
|
|
|
23
26
|
let mut resolved_map = synth_map.clone();
|
|
24
27
|
|
|
25
28
|
if let Some(Value::Block(body)) = synth_map.get("body") {
|
|
26
|
-
let resolved_body = body
|
|
29
|
+
let resolved_body = body
|
|
30
|
+
.iter()
|
|
27
31
|
.map(|s| resolve_statement(s, module, path, global_store))
|
|
28
32
|
.collect::<Vec<_>>();
|
|
29
33
|
resolved_map.insert("body".to_string(), Value::Block(resolved_body));
|
|
@@ -1,18 +1,16 @@
|
|
|
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_tempo(
|
|
12
10
|
stmt: &Statement,
|
|
13
11
|
module: &Module,
|
|
14
|
-
|
|
15
|
-
_global_store: &GlobalStore
|
|
12
|
+
_path: &str,
|
|
13
|
+
_global_store: &GlobalStore,
|
|
16
14
|
) -> Statement {
|
|
17
15
|
let mut new_stmt = stmt.clone();
|
|
18
16
|
let logger = Logger::new();
|
|
@@ -24,9 +22,7 @@ pub fn resolve_tempo(
|
|
|
24
22
|
} else {
|
|
25
23
|
let message = format!("Tempo identifier '{ident}' not found in variable table");
|
|
26
24
|
logger.log_error_with_stacktrace(&message, &module.path);
|
|
27
|
-
new_stmt.kind = StatementKind::Error {
|
|
28
|
-
message,
|
|
29
|
-
};
|
|
25
|
+
new_stmt.kind = StatementKind::Error { message };
|
|
30
26
|
new_stmt.value = Value::Null;
|
|
31
27
|
}
|
|
32
28
|
}
|
|
@@ -36,7 +32,10 @@ pub fn resolve_tempo(
|
|
|
36
32
|
}
|
|
37
33
|
|
|
38
34
|
other => {
|
|
39
|
-
let message = format!(
|
|
35
|
+
let message = format!(
|
|
36
|
+
"Expected a number or identifier for tempo, found {:?}",
|
|
37
|
+
other
|
|
38
|
+
);
|
|
40
39
|
logger.log_error_with_stacktrace(&message, &module.path);
|
|
41
40
|
new_stmt.kind = StatementKind::Error {
|
|
42
41
|
message: "Expected a number or identifier for tempo".to_string(),
|