@devaloop/devalang 0.0.1-alpha.12 → 0.0.1-alpha.14
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/.devalang +8 -9
- package/Cargo.toml +8 -3
- package/README.md +36 -34
- package/docs/CHANGELOG.md +65 -1
- package/docs/CONTRIBUTING.md +1 -0
- package/docs/ROADMAP.md +2 -2
- package/docs/TODO.md +6 -5
- package/examples/bank.deva +2 -4
- package/examples/function.deva +15 -0
- package/examples/index.deva +25 -14
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +6 -6
- package/project-version.json +3 -3
- package/rust/cli/bank.rs +2 -1
- package/rust/cli/build.rs +76 -14
- package/rust/cli/check.rs +71 -8
- package/rust/cli/driver.rs +40 -28
- package/rust/cli/install.rs +22 -7
- package/rust/cli/login.rs +134 -0
- package/rust/cli/mod.rs +2 -1
- package/rust/cli/play.rs +45 -20
- package/rust/common/api.rs +8 -0
- package/rust/common/cdn.rs +2 -5
- package/rust/common/mod.rs +3 -1
- package/rust/common/sso.rs +8 -0
- package/rust/config/driver.rs +19 -1
- package/rust/config/loader.rs +56 -10
- package/rust/core/audio/engine.rs +254 -91
- package/rust/core/audio/interpreter/arrow_call.rs +34 -15
- package/rust/core/audio/interpreter/call.rs +72 -47
- package/rust/core/audio/interpreter/condition.rs +14 -12
- package/rust/core/audio/interpreter/driver.rs +90 -128
- package/rust/core/audio/interpreter/function.rs +21 -0
- package/rust/core/audio/interpreter/load.rs +1 -1
- package/rust/core/audio/interpreter/loop_.rs +24 -18
- package/rust/core/audio/interpreter/mod.rs +2 -1
- package/rust/core/audio/interpreter/sleep.rs +0 -6
- package/rust/core/audio/interpreter/spawn.rs +78 -60
- package/rust/core/audio/interpreter/trigger.rs +157 -70
- package/rust/core/audio/loader/trigger.rs +37 -4
- package/rust/core/audio/player.rs +20 -10
- package/rust/core/audio/renderer.rs +24 -25
- package/rust/core/builder/mod.rs +11 -6
- package/rust/core/debugger/mod.rs +2 -0
- package/rust/core/debugger/module.rs +47 -0
- package/rust/core/debugger/store.rs +25 -11
- package/rust/core/error/mod.rs +6 -0
- package/rust/core/lexer/handler/driver.rs +23 -1
- package/rust/core/lexer/handler/identifier.rs +1 -0
- package/rust/core/lexer/handler/indent.rs +16 -2
- package/rust/core/lexer/handler/mod.rs +1 -0
- package/rust/core/lexer/handler/parenthesis.rs +41 -0
- package/rust/core/lexer/token.rs +4 -0
- package/rust/core/mod.rs +2 -1
- package/rust/core/parser/driver.rs +47 -4
- package/rust/core/parser/handler/arrow_call.rs +78 -18
- package/rust/core/parser/handler/bank.rs +35 -7
- package/rust/core/parser/handler/dot.rs +81 -123
- package/rust/core/parser/handler/identifier/call.rs +69 -22
- package/rust/core/parser/handler/identifier/function.rs +92 -0
- package/rust/core/parser/handler/identifier/let_.rs +13 -19
- package/rust/core/parser/handler/identifier/mod.rs +1 -0
- package/rust/core/parser/handler/identifier/spawn.rs +74 -27
- package/rust/core/parser/statement.rs +16 -4
- package/rust/core/plugin/loader.rs +48 -0
- package/rust/core/plugin/mod.rs +1 -0
- package/rust/core/preprocessor/loader.rs +50 -32
- package/rust/core/preprocessor/module.rs +3 -1
- package/rust/core/preprocessor/processor.rs +26 -1
- package/rust/core/preprocessor/resolver/call.rs +61 -84
- package/rust/core/preprocessor/resolver/condition.rs +11 -6
- package/rust/core/preprocessor/resolver/driver.rs +52 -6
- package/rust/core/preprocessor/resolver/function.rs +78 -0
- package/rust/core/preprocessor/resolver/group.rs +43 -13
- package/rust/core/preprocessor/resolver/let_.rs +7 -10
- package/rust/core/preprocessor/resolver/mod.rs +2 -1
- package/rust/core/preprocessor/resolver/spawn.rs +64 -30
- package/rust/core/preprocessor/resolver/trigger.rs +7 -3
- package/rust/core/preprocessor/resolver/value.rs +10 -1
- package/rust/core/shared/value.rs +4 -1
- package/rust/core/store/function.rs +34 -0
- package/rust/core/store/global.rs +9 -10
- package/rust/core/store/mod.rs +2 -1
- package/rust/core/store/variable.rs +6 -0
- package/rust/installer/addon.rs +80 -0
- package/rust/installer/bank.rs +24 -14
- package/rust/installer/mod.rs +4 -1
- package/rust/installer/plugin.rs +55 -0
- package/rust/lib.rs +10 -7
- package/rust/main.rs +32 -9
- package/rust/utils/logger.rs +16 -0
- package/rust/utils/mod.rs +45 -1
- package/rust/utils/spinner.rs +2 -4
|
@@ -14,13 +14,41 @@ pub fn parse_bank_token(parser: &mut Parser, _global_store: &mut GlobalStore) ->
|
|
|
14
14
|
|
|
15
15
|
let bank_value = if let Some(token) = parser.peek_clone() {
|
|
16
16
|
match token.kind {
|
|
17
|
-
TokenKind::Identifier => {
|
|
18
|
-
parser.advance();
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
TokenKind::Identifier | TokenKind::Number => {
|
|
18
|
+
parser.advance(); // consume identifier or number
|
|
19
|
+
|
|
20
|
+
let mut value = token.lexeme.clone();
|
|
21
|
+
|
|
22
|
+
// Support namespaced banks: <author>.<bank_name>
|
|
23
|
+
if let Some(next) = parser.peek_clone() {
|
|
24
|
+
if next.kind == TokenKind::Dot {
|
|
25
|
+
parser.advance(); // consume '.'
|
|
26
|
+
if let Some(last) = parser.peek_clone() {
|
|
27
|
+
match last.kind {
|
|
28
|
+
TokenKind::Identifier | TokenKind::Number => {
|
|
29
|
+
parser.advance();
|
|
30
|
+
value = format!("{}.{}", value, last.lexeme);
|
|
31
|
+
Value::String(value)
|
|
32
|
+
}
|
|
33
|
+
_ => Value::Unknown,
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
Value::Unknown
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
match token.kind {
|
|
40
|
+
TokenKind::Identifier => Value::Identifier(value),
|
|
41
|
+
TokenKind::Number => Value::Number(value.parse::<f32>().unwrap_or(0.0)),
|
|
42
|
+
_ => Value::Unknown,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
match token.kind {
|
|
47
|
+
TokenKind::Identifier => Value::Identifier(value),
|
|
48
|
+
TokenKind::Number => Value::Number(value.parse::<f32>().unwrap_or(0.0)),
|
|
49
|
+
_ => Value::Unknown,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
24
52
|
}
|
|
25
53
|
_ => Value::Unknown,
|
|
26
54
|
}
|
|
@@ -1,165 +1,123 @@
|
|
|
1
1
|
use crate::core::{
|
|
2
2
|
lexer::token::TokenKind,
|
|
3
|
-
parser::{ statement::{
|
|
4
|
-
shared::{
|
|
5
|
-
store::global::GlobalStore,
|
|
3
|
+
parser::{driver::Parser, statement::{Statement, StatementKind}},
|
|
4
|
+
shared::{duration::Duration, value::Value},
|
|
6
5
|
};
|
|
7
6
|
|
|
8
|
-
pub fn parse_dot_token(
|
|
9
|
-
parser
|
|
7
|
+
pub fn parse_dot_token(
|
|
8
|
+
parser: &mut Parser,
|
|
9
|
+
_global_store: &mut crate::core::store::global::GlobalStore
|
|
10
|
+
) -> Statement {
|
|
11
|
+
parser.advance(); // consume '.'
|
|
10
12
|
|
|
11
13
|
let Some(dot_token) = parser.previous_clone() else {
|
|
12
14
|
return Statement::unknown();
|
|
13
15
|
};
|
|
14
16
|
|
|
15
|
-
// Parse
|
|
17
|
+
// Parse a single entity (namespace-friendly, stops at newline)
|
|
16
18
|
let mut parts = Vec::new();
|
|
19
|
+
let current_line = dot_token.line;
|
|
17
20
|
|
|
18
21
|
while let Some(token) = parser.peek_clone() {
|
|
22
|
+
// Ne jamais traverser une nouvelle ligne
|
|
23
|
+
if token.line != current_line {
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
19
26
|
match token.kind {
|
|
20
|
-
TokenKind::Number => {
|
|
21
|
-
// Stop if it's part of a duration
|
|
22
|
-
if let Some(TokenKind::Slash) = parser.peek_nth_kind(1) {
|
|
23
|
-
break;
|
|
24
|
-
}
|
|
25
|
-
|
|
27
|
+
TokenKind::Identifier | TokenKind::Number => {
|
|
26
28
|
parts.push(token.lexeme.clone());
|
|
27
29
|
parser.advance();
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if token.lexeme == "auto" {
|
|
30
|
+
// Le séparateur doit être un '.' sur la même ligne, sinon on s'arrête
|
|
31
|
+
if let Some(next) = parser.peek_clone() {
|
|
32
|
+
if next.line != current_line || next.kind != TokenKind::Dot {
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
37
36
|
break;
|
|
38
37
|
}
|
|
39
|
-
|
|
40
|
-
parts.push(token.lexeme.clone());
|
|
41
|
-
parser.advance();
|
|
42
38
|
}
|
|
43
|
-
|
|
44
39
|
TokenKind::Dot => {
|
|
45
|
-
parser.advance();
|
|
40
|
+
parser.advance();
|
|
41
|
+
}
|
|
42
|
+
TokenKind::Newline | TokenKind::EOF | TokenKind::Indent | TokenKind::Dedent => {
|
|
43
|
+
break; // Stop at newline or dedent
|
|
46
44
|
}
|
|
47
|
-
|
|
48
45
|
_ => {
|
|
49
46
|
break;
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
49
|
}
|
|
53
50
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
},
|
|
62
|
-
value: Value::Null,
|
|
63
|
-
indent: dot_token.indent,
|
|
64
|
-
line: dot_token.line,
|
|
65
|
-
column: dot_token.column,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Check if there's a duration
|
|
70
|
-
let next = parser.peek_clone();
|
|
51
|
+
// Build entity name properly
|
|
52
|
+
let entity = if !parts.is_empty() {
|
|
53
|
+
parts.join(".") // only join within the same line
|
|
54
|
+
} else {
|
|
55
|
+
eprintln!("⚠️ Empty entity after '.' at line {}", dot_token.line);
|
|
56
|
+
String::new()
|
|
57
|
+
};
|
|
71
58
|
|
|
72
|
-
|
|
73
|
-
|
|
59
|
+
// Optional duration and effects map
|
|
60
|
+
let mut duration = Duration::Auto;
|
|
61
|
+
let mut value = Value::Null;
|
|
74
62
|
|
|
75
|
-
|
|
63
|
+
if let Some(token) = parser.peek_clone() {
|
|
64
|
+
// La durée et la map d'effets ne sont valides que sur la même ligne
|
|
65
|
+
if token.line == current_line {
|
|
76
66
|
match token.kind {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
let
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if denominator_token.kind == TokenKind::Number {
|
|
88
|
-
let denominator = denominator_token.lexeme.clone();
|
|
89
|
-
parser.advance(); // consume denominator
|
|
90
|
-
|
|
91
|
-
let beat_str = format!("{}/{}", numerator, denominator);
|
|
92
|
-
let beat_duration = Duration::Beat(beat_str);
|
|
93
|
-
|
|
94
|
-
let val = match parser.peek_clone() {
|
|
95
|
-
Some(param_token) if
|
|
96
|
-
param_token.kind == TokenKind::Identifier
|
|
97
|
-
=> {
|
|
67
|
+
TokenKind::Number => {
|
|
68
|
+
let numerator = token.lexeme.clone();
|
|
69
|
+
parser.advance();
|
|
70
|
+
if let Some(peek) = parser.peek_clone() {
|
|
71
|
+
if peek.line == current_line {
|
|
72
|
+
if let Some(TokenKind::Slash) = parser.peek_kind() {
|
|
73
|
+
parser.advance();
|
|
74
|
+
if let Some(denominator_token) = parser.peek_clone() {
|
|
75
|
+
if denominator_token.line == current_line && denominator_token.kind == TokenKind::Number {
|
|
76
|
+
let denominator = denominator_token.lexeme.clone();
|
|
98
77
|
parser.advance();
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
Some(param_token) if param_token.kind == TokenKind::LBrace => {
|
|
102
|
-
parser.parse_map_value().unwrap_or(Value::Null)
|
|
78
|
+
duration = Duration::Beat(format!("{}/{}", numerator, denominator));
|
|
103
79
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return Statement {
|
|
108
|
-
kind: StatementKind::Trigger {
|
|
109
|
-
entity,
|
|
110
|
-
duration: beat_duration,
|
|
111
|
-
},
|
|
112
|
-
value: val,
|
|
113
|
-
indent: dot_token.indent,
|
|
114
|
-
line: dot_token.line,
|
|
115
|
-
column: dot_token.column,
|
|
116
|
-
};
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
duration = parse_duration(numerator);
|
|
117
83
|
}
|
|
84
|
+
} else {
|
|
85
|
+
duration = parse_duration(numerator);
|
|
118
86
|
}
|
|
87
|
+
} else {
|
|
88
|
+
duration = parse_duration(numerator);
|
|
119
89
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
let val = match parser.peek_clone() {
|
|
125
|
-
Some(param_token) if param_token.kind == TokenKind::Identifier => {
|
|
126
|
-
parser.advance();
|
|
127
|
-
Value::Identifier(param_token.lexeme.clone())
|
|
128
|
-
}
|
|
129
|
-
Some(param_token) if param_token.kind == TokenKind::LBrace => {
|
|
130
|
-
parser.parse_map_value().unwrap_or(Value::Null)
|
|
131
|
-
}
|
|
132
|
-
_ => Value::Null,
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
(duration, val)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
TokenKind::Identifier => {
|
|
139
|
-
let duration_lexeme = token.lexeme.clone();
|
|
140
|
-
parser.advance(); // consume duration
|
|
141
|
-
|
|
142
|
-
let val = match parser.peek_clone() {
|
|
143
|
-
Some(param_token) if param_token.kind == TokenKind::Identifier => {
|
|
144
|
-
parser.advance();
|
|
145
|
-
Value::Identifier(param_token.lexeme.clone())
|
|
90
|
+
if let Some(next) = parser.peek_clone() {
|
|
91
|
+
if next.line == current_line && next.kind == TokenKind::LBrace {
|
|
92
|
+
value = parser.parse_map_value().unwrap_or(Value::Null);
|
|
146
93
|
}
|
|
147
|
-
|
|
148
|
-
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
TokenKind::Identifier => {
|
|
97
|
+
let id = token.lexeme.clone();
|
|
98
|
+
parser.advance();
|
|
99
|
+
duration = parse_duration(id);
|
|
100
|
+
if let Some(next) = parser.peek_clone() {
|
|
101
|
+
if next.line == current_line && next.kind == TokenKind::LBrace {
|
|
102
|
+
value = parser.parse_map_value().unwrap_or(Value::Null);
|
|
149
103
|
}
|
|
150
|
-
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
(parse_duration(duration_lexeme), val)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
_ => (Duration::Auto, Value::Null),
|
|
104
|
+
}
|
|
157
105
|
}
|
|
158
|
-
|
|
106
|
+
TokenKind::LBrace => {
|
|
107
|
+
value = parser.parse_map_value().unwrap_or(Value::Null);
|
|
108
|
+
}
|
|
109
|
+
_ => {}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
159
113
|
|
|
160
114
|
Statement {
|
|
161
|
-
kind: StatementKind::Trigger {
|
|
162
|
-
|
|
115
|
+
kind: StatementKind::Trigger {
|
|
116
|
+
entity,
|
|
117
|
+
duration,
|
|
118
|
+
effects: Some(value.clone()),
|
|
119
|
+
},
|
|
120
|
+
value: Value::Null,
|
|
163
121
|
indent: dot_token.indent,
|
|
164
122
|
line: dot_token.line,
|
|
165
123
|
column: dot_token.column,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use crate::core::{
|
|
2
|
-
lexer::token::{
|
|
3
|
-
parser::{
|
|
2
|
+
lexer::token::{Token, TokenKind},
|
|
3
|
+
parser::{statement::{Statement, StatementKind}, driver::Parser},
|
|
4
4
|
shared::value::Value,
|
|
5
5
|
store::global::GlobalStore,
|
|
6
6
|
};
|
|
@@ -8,34 +8,81 @@ use crate::core::{
|
|
|
8
8
|
pub fn parse_call_token(
|
|
9
9
|
parser: &mut Parser,
|
|
10
10
|
current_token: Token,
|
|
11
|
-
|
|
11
|
+
_global_store: &mut GlobalStore
|
|
12
12
|
) -> Statement {
|
|
13
13
|
parser.advance(); // consume "call"
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"Expected identifier or string after 'call'".to_string()
|
|
24
|
-
);
|
|
25
|
-
}
|
|
15
|
+
// Expect function name
|
|
16
|
+
let name_token = match parser.peek_clone() {
|
|
17
|
+
Some(t) => t,
|
|
18
|
+
None => {
|
|
19
|
+
return Statement::error(
|
|
20
|
+
current_token,
|
|
21
|
+
"Expected function name after 'call'".to_string()
|
|
22
|
+
);
|
|
26
23
|
}
|
|
27
|
-
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if name_token.kind != TokenKind::Identifier {
|
|
28
27
|
return Statement::error(
|
|
29
|
-
|
|
30
|
-
"Expected
|
|
28
|
+
name_token,
|
|
29
|
+
"Expected function name to be an identifier".to_string()
|
|
31
30
|
);
|
|
32
|
-
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let func_name = name_token.lexeme.clone();
|
|
34
|
+
parser.advance(); // consume function name
|
|
35
|
+
|
|
36
|
+
// Expect '('
|
|
37
|
+
let mut args: Vec<Value> = Vec::new();
|
|
38
|
+
if let Some(open_paren) = parser.peek_clone() {
|
|
39
|
+
if open_paren.kind == TokenKind::LParen {
|
|
40
|
+
parser.advance(); // consume '('
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
42
|
+
// Collect args until ')'
|
|
43
|
+
while let Some(token) = parser.peek_clone() {
|
|
44
|
+
if token.kind == TokenKind::RParen {
|
|
45
|
+
parser.advance(); // consume ')'
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
match token.kind {
|
|
50
|
+
TokenKind::Number => {
|
|
51
|
+
if let Ok(num) = token.lexeme.parse::<f32>() {
|
|
52
|
+
args.push(Value::Number(num));
|
|
53
|
+
}
|
|
54
|
+
parser.advance();
|
|
55
|
+
}
|
|
56
|
+
TokenKind::String => {
|
|
57
|
+
args.push(Value::String(token.lexeme.clone()));
|
|
58
|
+
parser.advance();
|
|
59
|
+
}
|
|
60
|
+
TokenKind::Identifier => {
|
|
61
|
+
args.push(Value::Identifier(token.lexeme.clone()));
|
|
62
|
+
parser.advance();
|
|
63
|
+
}
|
|
64
|
+
TokenKind::Comma => {
|
|
65
|
+
parser.advance(); // skip comma
|
|
66
|
+
}
|
|
67
|
+
_ => {
|
|
68
|
+
return Statement::error(
|
|
69
|
+
token,
|
|
70
|
+
"Unexpected token in call arguments".to_string()
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
Statement {
|
|
79
|
+
kind: StatementKind::Call {
|
|
80
|
+
name: func_name,
|
|
81
|
+
args,
|
|
82
|
+
},
|
|
83
|
+
value: Value::Null,
|
|
37
84
|
indent: current_token.indent,
|
|
38
85
|
line: current_token.line,
|
|
39
86
|
column: current_token.column,
|
|
40
|
-
}
|
|
87
|
+
}
|
|
41
88
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::{ token::TokenKind },
|
|
3
|
+
parser::{ statement::{ Statement, StatementKind }, driver::Parser },
|
|
4
|
+
shared::value::Value,
|
|
5
|
+
store::global::GlobalStore,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
pub fn parse_function_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
|
|
9
|
+
parser.advance(); // consume 'fn'
|
|
10
|
+
|
|
11
|
+
let fn_token = match parser.previous_clone() {
|
|
12
|
+
Some(tok) => tok,
|
|
13
|
+
None => return Statement::unknown(),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
let name_token = match parser.peek_clone() {
|
|
17
|
+
Some(tok) => tok,
|
|
18
|
+
None => return Statement::error(fn_token, "Expected function name after 'fn'".to_string()),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
if name_token.kind != TokenKind::Identifier {
|
|
22
|
+
return Statement::error(
|
|
23
|
+
name_token.clone(),
|
|
24
|
+
"Expected function name to be an identifier".to_string()
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let function_name = name_token.lexeme.clone();
|
|
29
|
+
parser.advance(); // consume function name
|
|
30
|
+
|
|
31
|
+
let mut parameters = Vec::new();
|
|
32
|
+
let mut body = Vec::new();
|
|
33
|
+
|
|
34
|
+
// Expect '('
|
|
35
|
+
if parser.peek_kind() != Some(TokenKind::LParen) {
|
|
36
|
+
return Statement::error(name_token.clone(), "Expected '(' after function name".to_string());
|
|
37
|
+
}
|
|
38
|
+
parser.advance(); // consume '('
|
|
39
|
+
|
|
40
|
+
// Parse parameters until ')'
|
|
41
|
+
let tokens = parser.collect_until(|t| t.kind == TokenKind::RParen || t.kind == TokenKind::EOF);
|
|
42
|
+
for token in tokens {
|
|
43
|
+
if token.kind == TokenKind::Identifier {
|
|
44
|
+
parameters.push(token.lexeme.clone());
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if parser.peek_kind() == Some(TokenKind::RParen) {
|
|
49
|
+
parser.advance(); // consume ')'
|
|
50
|
+
} else {
|
|
51
|
+
return Statement::error(name_token.clone(), "Expected ')' after parameters".to_string());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Expect colon
|
|
55
|
+
if parser.peek_kind() != Some(TokenKind::Colon) {
|
|
56
|
+
return Statement::error(name_token.clone(), "Expected ':' after ')'".to_string());
|
|
57
|
+
}
|
|
58
|
+
parser.advance(); // consume ':'
|
|
59
|
+
|
|
60
|
+
// Collect ALL tokens indented after this line until Dedent
|
|
61
|
+
let base_indent = fn_token.indent;
|
|
62
|
+
let mut body_tokens = Vec::new();
|
|
63
|
+
|
|
64
|
+
while let Some(tok) = parser.peek() {
|
|
65
|
+
if tok.kind == TokenKind::Dedent && tok.indent <= base_indent {
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
body_tokens.push(parser.advance().unwrap().clone());
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// arse those tokens into block statements
|
|
72
|
+
body = parser.parse_block(body_tokens.clone(), global_store);
|
|
73
|
+
|
|
74
|
+
// Skip Dedent if present
|
|
75
|
+
if let Some(tok) = parser.peek() {
|
|
76
|
+
if tok.kind == TokenKind::Dedent {
|
|
77
|
+
parser.advance();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
Statement {
|
|
82
|
+
kind: StatementKind::Function {
|
|
83
|
+
name: function_name.clone(),
|
|
84
|
+
parameters: parameters.clone(),
|
|
85
|
+
body: body.clone(),
|
|
86
|
+
},
|
|
87
|
+
value: Value::Null,
|
|
88
|
+
indent: fn_token.indent,
|
|
89
|
+
line: fn_token.line,
|
|
90
|
+
column: fn_token.column,
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -4,7 +4,7 @@ use crate::core::{
|
|
|
4
4
|
lexer::token::{ Token, TokenKind },
|
|
5
5
|
parser::{
|
|
6
6
|
driver::Parser,
|
|
7
|
-
handler::identifier::synth::parse_synth_token,
|
|
7
|
+
handler::{ dot::parse_dot_token, identifier::synth::parse_synth_token },
|
|
8
8
|
statement::{ Statement, StatementKind },
|
|
9
9
|
},
|
|
10
10
|
shared::value::Value,
|
|
@@ -33,21 +33,15 @@ pub fn parse_let_token(
|
|
|
33
33
|
return Statement::error(current_token, "Expected '=' after identifier".to_string());
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
if token.kind == TokenKind::
|
|
36
|
+
let value = match parser.peek_clone() {
|
|
37
|
+
Some(token) if token.kind == TokenKind::Dot => {
|
|
38
|
+
let dot_stmt = parse_dot_token(parser, global_store);
|
|
39
|
+
Value::Statement(Box::new(dot_stmt))
|
|
40
|
+
}
|
|
41
|
+
Some(token) if token.kind == TokenKind::Synth => {
|
|
38
42
|
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
|
-
};
|
|
43
|
+
Value::Statement(Box::new(synth_stmt))
|
|
47
44
|
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let value = match parser.peek_clone() {
|
|
51
45
|
Some(token) if token.kind == TokenKind::Identifier => {
|
|
52
46
|
parser.advance();
|
|
53
47
|
Value::Identifier(token.lexeme.clone())
|
|
@@ -65,7 +59,8 @@ pub fn parse_let_token(
|
|
|
65
59
|
Value::Boolean(token.lexeme.parse().unwrap_or(false))
|
|
66
60
|
}
|
|
67
61
|
Some(token) if token.kind == TokenKind::LBrace => {
|
|
68
|
-
parser.advance();
|
|
62
|
+
parser.advance();
|
|
63
|
+
|
|
69
64
|
let mut map = HashMap::new();
|
|
70
65
|
|
|
71
66
|
while let Some(key_token) = parser.peek_clone() {
|
|
@@ -117,15 +112,14 @@ pub fn parse_let_token(
|
|
|
117
112
|
|
|
118
113
|
Value::Map(map)
|
|
119
114
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return Statement::error(current_token, message);
|
|
115
|
+
_ => {
|
|
116
|
+
return Statement::error(current_token, "Unhandled value type after '='".to_string());
|
|
123
117
|
}
|
|
124
118
|
};
|
|
125
119
|
|
|
126
120
|
Statement {
|
|
127
121
|
kind: StatementKind::Let { name: identifier },
|
|
128
|
-
value,
|
|
122
|
+
value: value,
|
|
129
123
|
indent: current_token.indent,
|
|
130
124
|
line: current_token.line,
|
|
131
125
|
column: current_token.column,
|