@devaloop/devalang 0.0.1-alpha.7 → 0.0.1-alpha.9
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.toml +1 -1
- package/README.md +31 -16
- package/docs/CHANGELOG.md +49 -2
- package/docs/ROADMAP.md +2 -2
- package/docs/SYNTAX.md +41 -7
- package/docs/TODO.md +3 -3
- package/examples/condition.deva +20 -0
- package/examples/group.deva +3 -3
- package/examples/index.deva +9 -8
- package/examples/loop.deva +10 -8
- package/examples/synth.deva +14 -0
- package/examples/variables.deva +2 -2
- package/out-tsc/bin/devalang.exe +0 -0
- package/out-tsc/scripts/version/fetch.js +1 -5
- package/package.json +1 -1
- package/project-version.json +3 -3
- package/rust/cli/build.rs +6 -1
- package/rust/core/audio/engine.rs +89 -12
- package/rust/core/audio/evaluator.rs +31 -0
- package/rust/core/audio/interpreter/arrow_call.rs +129 -0
- package/rust/core/audio/interpreter/call.rs +64 -0
- package/rust/core/audio/interpreter/condition.rs +69 -0
- package/rust/core/audio/interpreter/driver.rs +216 -0
- package/rust/core/audio/interpreter/let_.rs +19 -0
- package/rust/core/audio/interpreter/load.rs +18 -0
- package/rust/core/audio/interpreter/loop_.rs +67 -0
- package/rust/core/audio/interpreter/mod.rs +12 -0
- package/rust/core/audio/interpreter/sleep.rs +36 -0
- package/rust/core/audio/interpreter/spawn.rs +66 -0
- package/rust/core/audio/interpreter/tempo.rs +16 -0
- package/rust/core/audio/interpreter/trigger.rs +69 -0
- package/rust/core/audio/loader/mod.rs +1 -0
- package/rust/core/audio/{loader.rs → loader/trigger.rs} +3 -1
- package/rust/core/audio/mod.rs +2 -1
- package/rust/core/audio/renderer.rs +54 -0
- package/rust/core/builder/mod.rs +1 -1
- package/rust/core/debugger/lexer.rs +1 -1
- package/rust/core/debugger/mod.rs +1 -0
- package/rust/core/debugger/store.rs +25 -0
- package/rust/core/error/mod.rs +1 -1
- package/rust/core/lexer/handler/arrow.rs +31 -0
- package/rust/core/lexer/handler/driver.rs +226 -0
- package/rust/core/lexer/handler/identifier.rs +3 -0
- package/rust/core/lexer/handler/mod.rs +4 -227
- package/rust/core/lexer/handler/operator.rs +44 -0
- package/rust/core/lexer/mod.rs +25 -4
- package/rust/core/lexer/token.rs +40 -9
- package/rust/core/parser/driver.rs +331 -0
- package/rust/core/parser/handler/arrow_call.rs +126 -0
- package/rust/core/parser/handler/at.rs +3 -7
- package/rust/core/parser/handler/bank.rs +5 -2
- package/rust/core/parser/handler/condition.rs +74 -0
- package/rust/core/parser/handler/dot.rs +1 -1
- package/rust/core/parser/handler/identifier/call.rs +41 -0
- package/rust/core/parser/handler/identifier/group.rs +75 -0
- package/rust/core/parser/handler/identifier/let_.rs +133 -0
- package/rust/core/parser/handler/identifier/mod.rs +51 -0
- package/rust/core/parser/handler/identifier/sleep.rs +33 -0
- package/rust/core/parser/handler/identifier/spawn.rs +41 -0
- package/rust/core/parser/handler/identifier/synth.rs +65 -0
- package/rust/core/parser/handler/loop_.rs +25 -19
- package/rust/core/parser/handler/mod.rs +3 -1
- package/rust/core/parser/handler/tempo.rs +1 -1
- package/rust/core/parser/mod.rs +3 -237
- package/rust/core/parser/statement.rs +36 -35
- package/rust/core/preprocessor/loader.rs +64 -49
- package/rust/core/preprocessor/module.rs +3 -6
- package/rust/core/preprocessor/processor.rs +13 -4
- package/rust/core/preprocessor/resolver/call.rs +123 -0
- package/rust/core/preprocessor/resolver/condition.rs +92 -0
- package/rust/core/preprocessor/resolver/driver.rs +227 -0
- package/rust/core/preprocessor/resolver/group.rs +35 -87
- package/rust/core/preprocessor/resolver/let_.rs +31 -0
- package/rust/core/preprocessor/resolver/loop_.rs +62 -116
- package/rust/core/preprocessor/resolver/mod.rs +9 -153
- package/rust/core/preprocessor/resolver/spawn.rs +58 -0
- package/rust/core/preprocessor/resolver/synth.rs +50 -0
- package/rust/core/preprocessor/resolver/trigger.rs +51 -50
- package/rust/core/preprocessor/resolver/value.rs +78 -0
- package/rust/core/utils/path.rs +17 -32
- package/rust/core/utils/validation.rs +30 -28
- package/typescript/scripts/version/fetch.ts +1 -6
- package/rust/core/audio/interpreter.rs +0 -317
- package/rust/core/audio/render.rs +0 -53
- package/rust/core/lexer/handler/equal.rs +0 -32
- package/rust/core/parser/handler/identifier.rs +0 -260
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::core::{
|
|
4
|
+
lexer::token::{ Token, TokenKind },
|
|
5
|
+
parser::{
|
|
6
|
+
driver::Parser,
|
|
7
|
+
handler::identifier::synth::parse_synth_token,
|
|
8
|
+
statement::{ Statement, StatementKind },
|
|
9
|
+
},
|
|
10
|
+
shared::value::Value,
|
|
11
|
+
store::global::GlobalStore,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
pub fn parse_let_token(
|
|
15
|
+
parser: &mut Parser,
|
|
16
|
+
current_token: Token,
|
|
17
|
+
global_store: &mut GlobalStore
|
|
18
|
+
) -> Statement {
|
|
19
|
+
parser.advance(); // consume "let"
|
|
20
|
+
|
|
21
|
+
let identifier = if let Some(token) = parser.peek_clone() {
|
|
22
|
+
if token.kind == TokenKind::Identifier {
|
|
23
|
+
parser.advance();
|
|
24
|
+
token.lexeme.clone()
|
|
25
|
+
} else {
|
|
26
|
+
return Statement::error(token, "Expected identifier after 'let'".to_string());
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
return Statement::error(current_token, "Expected identifier after 'let'".to_string());
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
if !parser.match_token(TokenKind::Equals) {
|
|
33
|
+
return Statement::error(current_token, "Expected '=' after identifier".to_string());
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if let Some(token) = parser.peek_clone() {
|
|
37
|
+
if token.kind == TokenKind::Synth {
|
|
38
|
+
let synth_stmt = parse_synth_token(parser, token.clone(), global_store);
|
|
39
|
+
|
|
40
|
+
return Statement {
|
|
41
|
+
kind: StatementKind::Let { name: identifier },
|
|
42
|
+
value: synth_stmt.value,
|
|
43
|
+
indent: current_token.indent,
|
|
44
|
+
line: current_token.line,
|
|
45
|
+
column: current_token.column,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let value = match parser.peek_clone() {
|
|
51
|
+
Some(token) if token.kind == TokenKind::Identifier => {
|
|
52
|
+
parser.advance();
|
|
53
|
+
Value::Identifier(token.lexeme.clone())
|
|
54
|
+
}
|
|
55
|
+
Some(token) if token.kind == TokenKind::String => {
|
|
56
|
+
parser.advance();
|
|
57
|
+
Value::String(token.lexeme.clone())
|
|
58
|
+
}
|
|
59
|
+
Some(token) if token.kind == TokenKind::Number => {
|
|
60
|
+
parser.advance();
|
|
61
|
+
Value::Number(token.lexeme.parse().unwrap_or(0.0))
|
|
62
|
+
}
|
|
63
|
+
Some(token) if token.kind == TokenKind::Boolean => {
|
|
64
|
+
parser.advance();
|
|
65
|
+
Value::Boolean(token.lexeme.parse().unwrap_or(false))
|
|
66
|
+
}
|
|
67
|
+
Some(token) if token.kind == TokenKind::LBrace => {
|
|
68
|
+
parser.advance(); // consume '{'
|
|
69
|
+
let mut map = HashMap::new();
|
|
70
|
+
|
|
71
|
+
while let Some(key_token) = parser.peek_clone() {
|
|
72
|
+
if key_token.kind == TokenKind::RBrace {
|
|
73
|
+
parser.advance(); // consume '}'
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if key_token.kind != TokenKind::Identifier {
|
|
78
|
+
return Statement::error(token, "Expected key identifier in map".to_string());
|
|
79
|
+
}
|
|
80
|
+
parser.advance();
|
|
81
|
+
let key = key_token.lexeme.clone();
|
|
82
|
+
|
|
83
|
+
if !parser.match_token(TokenKind::Colon) {
|
|
84
|
+
let message = format!("Expected ':' after key '{}'", key);
|
|
85
|
+
return Statement::error(token, message);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let val = match parser.peek_clone() {
|
|
89
|
+
Some(t) if t.kind == TokenKind::Number => {
|
|
90
|
+
parser.advance();
|
|
91
|
+
Value::Number(t.lexeme.parse().unwrap_or(0.0))
|
|
92
|
+
}
|
|
93
|
+
Some(t) if t.kind == TokenKind::String => {
|
|
94
|
+
parser.advance();
|
|
95
|
+
Value::String(t.lexeme.clone())
|
|
96
|
+
}
|
|
97
|
+
Some(t) if t.kind == TokenKind::Identifier => {
|
|
98
|
+
parser.advance();
|
|
99
|
+
Value::Identifier(t.lexeme.clone())
|
|
100
|
+
}
|
|
101
|
+
_ => Value::Null,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if val == Value::Null {
|
|
105
|
+
let message = format!("Invalid value for key '{}'", key);
|
|
106
|
+
return Statement::error(token, message);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
map.insert(key, val);
|
|
110
|
+
|
|
111
|
+
if let Some(t) = parser.peek() {
|
|
112
|
+
if t.kind == TokenKind::Comma {
|
|
113
|
+
parser.advance(); // skip comma
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
Value::Map(map)
|
|
119
|
+
}
|
|
120
|
+
other => {
|
|
121
|
+
let message = format!("Unexpected value token in let: {:?}", other);
|
|
122
|
+
return Statement::error(current_token, message);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
Statement {
|
|
127
|
+
kind: StatementKind::Let { name: identifier },
|
|
128
|
+
value,
|
|
129
|
+
indent: current_token.indent,
|
|
130
|
+
line: current_token.line,
|
|
131
|
+
column: current_token.column,
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
pub mod let_;
|
|
2
|
+
pub mod group;
|
|
3
|
+
pub mod call;
|
|
4
|
+
pub mod spawn;
|
|
5
|
+
pub mod sleep;
|
|
6
|
+
pub mod synth;
|
|
7
|
+
|
|
8
|
+
use crate::core::{
|
|
9
|
+
parser::{
|
|
10
|
+
driver::Parser,
|
|
11
|
+
handler::{
|
|
12
|
+
identifier::{
|
|
13
|
+
call::parse_call_token,
|
|
14
|
+
group::parse_group_token,
|
|
15
|
+
let_::parse_let_token,
|
|
16
|
+
sleep::parse_sleep_token,
|
|
17
|
+
spawn::parse_spawn_token,
|
|
18
|
+
synth::parse_synth_token
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
statement::Statement,
|
|
22
|
+
},
|
|
23
|
+
store::global::GlobalStore,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
pub fn parse_identifier_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
|
|
27
|
+
let Some(current_token) = parser.peek_clone() else {
|
|
28
|
+
return Statement::unknown();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
let current_token_clone = current_token.clone();
|
|
32
|
+
let current_token_lexeme = current_token_clone.lexeme.clone();
|
|
33
|
+
|
|
34
|
+
let statement = match current_token_lexeme.as_str() {
|
|
35
|
+
"let" => parse_let_token(parser, current_token_clone, global_store),
|
|
36
|
+
"group" => parse_group_token(parser, current_token_clone, global_store),
|
|
37
|
+
"call" => parse_call_token(parser, current_token_clone, global_store),
|
|
38
|
+
"spawn" => parse_spawn_token(parser, current_token_clone, global_store),
|
|
39
|
+
"sleep" => parse_sleep_token(parser, current_token_clone, global_store),
|
|
40
|
+
"synth" => parse_synth_token(parser, current_token_clone, global_store),
|
|
41
|
+
_ => {
|
|
42
|
+
parser.advance(); // consume identifier
|
|
43
|
+
|
|
44
|
+
println!("Unrecognized identifier: {}", current_token_lexeme);
|
|
45
|
+
|
|
46
|
+
return Statement::error(current_token_clone, "Unexpected identifier".to_string());
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return statement;
|
|
51
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::token::{ Token, TokenKind },
|
|
3
|
+
parser::{ statement::{ Statement, StatementKind }, driver::Parser },
|
|
4
|
+
shared::value::Value,
|
|
5
|
+
store::global::GlobalStore,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
pub fn parse_sleep_token(
|
|
9
|
+
parser: &mut Parser,
|
|
10
|
+
current_token: Token,
|
|
11
|
+
global_store: &mut GlobalStore
|
|
12
|
+
) -> Statement {
|
|
13
|
+
parser.advance(); // consume "sleep"
|
|
14
|
+
|
|
15
|
+
let duration = if let Some(token) = parser.peek_clone() {
|
|
16
|
+
if token.kind == TokenKind::Number {
|
|
17
|
+
parser.advance();
|
|
18
|
+
token.lexeme.parse().unwrap_or(0.0)
|
|
19
|
+
} else {
|
|
20
|
+
return Statement::error(token, "Expected number after 'sleep'".to_string());
|
|
21
|
+
}
|
|
22
|
+
} else {
|
|
23
|
+
return Statement::error(current_token, "Expected number after 'sleep'".to_string());
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return Statement {
|
|
27
|
+
kind: StatementKind::Sleep,
|
|
28
|
+
value: Value::Number(duration),
|
|
29
|
+
indent: current_token.indent,
|
|
30
|
+
line: current_token.line,
|
|
31
|
+
column: current_token.column,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::token::{ Token, TokenKind },
|
|
3
|
+
parser::{ statement::{ Statement, StatementKind }, driver::Parser },
|
|
4
|
+
shared::value::Value,
|
|
5
|
+
store::global::GlobalStore,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
pub fn parse_spawn_token(
|
|
9
|
+
parser: &mut Parser,
|
|
10
|
+
current_token: Token,
|
|
11
|
+
global_store: &mut GlobalStore
|
|
12
|
+
) -> Statement {
|
|
13
|
+
parser.advance(); // consume "spawn"
|
|
14
|
+
|
|
15
|
+
let value = if let Some(token) = parser.peek_clone() {
|
|
16
|
+
parser.advance();
|
|
17
|
+
match token.kind {
|
|
18
|
+
TokenKind::Identifier => Value::Identifier(token.lexeme.clone()),
|
|
19
|
+
TokenKind::String => Value::String(token.lexeme.clone()),
|
|
20
|
+
_ => {
|
|
21
|
+
return Statement::error(
|
|
22
|
+
token,
|
|
23
|
+
"Expected identifier or string after 'spawn'".to_string()
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
return Statement::error(
|
|
29
|
+
current_token,
|
|
30
|
+
"Expected identifier or string after 'spawn'".to_string()
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return Statement {
|
|
35
|
+
kind: StatementKind::Spawn,
|
|
36
|
+
value,
|
|
37
|
+
indent: current_token.indent,
|
|
38
|
+
line: current_token.line,
|
|
39
|
+
column: current_token.column,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::core::{
|
|
4
|
+
lexer::token::{ Token, TokenKind },
|
|
5
|
+
parser::{ driver::Parser, statement::{ Statement, StatementKind } },
|
|
6
|
+
shared::value::Value,
|
|
7
|
+
store::global::GlobalStore,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
pub fn parse_synth_token(
|
|
11
|
+
parser: &mut Parser,
|
|
12
|
+
current_token: Token,
|
|
13
|
+
global_store: &mut GlobalStore
|
|
14
|
+
) -> Statement {
|
|
15
|
+
parser.advance(); // consume 'synth'
|
|
16
|
+
|
|
17
|
+
let Some(synth_token) = parser.previous_clone() else {
|
|
18
|
+
return Statement::unknown();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Expect an identifier (synth waveform)
|
|
22
|
+
let Some(identifier_token) = parser.peek_clone() else {
|
|
23
|
+
return Statement::error(synth_token, "Expected identifier after 'synth'".to_string());
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
let synth_waveform = identifier_token.lexeme.clone();
|
|
27
|
+
|
|
28
|
+
parser.advance(); // consume identifier
|
|
29
|
+
|
|
30
|
+
// Expect synth optional parameters map
|
|
31
|
+
let mut parameters = HashMap::new();
|
|
32
|
+
|
|
33
|
+
if let Some(params) = parser.parse_map_value() {
|
|
34
|
+
// If parameters are provided, we expect a map
|
|
35
|
+
if let Value::Map(map) = params {
|
|
36
|
+
parameters = map;
|
|
37
|
+
} else {
|
|
38
|
+
return Statement::error(synth_token, "Expected a map for synth parameters".to_string());
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
// If no parameters are provided, we can still create the statement with an empty map
|
|
42
|
+
parameters = HashMap::new();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
Statement {
|
|
46
|
+
kind: StatementKind::Synth,
|
|
47
|
+
value: Value::Map(
|
|
48
|
+
HashMap::from([
|
|
49
|
+
("entity".to_string(), Value::String("synth".to_string())),
|
|
50
|
+
(
|
|
51
|
+
"value".to_string(),
|
|
52
|
+
Value::Map(
|
|
53
|
+
HashMap::from([
|
|
54
|
+
("waveform".to_string(), Value::String(synth_waveform)),
|
|
55
|
+
("parameters".to_string(), Value::Map(parameters)),
|
|
56
|
+
])
|
|
57
|
+
),
|
|
58
|
+
),
|
|
59
|
+
])
|
|
60
|
+
),
|
|
61
|
+
indent: synth_token.indent,
|
|
62
|
+
line: synth_token.line,
|
|
63
|
+
column: synth_token.column,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -2,58 +2,64 @@ use std::collections::HashMap;
|
|
|
2
2
|
|
|
3
3
|
use crate::core::{
|
|
4
4
|
lexer::{ token::TokenKind },
|
|
5
|
-
parser::{ statement::{ Statement, StatementKind }, Parser },
|
|
5
|
+
parser::{ statement::{ Statement, StatementKind }, driver::Parser },
|
|
6
6
|
shared::value::Value,
|
|
7
7
|
store::global::GlobalStore,
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
|
|
11
11
|
parser.advance(); // consume 'loop'
|
|
12
|
-
|
|
13
12
|
let Some(loop_token) = parser.previous_clone() else {
|
|
14
13
|
return Statement::unknown();
|
|
15
14
|
};
|
|
16
15
|
|
|
17
|
-
// Expect an identifier (iterator)
|
|
18
16
|
let Some(iterator_token) = parser.peek_clone() else {
|
|
19
|
-
return Statement::error(loop_token, "Expected identifier after 'loop'".to_string());
|
|
17
|
+
return Statement::error(loop_token, "Expected number or identifier after 'loop'".to_string());
|
|
20
18
|
};
|
|
21
19
|
|
|
22
|
-
let
|
|
23
|
-
|
|
20
|
+
let iterator_value = match iterator_token.kind {
|
|
21
|
+
TokenKind::Number => {
|
|
22
|
+
let val = iterator_token.lexeme.parse::<f32>().unwrap_or(1.0);
|
|
23
|
+
parser.advance();
|
|
24
|
+
Value::Number(val)
|
|
25
|
+
}
|
|
26
|
+
TokenKind::Identifier => {
|
|
27
|
+
let val = iterator_token.lexeme.clone();
|
|
28
|
+
parser.advance();
|
|
29
|
+
Value::Identifier(val)
|
|
30
|
+
}
|
|
31
|
+
_ => {
|
|
32
|
+
return Statement::error(
|
|
33
|
+
iterator_token.clone(),
|
|
34
|
+
"Expected a number or identifier as loop count".to_string()
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
24
38
|
|
|
25
39
|
// Expect colon
|
|
26
40
|
let Some(colon_token) = parser.peek_clone() else {
|
|
27
|
-
return Statement::error(iterator_token.clone(), "Expected ':' after
|
|
41
|
+
return Statement::error(iterator_token.clone(), "Expected ':' after loop count".to_string());
|
|
28
42
|
};
|
|
29
43
|
|
|
30
44
|
if colon_token.kind != TokenKind::Colon {
|
|
31
|
-
let message = format!("Expected ':' after
|
|
45
|
+
let message = format!("Expected ':' after loop count, got {:?}", colon_token.kind);
|
|
32
46
|
return Statement::error(colon_token.clone(), message);
|
|
33
47
|
}
|
|
34
48
|
|
|
35
49
|
parser.advance(); // consume ':'
|
|
36
50
|
|
|
37
|
-
// Collect
|
|
38
|
-
let tokens = parser.collect_until(
|
|
39
|
-
|t| (t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF)
|
|
40
|
-
);
|
|
51
|
+
// Collect body
|
|
52
|
+
let tokens = parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
|
|
41
53
|
let loop_body = parser.parse_block(tokens.clone(), global_store);
|
|
42
54
|
|
|
43
|
-
// Peek for dedent
|
|
44
55
|
if let Some(token) = parser.peek() {
|
|
45
56
|
if token.kind == TokenKind::Dedent {
|
|
46
57
|
parser.advance();
|
|
47
|
-
} else {
|
|
48
|
-
// Unexpected token after loop body
|
|
49
58
|
}
|
|
50
|
-
} else {
|
|
51
|
-
// EOF or unexpected end of input
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
let mut value_map = HashMap::new();
|
|
55
|
-
|
|
56
|
-
value_map.insert("iterator".to_string(), Value::Identifier(iterator_name));
|
|
62
|
+
value_map.insert("iterator".to_string(), iterator_value);
|
|
57
63
|
value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
|
|
58
64
|
|
|
59
65
|
Statement {
|
package/rust/core/parser/mod.rs
CHANGED
|
@@ -1,238 +1,4 @@
|
|
|
1
|
-
pub mod
|
|
2
|
-
pub mod handler;
|
|
3
|
-
|
|
4
|
-
use crate::core::{
|
|
5
|
-
lexer::token::{ Token, TokenKind },
|
|
6
|
-
parser::{
|
|
7
|
-
handler::{
|
|
8
|
-
at::parse_at_token,
|
|
9
|
-
bank::parse_bank_token,
|
|
10
|
-
dot::parse_dot_token,
|
|
11
|
-
identifier::parse_identifier_token,
|
|
12
|
-
loop_::parse_loop_token,
|
|
13
|
-
tempo::parse_tempo_token,
|
|
14
|
-
},
|
|
15
|
-
statement::{ Statement, StatementKind },
|
|
16
|
-
},
|
|
17
|
-
shared::value::Value,
|
|
18
|
-
store::global::GlobalStore,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
#[derive(Debug, Clone, PartialEq)]
|
|
22
|
-
pub struct Parser {
|
|
23
|
-
pub resolve_modules: bool,
|
|
24
|
-
pub tokens: Vec<Token>,
|
|
25
|
-
pub token_index: usize,
|
|
26
|
-
pub current_module: String,
|
|
27
|
-
pub previous: Option<Token>,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
impl Parser {
|
|
31
|
-
pub fn new() -> Self {
|
|
32
|
-
Parser {
|
|
33
|
-
resolve_modules: false,
|
|
34
|
-
tokens: Vec::new(),
|
|
35
|
-
token_index: 0,
|
|
36
|
-
current_module: String::new(),
|
|
37
|
-
previous: None,
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
pub fn set_current_module(&mut self, module_path: String) {
|
|
42
|
-
self.current_module = module_path;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
pub fn advance(&mut self) -> Option<&Token> {
|
|
46
|
-
if self.is_eof() {
|
|
47
|
-
return None;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
self.previous = self.tokens.get(self.token_index).cloned(); // mémorise avant de bouger
|
|
51
|
-
self.token_index += 1;
|
|
52
|
-
|
|
53
|
-
self.tokens.get(self.token_index - 1)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
pub fn match_token(&mut self, kind: TokenKind) -> bool {
|
|
57
|
-
if let Some(tok) = self.peek() {
|
|
58
|
-
if tok.kind == kind {
|
|
59
|
-
self.advance();
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
false
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
pub fn previous_clone(&self) -> Option<Token> {
|
|
67
|
-
self.previous.clone()
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
pub fn parse_block(
|
|
71
|
-
&self,
|
|
72
|
-
tokens: Vec<Token>,
|
|
73
|
-
global_store: &mut GlobalStore
|
|
74
|
-
) -> Vec<Statement> {
|
|
75
|
-
let mut inner_parser = Parser {
|
|
76
|
-
resolve_modules: self.resolve_modules,
|
|
77
|
-
tokens,
|
|
78
|
-
token_index: 0,
|
|
79
|
-
current_module: self.current_module.clone(),
|
|
80
|
-
previous: None,
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
inner_parser.parse_tokens(inner_parser.tokens.clone(), global_store)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
pub fn parse_tokens(
|
|
87
|
-
&mut self,
|
|
88
|
-
tokens: Vec<Token>,
|
|
89
|
-
global_store: &mut GlobalStore
|
|
90
|
-
) -> Vec<Statement> {
|
|
91
|
-
self.tokens = tokens;
|
|
92
|
-
self.token_index = 0;
|
|
93
|
-
|
|
94
|
-
let mut statements = Vec::new();
|
|
95
|
-
|
|
96
|
-
while !self.is_eof() {
|
|
97
|
-
let token = match self.peek() {
|
|
98
|
-
Some(t) => t.clone(),
|
|
99
|
-
None => {
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
let mut statement = match &token.kind {
|
|
105
|
-
TokenKind::At => parse_at_token(self, global_store),
|
|
106
|
-
TokenKind::Identifier => parse_identifier_token(self, global_store),
|
|
107
|
-
TokenKind::Dot => parse_dot_token(self, global_store),
|
|
108
|
-
TokenKind::Tempo => parse_tempo_token(self, global_store),
|
|
109
|
-
TokenKind::Bank => parse_bank_token(self, global_store),
|
|
110
|
-
TokenKind::Loop => parse_loop_token(self, global_store),
|
|
111
|
-
|
|
112
|
-
| TokenKind::Comment
|
|
113
|
-
| TokenKind::Equals
|
|
114
|
-
| TokenKind::Colon
|
|
115
|
-
| TokenKind::Number
|
|
116
|
-
| TokenKind::String
|
|
117
|
-
| TokenKind::LBrace
|
|
118
|
-
| TokenKind::RBrace
|
|
119
|
-
| TokenKind::Comma
|
|
120
|
-
| TokenKind::Newline
|
|
121
|
-
| TokenKind::Dedent
|
|
122
|
-
| TokenKind::Indent => {
|
|
123
|
-
self.advance();
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
TokenKind::EOF => {
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
1
|
+
pub mod driver;
|
|
130
2
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
self.advance();
|
|
134
|
-
Statement::unknown()
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
statements.push(statement);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
statements
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
pub fn check_token(&self, kind: TokenKind) -> bool {
|
|
145
|
-
self.peek().map_or(false, |t| t.kind == kind)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
pub fn parse_map_value(&mut self) -> Option<Value> {
|
|
149
|
-
if !self.match_token(TokenKind::LBrace) {
|
|
150
|
-
return None;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
let mut map = std::collections::HashMap::new();
|
|
154
|
-
|
|
155
|
-
while !self.check_token(TokenKind::RBrace) && !self.is_eof() {
|
|
156
|
-
let key = if let Some(token) = self.advance() {
|
|
157
|
-
token.lexeme.clone()
|
|
158
|
-
} else {
|
|
159
|
-
break;
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
if !self.match_token(TokenKind::Colon) {
|
|
163
|
-
println!("Expected ':' after map key '{}'", key);
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
let value = if let Some(token) = self.peek_clone() {
|
|
168
|
-
match token.kind {
|
|
169
|
-
TokenKind::String => {
|
|
170
|
-
self.advance();
|
|
171
|
-
Value::String(token.lexeme.clone())
|
|
172
|
-
}
|
|
173
|
-
TokenKind::Number => {
|
|
174
|
-
self.advance();
|
|
175
|
-
Value::Number(token.lexeme.parse().unwrap_or(0.0))
|
|
176
|
-
}
|
|
177
|
-
TokenKind::Identifier => {
|
|
178
|
-
self.advance();
|
|
179
|
-
Value::Identifier(token.lexeme.clone())
|
|
180
|
-
}
|
|
181
|
-
_ => {
|
|
182
|
-
println!("Unexpected token in map value: {:?}", token);
|
|
183
|
-
Value::Null
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
} else {
|
|
187
|
-
Value::Null
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
map.insert(key, value);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if !self.match_token(TokenKind::RBrace) {
|
|
194
|
-
println!("Expected '}}' at end of map");
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
Some(Value::Map(map))
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
pub fn peek(&self) -> Option<&Token> {
|
|
201
|
-
self.tokens.get(self.token_index)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
pub fn peek_clone(&self) -> Option<Token> {
|
|
205
|
-
self.tokens.get(self.token_index).cloned()
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
pub fn expect(&mut self, kind: TokenKind) -> Result<&Token, String> {
|
|
209
|
-
let tok = self.advance().ok_or("Unexpected end of input")?;
|
|
210
|
-
if tok.kind == kind {
|
|
211
|
-
Ok(tok)
|
|
212
|
-
} else {
|
|
213
|
-
Err(format!("Expected {:?}, got {:?}", kind, tok.kind))
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
pub fn collect_until<F>(&mut self, condition: F) -> Vec<Token> where F: Fn(&Token) -> bool {
|
|
218
|
-
let mut collected = Vec::new();
|
|
219
|
-
while let Some(token) = self.peek() {
|
|
220
|
-
if token.kind == TokenKind::Newline || token.kind == TokenKind::Indent {
|
|
221
|
-
self.advance(); // Skip newlines and indents
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
if token.kind == TokenKind::EOF {
|
|
225
|
-
break;
|
|
226
|
-
}
|
|
227
|
-
if condition(token) {
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
collected.push(self.advance().unwrap().clone());
|
|
231
|
-
}
|
|
232
|
-
collected
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
pub fn is_eof(&self) -> bool {
|
|
236
|
-
self.token_index >= self.tokens.len()
|
|
237
|
-
}
|
|
238
|
-
}
|
|
3
|
+
pub mod statement;
|
|
4
|
+
pub mod handler;
|