@devaloop/devalang 0.0.1-alpha.12 → 0.0.1-alpha.13
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 +54 -53
- package/README.md +1 -14
- package/docs/CHANGELOG.md +26 -0
- package/docs/TODO.md +1 -1
- package/examples/index.deva +10 -13
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +1 -1
- package/project-version.json +3 -3
- package/rust/cli/build.rs +25 -2
- package/rust/cli/check.rs +26 -3
- package/rust/cli/play.rs +1 -1
- package/rust/core/audio/engine.rs +126 -73
- 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 +84 -127
- 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/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/mod.rs +1 -0
- package/rust/core/lexer/handler/parenthesis.rs +41 -0
- package/rust/core/lexer/token.rs +3 -0
- package/rust/core/parser/driver.rs +3 -1
- package/rust/core/parser/handler/dot.rs +64 -127
- 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/preprocessor/loader.rs +45 -29
- 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/lib.rs +10 -7
- package/rust/utils/mod.rs +45 -1
package/rust/core/lexer/token.rs
CHANGED
|
@@ -29,6 +29,7 @@ pub enum TokenKind {
|
|
|
29
29
|
Tempo,
|
|
30
30
|
Bank,
|
|
31
31
|
Loop,
|
|
32
|
+
Function,
|
|
32
33
|
|
|
33
34
|
// ───── Instruments ─────
|
|
34
35
|
Synth,
|
|
@@ -64,6 +65,8 @@ pub enum TokenKind {
|
|
|
64
65
|
RBrace, // }
|
|
65
66
|
LBracket, // [
|
|
66
67
|
RBracket, // ]
|
|
68
|
+
LParen, // (
|
|
69
|
+
RParen, // )
|
|
67
70
|
|
|
68
71
|
// ───── Quotes ─────
|
|
69
72
|
Quote, // '
|
|
@@ -7,7 +7,7 @@ use crate::core::{
|
|
|
7
7
|
bank::parse_bank_token,
|
|
8
8
|
condition::parse_condition_token,
|
|
9
9
|
dot::parse_dot_token,
|
|
10
|
-
identifier::parse_identifier_token,
|
|
10
|
+
identifier::{function::parse_function_token, parse_identifier_token},
|
|
11
11
|
loop_::parse_loop_token,
|
|
12
12
|
tempo::parse_tempo_token,
|
|
13
13
|
},
|
|
@@ -138,6 +138,7 @@ impl Parser {
|
|
|
138
138
|
TokenKind::Bank => parse_bank_token(self, global_store),
|
|
139
139
|
TokenKind::Loop => parse_loop_token(self, global_store),
|
|
140
140
|
TokenKind::If => parse_condition_token(self, global_store),
|
|
141
|
+
TokenKind::Function => parse_function_token(self, global_store),
|
|
141
142
|
|
|
142
143
|
| TokenKind::Else // Ignore else, already handled in `parse_condition_token`
|
|
143
144
|
| TokenKind::Comment
|
|
@@ -303,6 +304,7 @@ impl Parser {
|
|
|
303
304
|
}
|
|
304
305
|
collected.push(self.advance().unwrap().clone());
|
|
305
306
|
}
|
|
307
|
+
|
|
306
308
|
collected
|
|
307
309
|
}
|
|
308
310
|
|
|
@@ -1,165 +1,102 @@
|
|
|
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();
|
|
17
19
|
|
|
18
20
|
while let Some(token) = parser.peek_clone() {
|
|
19
21
|
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
|
-
|
|
22
|
+
TokenKind::Identifier | TokenKind::Number => {
|
|
26
23
|
parts.push(token.lexeme.clone());
|
|
27
24
|
parser.advance();
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
TokenKind::Identifier => {
|
|
31
|
-
// Stop parsing entity name if next token is ':' or if already have one ident and current might be a param
|
|
32
|
-
if parts.len() >= 1 {
|
|
33
|
-
break; // we've already got the entity
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if token.lexeme == "auto" {
|
|
25
|
+
if parser.peek_kind() != Some(TokenKind::Dot) {
|
|
37
26
|
break;
|
|
38
27
|
}
|
|
39
|
-
|
|
40
|
-
parts.push(token.lexeme.clone());
|
|
41
|
-
parser.advance();
|
|
42
28
|
}
|
|
43
|
-
|
|
44
29
|
TokenKind::Dot => {
|
|
45
|
-
parser.advance();
|
|
30
|
+
parser.advance();
|
|
31
|
+
}
|
|
32
|
+
TokenKind::Newline | TokenKind::EOF | TokenKind::Indent | TokenKind::Dedent => {
|
|
33
|
+
break; // Stop at newline or dedent
|
|
46
34
|
}
|
|
47
|
-
|
|
48
35
|
_ => {
|
|
49
36
|
break;
|
|
50
37
|
}
|
|
51
38
|
}
|
|
52
39
|
}
|
|
53
40
|
|
|
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();
|
|
71
|
-
|
|
72
|
-
let (duration, value) = match next {
|
|
73
|
-
None => (Duration::Auto, Value::Null),
|
|
74
|
-
|
|
75
|
-
Some(token) =>
|
|
76
|
-
match token.kind {
|
|
77
|
-
TokenKind::Newline | TokenKind::EOF => (Duration::Auto, Value::Null),
|
|
78
|
-
|
|
79
|
-
TokenKind::Number => {
|
|
80
|
-
let numerator = token.lexeme.clone();
|
|
81
|
-
parser.advance(); // consume numerator
|
|
82
|
-
|
|
83
|
-
if let Some(TokenKind::Slash) = parser.peek_kind() {
|
|
84
|
-
parser.advance(); // consume slash
|
|
85
|
-
|
|
86
|
-
if let Some(denominator_token) = parser.peek_clone() {
|
|
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
|
-
=> {
|
|
98
|
-
parser.advance();
|
|
99
|
-
Value::Identifier(param_token.lexeme.clone())
|
|
100
|
-
}
|
|
101
|
-
Some(param_token) if param_token.kind == TokenKind::LBrace => {
|
|
102
|
-
parser.parse_map_value().unwrap_or(Value::Null)
|
|
103
|
-
}
|
|
104
|
-
_ => Value::Null,
|
|
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
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
41
|
+
// Build entity name properly
|
|
42
|
+
let entity = if !parts.is_empty() {
|
|
43
|
+
parts.join(".") // only join within the same line
|
|
44
|
+
} else {
|
|
45
|
+
eprintln!("⚠️ Empty entity after '.' at line {}", dot_token.line);
|
|
46
|
+
String::new()
|
|
47
|
+
};
|
|
120
48
|
|
|
121
|
-
|
|
122
|
-
|
|
49
|
+
// Optional duration and effects map
|
|
50
|
+
let mut duration = Duration::Auto;
|
|
51
|
+
let mut value = Value::Null;
|
|
123
52
|
|
|
124
|
-
|
|
125
|
-
|
|
53
|
+
if let Some(token) = parser.peek_clone() {
|
|
54
|
+
match token.kind {
|
|
55
|
+
TokenKind::Number => {
|
|
56
|
+
let numerator = token.lexeme.clone();
|
|
57
|
+
parser.advance();
|
|
58
|
+
if let Some(TokenKind::Slash) = parser.peek_kind() {
|
|
59
|
+
parser.advance();
|
|
60
|
+
if let Some(denominator_token) = parser.peek_clone() {
|
|
61
|
+
if denominator_token.kind == TokenKind::Number {
|
|
62
|
+
let denominator = denominator_token.lexeme.clone();
|
|
126
63
|
parser.advance();
|
|
127
|
-
|
|
64
|
+
duration = Duration::Beat(format!("{}/{}", numerator, denominator));
|
|
128
65
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
_ => Value::Null,
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
(duration, val)
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
duration = parse_duration(numerator);
|
|
136
69
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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())
|
|
146
|
-
}
|
|
147
|
-
Some(param_token) if param_token.kind == TokenKind::LBrace => {
|
|
148
|
-
parser.parse_map_value().unwrap_or(Value::Null)
|
|
149
|
-
}
|
|
150
|
-
_ => Value::Null,
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
(parse_duration(duration_lexeme), val)
|
|
70
|
+
if let Some(next) = parser.peek_clone() {
|
|
71
|
+
if next.kind == TokenKind::LBrace {
|
|
72
|
+
value = parser.parse_map_value().unwrap_or(Value::Null);
|
|
73
|
+
}
|
|
154
74
|
}
|
|
155
|
-
|
|
156
|
-
_ => (Duration::Auto, Value::Null),
|
|
157
75
|
}
|
|
158
|
-
|
|
76
|
+
TokenKind::Identifier => {
|
|
77
|
+
let id = token.lexeme.clone();
|
|
78
|
+
parser.advance();
|
|
79
|
+
duration = parse_duration(id);
|
|
80
|
+
if let Some(next) = parser.peek_clone() {
|
|
81
|
+
if next.kind == TokenKind::LBrace {
|
|
82
|
+
value = parser.parse_map_value().unwrap_or(Value::Null);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
TokenKind::LBrace => {
|
|
87
|
+
value = parser.parse_map_value().unwrap_or(Value::Null);
|
|
88
|
+
}
|
|
89
|
+
_ => {}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
159
92
|
|
|
160
93
|
Statement {
|
|
161
|
-
kind: StatementKind::Trigger {
|
|
162
|
-
|
|
94
|
+
kind: StatementKind::Trigger {
|
|
95
|
+
entity,
|
|
96
|
+
duration,
|
|
97
|
+
effects: Some(value.clone()),
|
|
98
|
+
},
|
|
99
|
+
value: Value::Null,
|
|
163
100
|
indent: dot_token.indent,
|
|
164
101
|
line: dot_token.line,
|
|
165
102
|
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,
|
|
@@ -8,34 +8,81 @@ use crate::core::{
|
|
|
8
8
|
pub fn parse_spawn_token(
|
|
9
9
|
parser: &mut Parser,
|
|
10
10
|
current_token: Token,
|
|
11
|
-
|
|
11
|
+
_global_store: &mut GlobalStore
|
|
12
12
|
) -> Statement {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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 {
|
|
13
|
+
parser.advance(); // consume "spawn"
|
|
14
|
+
|
|
15
|
+
// Expect function name
|
|
16
|
+
let name_token = match parser.peek_clone() {
|
|
17
|
+
Some(t) => t,
|
|
18
|
+
None => {
|
|
28
19
|
return Statement::error(
|
|
29
20
|
current_token,
|
|
30
|
-
"Expected
|
|
21
|
+
"Expected function name after 'spawn'".to_string()
|
|
31
22
|
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if name_token.kind != TokenKind::Identifier {
|
|
27
|
+
return Statement::error(
|
|
28
|
+
name_token,
|
|
29
|
+
"Expected function name to be an identifier".to_string()
|
|
30
|
+
);
|
|
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 '('
|
|
41
|
+
|
|
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 spawn arguments".to_string()
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
Statement {
|
|
79
|
+
kind: StatementKind::Spawn {
|
|
80
|
+
name: func_name,
|
|
81
|
+
args,
|
|
82
|
+
},
|
|
83
|
+
value: Value::Null,
|
|
84
|
+
indent: current_token.indent,
|
|
85
|
+
line: current_token.line,
|
|
86
|
+
column: current_token.column,
|
|
87
|
+
}
|
|
88
|
+
}
|