@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
|
@@ -32,7 +32,7 @@ pub fn parse_identifier_token(parser: &mut Parser, global_store: &mut GlobalStor
|
|
|
32
32
|
let current_token_clone = current_token.clone();
|
|
33
33
|
let current_token_lexeme = current_token_clone.lexeme.clone();
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
match current_token_lexeme.as_str() {
|
|
36
36
|
"let" => parse_let_token(parser, current_token_clone, global_store),
|
|
37
37
|
"group" => parse_group_token(parser, current_token_clone, global_store),
|
|
38
38
|
"call" => parse_call_token(parser, current_token_clone, global_store),
|
|
@@ -46,9 +46,10 @@ pub fn parse_identifier_token(parser: &mut Parser, global_store: &mut GlobalStor
|
|
|
46
46
|
_ => {
|
|
47
47
|
parser.advance(); // consume identifier
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
crate::core::parser::statement::error_from_token(
|
|
50
|
+
current_token_clone,
|
|
51
|
+
"Unexpected identifier".to_string(),
|
|
52
|
+
)
|
|
50
53
|
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return statement;
|
|
54
|
+
}
|
|
54
55
|
}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
+
use devalang_types::Value;
|
|
2
|
+
|
|
1
3
|
use crate::core::{
|
|
2
4
|
lexer::token::TokenKind,
|
|
3
5
|
parser::{
|
|
4
6
|
driver::Parser,
|
|
5
7
|
statement::{Statement, StatementKind},
|
|
6
8
|
},
|
|
7
|
-
shared::value::Value,
|
|
8
9
|
store::global::GlobalStore,
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
// Syntax:
|
|
12
|
-
// on <identifier>:
|
|
13
|
-
// <indented block>
|
|
14
12
|
pub fn parse_on_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
|
|
15
13
|
// consume 'on'
|
|
16
14
|
let on_tok = match parser.peek_clone() {
|
|
@@ -23,9 +21,17 @@ pub fn parse_on_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> S
|
|
|
23
21
|
let event_tok = match parser.peek_clone() {
|
|
24
22
|
Some(tok) if tok.kind == TokenKind::Identifier => tok,
|
|
25
23
|
Some(other) => {
|
|
26
|
-
return
|
|
24
|
+
return crate::core::parser::statement::error_from_token(
|
|
25
|
+
other,
|
|
26
|
+
"Expected event name after 'on'".to_string(),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
None => {
|
|
30
|
+
return crate::core::parser::statement::error_from_token(
|
|
31
|
+
on_tok,
|
|
32
|
+
"Expected event name after 'on'".to_string(),
|
|
33
|
+
);
|
|
27
34
|
}
|
|
28
|
-
None => return Statement::error(on_tok, "Expected event name after 'on'".to_string()),
|
|
29
35
|
};
|
|
30
36
|
let event_name = event_tok.lexeme.clone();
|
|
31
37
|
parser.advance();
|
|
@@ -68,7 +74,10 @@ pub fn parse_on_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> S
|
|
|
68
74
|
|
|
69
75
|
// Expect ':' then block
|
|
70
76
|
if parser.peek_kind() != Some(TokenKind::Colon) {
|
|
71
|
-
return
|
|
77
|
+
return crate::core::parser::statement::error_from_token(
|
|
78
|
+
event_tok,
|
|
79
|
+
"Expected ':' after event name".to_string(),
|
|
80
|
+
);
|
|
72
81
|
}
|
|
73
82
|
parser.advance(); // consume ':'
|
|
74
83
|
|
|
@@ -6,6 +6,7 @@ use crate::core::{
|
|
|
6
6
|
},
|
|
7
7
|
store::global::GlobalStore,
|
|
8
8
|
};
|
|
9
|
+
use devalang_types::Value;
|
|
9
10
|
|
|
10
11
|
pub fn parse_print_token(
|
|
11
12
|
parser: &mut Parser,
|
|
@@ -19,17 +20,13 @@ pub fn parse_print_token(
|
|
|
19
20
|
// Accept: print <identifier|string|number|expression>
|
|
20
21
|
let value = if collected.len() == 1 {
|
|
21
22
|
match collected[0].kind {
|
|
22
|
-
TokenKind::Identifier =>
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
TokenKind::String => {
|
|
26
|
-
crate::core::shared::value::Value::String(collected[0].lexeme.clone())
|
|
27
|
-
}
|
|
23
|
+
TokenKind::Identifier => Value::Identifier(collected[0].lexeme.clone()),
|
|
24
|
+
TokenKind::String => Value::String(collected[0].lexeme.clone()),
|
|
28
25
|
TokenKind::Number => {
|
|
29
26
|
let n = collected[0].lexeme.parse::<f32>().unwrap_or(0.0);
|
|
30
|
-
|
|
27
|
+
Value::Number(n)
|
|
31
28
|
}
|
|
32
|
-
_ =>
|
|
29
|
+
_ => Value::String(collected[0].lexeme.clone()),
|
|
33
30
|
}
|
|
34
31
|
} else {
|
|
35
32
|
// Join tokens with spaces to preserve readability for expressions/text
|
|
@@ -39,7 +36,7 @@ pub fn parse_print_token(
|
|
|
39
36
|
.map(|t| t.lexeme.clone())
|
|
40
37
|
.collect::<Vec<_>>()
|
|
41
38
|
.join(" ");
|
|
42
|
-
|
|
39
|
+
Value::String(text.trim().to_string())
|
|
43
40
|
};
|
|
44
41
|
|
|
45
42
|
Statement {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
use devalang_types::Value;
|
|
2
|
+
|
|
1
3
|
use crate::core::{
|
|
2
4
|
lexer::token::{Token, TokenKind},
|
|
3
5
|
parser::{
|
|
4
6
|
driver::Parser,
|
|
5
7
|
statement::{Statement, StatementKind},
|
|
6
8
|
},
|
|
7
|
-
shared::value::Value,
|
|
8
9
|
store::global::GlobalStore,
|
|
9
10
|
};
|
|
10
11
|
|
|
@@ -20,17 +21,23 @@ pub fn parse_sleep_token(
|
|
|
20
21
|
parser.advance();
|
|
21
22
|
token.lexeme.parse().unwrap_or(0.0)
|
|
22
23
|
} else {
|
|
23
|
-
return
|
|
24
|
+
return crate::core::parser::statement::error_from_token(
|
|
25
|
+
token,
|
|
26
|
+
"Expected number after 'sleep'".to_string(),
|
|
27
|
+
);
|
|
24
28
|
}
|
|
25
29
|
} else {
|
|
26
|
-
return
|
|
30
|
+
return crate::core::parser::statement::error_from_token(
|
|
31
|
+
current_token,
|
|
32
|
+
"Expected number after 'sleep'".to_string(),
|
|
33
|
+
);
|
|
27
34
|
};
|
|
28
35
|
|
|
29
|
-
|
|
36
|
+
Statement {
|
|
30
37
|
kind: StatementKind::Sleep,
|
|
31
38
|
value: Value::Number(duration),
|
|
32
39
|
indent: current_token.indent,
|
|
33
40
|
line: current_token.line,
|
|
34
41
|
column: current_token.column,
|
|
35
|
-
}
|
|
42
|
+
}
|
|
36
43
|
}
|
|
@@ -4,9 +4,9 @@ use crate::core::{
|
|
|
4
4
|
driver::Parser,
|
|
5
5
|
statement::{Statement, StatementKind},
|
|
6
6
|
},
|
|
7
|
-
shared::value::Value,
|
|
8
7
|
store::global::GlobalStore,
|
|
9
8
|
};
|
|
9
|
+
use devalang_types::Value;
|
|
10
10
|
|
|
11
11
|
pub fn parse_spawn_token(
|
|
12
12
|
parser: &mut Parser,
|
|
@@ -19,7 +19,7 @@ pub fn parse_spawn_token(
|
|
|
19
19
|
let name_token = match parser.peek_clone() {
|
|
20
20
|
Some(t) => t,
|
|
21
21
|
None => {
|
|
22
|
-
return
|
|
22
|
+
return crate::core::parser::statement::error_from_token(
|
|
23
23
|
current_token,
|
|
24
24
|
"Expected function name after 'spawn'".to_string(),
|
|
25
25
|
);
|
|
@@ -27,7 +27,7 @@ pub fn parse_spawn_token(
|
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
if name_token.kind != TokenKind::Identifier {
|
|
30
|
-
return
|
|
30
|
+
return crate::core::parser::statement::error_from_token(
|
|
31
31
|
name_token,
|
|
32
32
|
"Expected function name to be an identifier".to_string(),
|
|
33
33
|
);
|
|
@@ -68,7 +68,7 @@ pub fn parse_spawn_token(
|
|
|
68
68
|
parser.advance(); // skip comma
|
|
69
69
|
}
|
|
70
70
|
_ => {
|
|
71
|
-
return
|
|
71
|
+
return crate::core::parser::statement::error_from_token(
|
|
72
72
|
token,
|
|
73
73
|
"Unexpected token in spawn arguments".to_string(),
|
|
74
74
|
);
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
2
|
|
|
3
|
+
use devalang_types::Value;
|
|
4
|
+
|
|
3
5
|
use crate::core::{
|
|
4
6
|
lexer::token::Token,
|
|
5
7
|
parser::{
|
|
6
8
|
driver::Parser,
|
|
9
|
+
handler::dot::parse_dot_token,
|
|
7
10
|
statement::{Statement, StatementKind},
|
|
8
11
|
},
|
|
9
|
-
shared::value::Value,
|
|
10
12
|
store::global::GlobalStore,
|
|
11
13
|
};
|
|
12
14
|
|
|
@@ -21,14 +23,81 @@ pub fn parse_synth_token(
|
|
|
21
23
|
return Statement::unknown();
|
|
22
24
|
};
|
|
23
25
|
|
|
24
|
-
// Expect
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
// Expect a provider/waveform identifier (can be dotted: alias.synth)
|
|
27
|
+
// Also accept a dot-led entity by delegating to the dot parser (e.g. .module.export)
|
|
28
|
+
let synth_waveform = if let Some(first_token) = parser.peek_clone() {
|
|
29
|
+
use crate::core::lexer::token::TokenKind;
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
if first_token.kind == TokenKind::Dot {
|
|
32
|
+
// Parse dot-entity and extract its entity string
|
|
33
|
+
let dot_stmt = parse_dot_token(parser, _global_store);
|
|
34
|
+
// Extract entity if the parsed statement is a Trigger
|
|
35
|
+
match dot_stmt.kind {
|
|
36
|
+
StatementKind::Trigger { entity, .. } => entity,
|
|
37
|
+
_ => String::new(),
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
if first_token.kind != crate::core::lexer::token::TokenKind::Identifier
|
|
41
|
+
&& first_token.kind != crate::core::lexer::token::TokenKind::Number
|
|
42
|
+
&& first_token.kind != crate::core::lexer::token::TokenKind::Synth
|
|
43
|
+
{
|
|
44
|
+
return crate::core::parser::statement::error_from_token(
|
|
45
|
+
first_token.clone(),
|
|
46
|
+
"Expected identifier after 'synth'".to_string(),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
30
49
|
|
|
31
|
-
|
|
50
|
+
// Collect dotted parts on the same line
|
|
51
|
+
let mut parts: Vec<String> = Vec::new();
|
|
52
|
+
let current_line = first_token.line;
|
|
53
|
+
loop {
|
|
54
|
+
let Some(tok) = parser.peek_clone() else {
|
|
55
|
+
break;
|
|
56
|
+
};
|
|
57
|
+
if tok.line != current_line {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
match tok.kind {
|
|
61
|
+
crate::core::lexer::token::TokenKind::Identifier
|
|
62
|
+
| crate::core::lexer::token::TokenKind::Number
|
|
63
|
+
| crate::core::lexer::token::TokenKind::Synth => {
|
|
64
|
+
parts.push(tok.lexeme.clone());
|
|
65
|
+
parser.advance();
|
|
66
|
+
// If next isn't a dot on same line, stop
|
|
67
|
+
if let Some(next) = parser.peek_clone() {
|
|
68
|
+
if !(next.line == current_line
|
|
69
|
+
&& next.kind == crate::core::lexer::token::TokenKind::Dot)
|
|
70
|
+
{
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
crate::core::lexer::token::TokenKind::Dot => {
|
|
78
|
+
parser.advance();
|
|
79
|
+
}
|
|
80
|
+
_ => break,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
parts.join(".")
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
return crate::core::parser::statement::error_from_token(
|
|
88
|
+
synth_token,
|
|
89
|
+
"Expected identifier after 'synth'".to_string(),
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Skip formatting before optional parameters map
|
|
94
|
+
while parser.check_token(crate::core::lexer::token::TokenKind::Newline)
|
|
95
|
+
|| parser.check_token(crate::core::lexer::token::TokenKind::Indent)
|
|
96
|
+
|| parser.check_token(crate::core::lexer::token::TokenKind::Dedent)
|
|
97
|
+
|| parser.check_token(crate::core::lexer::token::TokenKind::Whitespace)
|
|
98
|
+
{
|
|
99
|
+
parser.advance();
|
|
100
|
+
}
|
|
32
101
|
|
|
33
102
|
// Expect synth optional parameters map
|
|
34
103
|
let parameters = if let Some(params) = parser.parse_map_value() {
|
|
@@ -36,7 +105,7 @@ pub fn parse_synth_token(
|
|
|
36
105
|
if let Value::Map(map) = params {
|
|
37
106
|
map
|
|
38
107
|
} else {
|
|
39
|
-
return
|
|
108
|
+
return crate::core::parser::statement::error_from_token(
|
|
40
109
|
synth_token,
|
|
41
110
|
"Expected a map for synth parameters".to_string(),
|
|
42
111
|
);
|
|
@@ -53,7 +122,8 @@ pub fn parse_synth_token(
|
|
|
53
122
|
(
|
|
54
123
|
"value".to_string(),
|
|
55
124
|
Value::Map(HashMap::from([
|
|
56
|
-
|
|
125
|
+
// Store waveform as identifier to allow resolution from variables/exports
|
|
126
|
+
("waveform".to_string(), Value::Identifier(synth_waveform)),
|
|
57
127
|
("parameters".to_string(), Value::Map(parameters)),
|
|
58
128
|
])),
|
|
59
129
|
),
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
use devalang_types::Value;
|
|
2
|
+
|
|
1
3
|
use crate::core::{
|
|
2
4
|
lexer::token::TokenKind,
|
|
3
5
|
parser::{
|
|
4
6
|
driver::Parser,
|
|
5
7
|
statement::{Statement, StatementKind},
|
|
6
8
|
},
|
|
7
|
-
shared::value::Value,
|
|
8
9
|
store::global::GlobalStore,
|
|
9
10
|
};
|
|
10
11
|
|
|
@@ -20,7 +21,12 @@ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) ->
|
|
|
20
21
|
|
|
21
22
|
// Peek next to decide
|
|
22
23
|
let Some(next_token) = parser.peek_clone() else {
|
|
23
|
-
return Statement::
|
|
24
|
+
return Statement::error_with_pos(
|
|
25
|
+
loop_token.indent,
|
|
26
|
+
loop_token.line,
|
|
27
|
+
loop_token.column,
|
|
28
|
+
"Expected iterator after loop/for".to_string(),
|
|
29
|
+
);
|
|
24
30
|
};
|
|
25
31
|
|
|
26
32
|
// Try to detect 'for <ident> in [array]:' form
|
|
@@ -66,26 +72,35 @@ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) ->
|
|
|
66
72
|
Value::Identifier(tok.lexeme.clone())
|
|
67
73
|
}
|
|
68
74
|
_ => {
|
|
69
|
-
return Statement::
|
|
70
|
-
loop_token,
|
|
75
|
+
return Statement::error_with_pos(
|
|
76
|
+
loop_token.indent,
|
|
77
|
+
loop_token.line,
|
|
78
|
+
loop_token.column,
|
|
71
79
|
"Expected array, number, string or identifier after 'in'".to_string(),
|
|
72
80
|
);
|
|
73
81
|
}
|
|
74
82
|
}
|
|
75
83
|
} else {
|
|
76
|
-
return Statement::
|
|
77
|
-
loop_token,
|
|
84
|
+
return Statement::error_with_pos(
|
|
85
|
+
loop_token.indent,
|
|
86
|
+
loop_token.line,
|
|
87
|
+
loop_token.column,
|
|
78
88
|
"Expected array, number, string or identifier after 'in'".to_string(),
|
|
79
89
|
);
|
|
80
90
|
};
|
|
81
91
|
|
|
82
92
|
// Expect ':'
|
|
83
93
|
if !parser.match_token(TokenKind::Colon) {
|
|
84
|
-
return Statement::
|
|
94
|
+
return Statement::error_with_pos(
|
|
95
|
+
loop_token.indent,
|
|
96
|
+
loop_token.line,
|
|
97
|
+
loop_token.column,
|
|
98
|
+
"Expected ':' after foreach header".to_string(),
|
|
99
|
+
);
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
let tokens =
|
|
88
|
-
parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
|
|
103
|
+
parser.collect_until(|t| (t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF));
|
|
89
104
|
let loop_body = parser.parse_block(tokens.clone(), global_store);
|
|
90
105
|
if let Some(token) = parser.peek() {
|
|
91
106
|
if token.kind == TokenKind::Dedent {
|
|
@@ -109,8 +124,10 @@ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) ->
|
|
|
109
124
|
|
|
110
125
|
// Fallback to legacy: loop <count>:
|
|
111
126
|
let Some(iterator_token) = parser.peek_clone() else {
|
|
112
|
-
return Statement::
|
|
113
|
-
loop_token,
|
|
127
|
+
return Statement::error_with_pos(
|
|
128
|
+
loop_token.indent,
|
|
129
|
+
loop_token.line,
|
|
130
|
+
loop_token.column,
|
|
114
131
|
"Expected number or identifier after 'loop'".to_string(),
|
|
115
132
|
);
|
|
116
133
|
};
|
|
@@ -133,8 +150,10 @@ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) ->
|
|
|
133
150
|
Value::String(s)
|
|
134
151
|
}
|
|
135
152
|
_ => {
|
|
136
|
-
return Statement::
|
|
137
|
-
iterator_token.clone(),
|
|
153
|
+
return Statement::error_with_pos(
|
|
154
|
+
iterator_token.clone().indent,
|
|
155
|
+
iterator_token.clone().line,
|
|
156
|
+
iterator_token.clone().column,
|
|
138
157
|
"Expected a number, string or identifier as loop count".to_string(),
|
|
139
158
|
);
|
|
140
159
|
}
|
|
@@ -145,10 +164,16 @@ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) ->
|
|
|
145
164
|
"Expected ':' after loop count, got {:?}",
|
|
146
165
|
parser.peek_kind()
|
|
147
166
|
);
|
|
148
|
-
return Statement::
|
|
167
|
+
return Statement::error_with_pos(
|
|
168
|
+
loop_token.clone().indent,
|
|
169
|
+
loop_token.clone().line,
|
|
170
|
+
loop_token.clone().column,
|
|
171
|
+
message,
|
|
172
|
+
);
|
|
149
173
|
}
|
|
150
174
|
|
|
151
|
-
let tokens =
|
|
175
|
+
let tokens =
|
|
176
|
+
parser.collect_until(|t| (t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF));
|
|
152
177
|
let loop_body = parser.parse_block(tokens.clone(), global_store);
|
|
153
178
|
if let Some(token) = parser.peek() {
|
|
154
179
|
if token.kind == TokenKind::Dedent {
|
|
@@ -4,9 +4,9 @@ use crate::core::{
|
|
|
4
4
|
driver::Parser,
|
|
5
5
|
statement::{Statement, StatementKind},
|
|
6
6
|
},
|
|
7
|
-
shared::value::Value,
|
|
8
7
|
store::global::GlobalStore,
|
|
9
8
|
};
|
|
9
|
+
use devalang_types::Value;
|
|
10
10
|
|
|
11
11
|
pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
|
|
12
12
|
parser.advance(); // consume 'bpm'
|
|
@@ -17,8 +17,10 @@ pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -
|
|
|
17
17
|
|
|
18
18
|
// Expect a number or identifier
|
|
19
19
|
let Some(value_token) = parser.peek_clone() else {
|
|
20
|
-
return Statement::
|
|
21
|
-
tempo_token,
|
|
20
|
+
return Statement::error_with_pos(
|
|
21
|
+
tempo_token.indent,
|
|
22
|
+
tempo_token.line,
|
|
23
|
+
tempo_token.column,
|
|
22
24
|
"Expected a number or identifier after 'bpm'".to_string(),
|
|
23
25
|
);
|
|
24
26
|
};
|
|
@@ -33,8 +35,10 @@ pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -
|
|
|
33
35
|
Value::Identifier(value_token.lexeme.clone())
|
|
34
36
|
}
|
|
35
37
|
_ => {
|
|
36
|
-
return Statement::
|
|
37
|
-
value_token.
|
|
38
|
+
return Statement::error_with_pos(
|
|
39
|
+
value_token.indent,
|
|
40
|
+
value_token.line,
|
|
41
|
+
value_token.column,
|
|
38
42
|
format!(
|
|
39
43
|
"Expected a number or identifier after 'bpm', got {:?}",
|
|
40
44
|
value_token.kind
|
package/rust/core/parser/mod.rs
CHANGED
|
@@ -1,142 +1,11 @@
|
|
|
1
|
-
use crate::core::
|
|
2
|
-
lexer::token::Token,
|
|
3
|
-
shared::{duration::Duration, value::Value},
|
|
4
|
-
};
|
|
5
|
-
use serde::{Deserialize, Serialize};
|
|
1
|
+
use crate::core::lexer::token::Token;
|
|
6
2
|
|
|
7
|
-
|
|
8
|
-
pub struct Statement {
|
|
9
|
-
pub kind: StatementKind,
|
|
10
|
-
pub value: Value,
|
|
11
|
-
pub indent: usize,
|
|
12
|
-
pub line: usize,
|
|
13
|
-
pub column: usize,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
impl Statement {
|
|
17
|
-
pub fn unknown() -> Self {
|
|
18
|
-
Statement {
|
|
19
|
-
kind: StatementKind::Unknown,
|
|
20
|
-
value: Value::Null,
|
|
21
|
-
indent: 0,
|
|
22
|
-
line: 0,
|
|
23
|
-
column: 0,
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
pub fn unknown_from_token(token: &Token) -> Self {
|
|
28
|
-
Statement {
|
|
29
|
-
kind: StatementKind::Unknown,
|
|
30
|
-
value: Value::Null,
|
|
31
|
-
indent: token.indent,
|
|
32
|
-
line: token.line,
|
|
33
|
-
column: token.column,
|
|
34
|
-
}
|
|
35
|
-
}
|
|
3
|
+
pub use devalang_types::{Duration, Statement, StatementKind, Value};
|
|
36
4
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
kind: StatementKind::Error { message },
|
|
40
|
-
value: Value::Null,
|
|
41
|
-
indent: token.indent,
|
|
42
|
-
line: token.line,
|
|
43
|
-
column: token.column,
|
|
44
|
-
}
|
|
45
|
-
}
|
|
5
|
+
pub fn unknown_from_token(token: &Token) -> Statement {
|
|
6
|
+
Statement::unknown_with_pos(token.indent, token.line, token.column)
|
|
46
7
|
}
|
|
47
8
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// ───── Core Instructions ─────
|
|
51
|
-
Tempo,
|
|
52
|
-
Bank {
|
|
53
|
-
alias: Option<String>,
|
|
54
|
-
},
|
|
55
|
-
Print,
|
|
56
|
-
Load {
|
|
57
|
-
source: String,
|
|
58
|
-
alias: String,
|
|
59
|
-
},
|
|
60
|
-
Use {
|
|
61
|
-
name: String,
|
|
62
|
-
alias: Option<String>,
|
|
63
|
-
},
|
|
64
|
-
Let {
|
|
65
|
-
name: String,
|
|
66
|
-
},
|
|
67
|
-
Automate {
|
|
68
|
-
target: String,
|
|
69
|
-
},
|
|
70
|
-
ArrowCall {
|
|
71
|
-
target: String,
|
|
72
|
-
method: String,
|
|
73
|
-
args: Vec<Value>,
|
|
74
|
-
},
|
|
75
|
-
Function {
|
|
76
|
-
name: String,
|
|
77
|
-
parameters: Vec<String>,
|
|
78
|
-
body: Vec<Statement>,
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
// ───── Instruments ─────
|
|
82
|
-
Synth,
|
|
83
|
-
|
|
84
|
-
// ───── Playback / Scheduling ─────
|
|
85
|
-
Trigger {
|
|
86
|
-
entity: String,
|
|
87
|
-
duration: Duration,
|
|
88
|
-
effects: Option<Value>,
|
|
89
|
-
},
|
|
90
|
-
Sleep,
|
|
91
|
-
Call {
|
|
92
|
-
name: String,
|
|
93
|
-
args: Vec<Value>,
|
|
94
|
-
},
|
|
95
|
-
Spawn {
|
|
96
|
-
name: String,
|
|
97
|
-
args: Vec<Value>,
|
|
98
|
-
},
|
|
99
|
-
Loop,
|
|
100
|
-
|
|
101
|
-
// ───── Structure & Logic ─────
|
|
102
|
-
Group,
|
|
103
|
-
|
|
104
|
-
// ───── Module System ─────
|
|
105
|
-
Include(String),
|
|
106
|
-
Export {
|
|
107
|
-
names: Vec<String>,
|
|
108
|
-
source: String,
|
|
109
|
-
},
|
|
110
|
-
Import {
|
|
111
|
-
names: Vec<String>,
|
|
112
|
-
source: String,
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
// ───── Conditions ─────
|
|
116
|
-
If,
|
|
117
|
-
Else,
|
|
118
|
-
ElseIf,
|
|
119
|
-
|
|
120
|
-
// ───── Internal / Utility ─────
|
|
121
|
-
Comment,
|
|
122
|
-
Indent,
|
|
123
|
-
Dedent,
|
|
124
|
-
NewLine,
|
|
125
|
-
|
|
126
|
-
// ───── Events / Live coding ─────
|
|
127
|
-
On {
|
|
128
|
-
event: String,
|
|
129
|
-
args: Option<Vec<Value>>,
|
|
130
|
-
body: Vec<Statement>,
|
|
131
|
-
},
|
|
132
|
-
Emit {
|
|
133
|
-
event: String,
|
|
134
|
-
payload: Option<Value>,
|
|
135
|
-
},
|
|
136
|
-
|
|
137
|
-
// ───── Error Handling ─────
|
|
138
|
-
Unknown,
|
|
139
|
-
Error {
|
|
140
|
-
message: String,
|
|
141
|
-
},
|
|
9
|
+
pub fn error_from_token(token: Token, message: String) -> Statement {
|
|
10
|
+
Statement::error_with_pos(token.indent, token.line, token.column, message)
|
|
142
11
|
}
|