@devaloop/devalang 0.0.1-alpha.2 → 0.0.1-alpha.3
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 +46 -46
- package/README.md +7 -6
- package/docs/CHANGELOG.md +11 -6
- package/docs/ROADMAP.md +5 -1
- package/docs/TODO.md +6 -31
- package/examples/exported.deva +1 -1
- package/examples/index.deva +1 -0
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +1 -2
- package/project-version.json +3 -3
- package/rust/cli/build.rs +57 -40
- package/rust/cli/check.rs +47 -111
- package/rust/cli/init.rs +1 -1
- package/rust/cli/mod.rs +174 -2
- package/rust/{utils/config.rs → config/loader.rs} +3 -2
- package/rust/{core/types/config.rs → config/mod.rs} +5 -5
- package/rust/core/builder/mod.rs +21 -27
- package/rust/core/debugger/lexer.rs +12 -0
- package/rust/core/debugger/mod.rs +12 -49
- package/rust/core/debugger/preprocessor.rs +23 -0
- package/rust/core/error/mod.rs +60 -0
- package/rust/core/lexer/{at.rs → handler/at.rs} +1 -1
- package/rust/core/lexer/{brace.rs → handler/brace.rs} +1 -1
- package/rust/core/lexer/{colon.rs → handler/colon.rs} +1 -1
- package/rust/core/lexer/{comment.rs → handler/comment.rs} +3 -3
- package/rust/core/lexer/{dot.rs → handler/dot.rs} +1 -1
- package/rust/core/lexer/{equal.rs → handler/equal.rs} +1 -1
- package/rust/core/lexer/{identifier.rs → handler/identifier.rs} +1 -1
- package/rust/core/lexer/{indent.rs → handler/indent.rs} +10 -5
- package/rust/core/lexer/handler/mod.rs +238 -0
- package/rust/core/lexer/{newline.rs → handler/newline.rs} +6 -10
- package/rust/core/lexer/{number.rs → handler/number.rs} +1 -1
- package/rust/core/lexer/handler/string.rs +66 -0
- package/rust/core/lexer/mod.rs +25 -14
- package/rust/core/lexer/token.rs +55 -0
- package/rust/core/mod.rs +5 -2
- package/rust/core/parser/handler/at.rs +166 -0
- package/rust/core/parser/handler/bank.rs +38 -0
- package/rust/core/parser/handler/dot.rs +112 -0
- package/rust/core/parser/handler/identifier.rs +134 -0
- package/rust/core/parser/handler/loop_.rs +55 -0
- package/rust/core/parser/handler/mod.rs +6 -0
- package/rust/core/parser/handler/tempo.rs +47 -0
- package/rust/core/parser/mod.rs +204 -166
- package/rust/core/parser/statement.rs +91 -0
- package/rust/core/preprocessor/loader.rs +105 -0
- package/rust/core/preprocessor/mod.rs +2 -24
- package/rust/core/preprocessor/module.rs +37 -56
- package/rust/core/preprocessor/processor.rs +41 -0
- package/rust/core/preprocessor/resolver.rs +372 -0
- package/rust/core/shared/duration.rs +8 -0
- package/rust/core/shared/mod.rs +2 -0
- package/rust/core/shared/value.rs +18 -0
- package/rust/core/store/export.rs +28 -0
- package/rust/core/store/global.rs +39 -0
- package/rust/core/store/import.rs +28 -0
- package/rust/core/store/mod.rs +4 -0
- package/rust/core/store/variable.rs +28 -0
- package/rust/core/utils/mod.rs +2 -0
- package/rust/core/utils/validation.rs +35 -0
- package/rust/lib.rs +0 -1
- package/rust/main.rs +17 -19
- package/rust/utils/logger.rs +69 -34
- package/rust/utils/mod.rs +3 -5
- package/templates/minimal/.devalang +1 -1
- package/templates/welcome/.devalang +1 -1
- package/rust/audio/mod.rs +0 -1
- package/rust/core/lexer/bracket.rs +0 -41
- package/rust/core/lexer/driver.rs +0 -286
- package/rust/core/lexer/quote.rs +0 -61
- package/rust/core/parser/at.rs +0 -142
- package/rust/core/parser/bank.rs +0 -42
- package/rust/core/parser/dot.rs +0 -137
- package/rust/core/parser/identifer.rs +0 -91
- package/rust/core/parser/loop_.rs +0 -62
- package/rust/core/parser/tempo.rs +0 -42
- package/rust/core/parser/variable.rs +0 -129
- package/rust/core/preprocessor/dependencies.rs +0 -54
- package/rust/core/preprocessor/resolver/at.rs +0 -24
- package/rust/core/preprocessor/resolver/bank.rs +0 -59
- package/rust/core/preprocessor/resolver/loop_.rs +0 -82
- package/rust/core/preprocessor/resolver/mod.rs +0 -113
- package/rust/core/preprocessor/resolver/tempo.rs +0 -70
- package/rust/core/preprocessor/resolver/trigger.rs +0 -176
- package/rust/core/types/cli.rs +0 -182
- package/rust/core/types/mod.rs +0 -8
- package/rust/core/types/module.rs +0 -41
- package/rust/core/types/parser.rs +0 -73
- package/rust/core/types/statement.rs +0 -105
- package/rust/core/types/store.rs +0 -116
- package/rust/core/types/token.rs +0 -83
- package/rust/core/types/variable.rs +0 -32
- package/rust/runner/executer.rs +0 -44
- package/rust/runner/mod.rs +0 -1
- /package/rust/{utils → core/utils}/path.rs +0 -0
- /package/rust/utils/{loader.rs → spinner.rs} +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::token::TokenKind,
|
|
3
|
+
parser::{ statement::{ Statement, StatementKind }, Parser },
|
|
4
|
+
shared::{ duration::Duration, value::Value },
|
|
5
|
+
store::global::GlobalStore,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
pub fn parse_dot_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
|
|
9
|
+
parser.advance(); // consume the dot token
|
|
10
|
+
|
|
11
|
+
let Some(dot_token) = parser.previous_clone() else {
|
|
12
|
+
return Statement::unknown();
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// .kick
|
|
16
|
+
let Some(entity_token) = parser.peek_clone() else {
|
|
17
|
+
return Statement {
|
|
18
|
+
kind: StatementKind::Trigger {
|
|
19
|
+
entity: String::new(),
|
|
20
|
+
duration: Duration::Auto,
|
|
21
|
+
},
|
|
22
|
+
value: Value::Null,
|
|
23
|
+
indent: dot_token.indent,
|
|
24
|
+
line: dot_token.line,
|
|
25
|
+
column: dot_token.column,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
parser.advance(); // consume entity
|
|
30
|
+
let entity = entity_token.lexeme.clone();
|
|
31
|
+
|
|
32
|
+
// Check if there's a duration
|
|
33
|
+
let next = parser.peek_clone();
|
|
34
|
+
|
|
35
|
+
let (duration, value) = match next {
|
|
36
|
+
// If no more tokens, it's just `.kick`
|
|
37
|
+
None => (Duration::Auto, Value::Null),
|
|
38
|
+
|
|
39
|
+
Some(token) =>
|
|
40
|
+
match token.kind {
|
|
41
|
+
TokenKind::Newline | TokenKind::EOF => { (Duration::Auto, Value::Null) }
|
|
42
|
+
|
|
43
|
+
TokenKind::Number => {
|
|
44
|
+
let duration_lexeme = token.lexeme.clone();
|
|
45
|
+
parser.advance(); // consume duration
|
|
46
|
+
|
|
47
|
+
// Try to parse optional value (ex: .kick 250 params)
|
|
48
|
+
match parser.peek_clone() {
|
|
49
|
+
Some(param_token) if param_token.kind == TokenKind::Identifier => {
|
|
50
|
+
parser.advance();
|
|
51
|
+
(
|
|
52
|
+
parse_duration(duration_lexeme),
|
|
53
|
+
Value::Identifier(param_token.lexeme.clone()),
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Some(param_token) if param_token.kind == TokenKind::LBrace => {
|
|
58
|
+
// Handle value as Map
|
|
59
|
+
let map = parser.parse_map_value(); // Assumes you have a helper for map
|
|
60
|
+
(parse_duration(duration_lexeme), map.unwrap_or(Value::Null))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_ => (parse_duration(duration_lexeme), Value::Null),
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
TokenKind::Identifier => {
|
|
68
|
+
let duration_lexeme = token.lexeme.clone();
|
|
69
|
+
parser.advance(); // consume duration
|
|
70
|
+
|
|
71
|
+
// Try to parse optional value (ex: .kick auto params)
|
|
72
|
+
match parser.peek_clone() {
|
|
73
|
+
Some(param_token) if param_token.kind == TokenKind::Identifier => {
|
|
74
|
+
parser.advance();
|
|
75
|
+
(
|
|
76
|
+
parse_duration(duration_lexeme),
|
|
77
|
+
Value::Identifier(param_token.lexeme.clone()),
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
Some(param_token) if param_token.kind == TokenKind::LBrace => {
|
|
82
|
+
// Handle value as Map
|
|
83
|
+
let map = parser.parse_map_value(); // Assumes you have a helper for map
|
|
84
|
+
(parse_duration(duration_lexeme), map.unwrap_or(Value::Null))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_ => (parse_duration(duration_lexeme), Value::Null),
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_ => (Duration::Auto, Value::Null),
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
Statement {
|
|
96
|
+
kind: StatementKind::Trigger { entity, duration },
|
|
97
|
+
value,
|
|
98
|
+
indent: dot_token.indent,
|
|
99
|
+
line: dot_token.line,
|
|
100
|
+
column: dot_token.column,
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fn parse_duration(s: String) -> Duration {
|
|
105
|
+
if s == "auto" {
|
|
106
|
+
Duration::Auto
|
|
107
|
+
} else if s.parse::<f32>().is_ok() {
|
|
108
|
+
Duration::Number(s.parse().unwrap())
|
|
109
|
+
} else {
|
|
110
|
+
Duration::Identifier(s)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::token::{ Token, TokenKind },
|
|
3
|
+
parser::{ statement::{ Statement, StatementKind }, Parser },
|
|
4
|
+
shared::value::Value,
|
|
5
|
+
store::global::GlobalStore,
|
|
6
|
+
};
|
|
7
|
+
use std::collections::HashMap;
|
|
8
|
+
|
|
9
|
+
pub fn parse_identifier_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
|
|
10
|
+
let Some(current_token) = parser.peek_clone() else {
|
|
11
|
+
return Statement::unknown();
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
if current_token.lexeme == "let" {
|
|
15
|
+
parser.advance(); // consume "let"
|
|
16
|
+
|
|
17
|
+
let identifier = if let Some(token) = parser.peek_clone() {
|
|
18
|
+
if token.kind == TokenKind::Identifier {
|
|
19
|
+
parser.advance();
|
|
20
|
+
token.lexeme.clone()
|
|
21
|
+
} else {
|
|
22
|
+
return Statement::error(token, "Expected identifier after 'let'".to_string());
|
|
23
|
+
}
|
|
24
|
+
} else {
|
|
25
|
+
return Statement::error(current_token, "Expected identifier after 'let'".to_string());
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
if !parser.match_token(TokenKind::Equals) {
|
|
29
|
+
return Statement::error(current_token, "Expected '=' after identifier".to_string());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let value = match parser.peek_clone() {
|
|
33
|
+
Some(token) if token.kind == TokenKind::Identifier => {
|
|
34
|
+
parser.advance();
|
|
35
|
+
Value::Identifier(token.lexeme.clone())
|
|
36
|
+
}
|
|
37
|
+
Some(token) if token.kind == TokenKind::String => {
|
|
38
|
+
parser.advance();
|
|
39
|
+
Value::String(token.lexeme.clone())
|
|
40
|
+
}
|
|
41
|
+
Some(token) if token.kind == TokenKind::Number => {
|
|
42
|
+
parser.advance();
|
|
43
|
+
Value::Number(token.lexeme.parse().unwrap_or(0.0))
|
|
44
|
+
}
|
|
45
|
+
Some(token) if token.kind == TokenKind::LBrace => {
|
|
46
|
+
parser.advance(); // consume '{'
|
|
47
|
+
let mut map = HashMap::new();
|
|
48
|
+
|
|
49
|
+
while let Some(key_token) = parser.peek_clone() {
|
|
50
|
+
if key_token.kind == TokenKind::RBrace {
|
|
51
|
+
parser.advance(); // consume '}'
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if key_token.kind != TokenKind::Identifier {
|
|
56
|
+
return Statement::error(
|
|
57
|
+
token,
|
|
58
|
+
"Expected key identifier in map".to_string()
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
parser.advance();
|
|
62
|
+
let key = key_token.lexeme.clone();
|
|
63
|
+
|
|
64
|
+
if !parser.match_token(TokenKind::Colon) {
|
|
65
|
+
let message = format!("Expected ':' after key '{}'", key);
|
|
66
|
+
return Statement::error(token, message);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let val = match parser.peek_clone() {
|
|
70
|
+
Some(t) if t.kind == TokenKind::Number => {
|
|
71
|
+
parser.advance();
|
|
72
|
+
Value::Number(t.lexeme.parse().unwrap_or(0.0))
|
|
73
|
+
}
|
|
74
|
+
Some(t) if t.kind == TokenKind::String => {
|
|
75
|
+
parser.advance();
|
|
76
|
+
Value::String(t.lexeme.clone())
|
|
77
|
+
}
|
|
78
|
+
Some(t) if t.kind == TokenKind::Identifier => {
|
|
79
|
+
parser.advance();
|
|
80
|
+
Value::Identifier(t.lexeme.clone())
|
|
81
|
+
}
|
|
82
|
+
_ => { Value::Null }
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
if val == Value::Null {
|
|
86
|
+
let message = format!("Invalid value for key '{}'", key);
|
|
87
|
+
return Statement::error(token, message);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
map.insert(key, val);
|
|
91
|
+
|
|
92
|
+
if let Some(t) = parser.peek() {
|
|
93
|
+
if t.kind == TokenKind::Comma {
|
|
94
|
+
parser.advance(); // skip comma
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Value::Map(map)
|
|
100
|
+
}
|
|
101
|
+
other => {
|
|
102
|
+
let message = format!("Unexpected value token in let: {:?}", other);
|
|
103
|
+
return Statement::error(current_token, message);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
return Statement {
|
|
108
|
+
kind: StatementKind::Let { name: identifier },
|
|
109
|
+
value,
|
|
110
|
+
indent: current_token.indent,
|
|
111
|
+
line: current_token.line,
|
|
112
|
+
column: current_token.column,
|
|
113
|
+
};
|
|
114
|
+
} else {
|
|
115
|
+
// Unknown identifier handling
|
|
116
|
+
Statement {
|
|
117
|
+
kind: StatementKind::Unknown,
|
|
118
|
+
value: Value::String(current_token.lexeme.clone()),
|
|
119
|
+
indent: current_token.indent,
|
|
120
|
+
line: current_token.line,
|
|
121
|
+
column: current_token.column,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
parser.advance(); // unknown identifier fallback
|
|
126
|
+
|
|
127
|
+
Statement {
|
|
128
|
+
kind: StatementKind::Unknown,
|
|
129
|
+
value: Value::String(current_token.lexeme.clone()),
|
|
130
|
+
indent: current_token.indent,
|
|
131
|
+
line: current_token.line,
|
|
132
|
+
column: current_token.column,
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::core::{
|
|
4
|
+
lexer::{ token::TokenKind },
|
|
5
|
+
parser::{ statement::{ Statement, StatementKind }, Parser },
|
|
6
|
+
shared::value::Value,
|
|
7
|
+
store::global::GlobalStore,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
|
|
11
|
+
parser.advance(); // consume 'loop'
|
|
12
|
+
|
|
13
|
+
let Some(loop_token) = parser.previous_clone() else {
|
|
14
|
+
return Statement::unknown();
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// Expect an identifier (iterator)
|
|
18
|
+
let Some(iterator_token) = parser.peek_clone() else {
|
|
19
|
+
return Statement::error(loop_token, "Expected identifier after 'loop'".to_string());
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
let iterator_name = iterator_token.lexeme.clone();
|
|
23
|
+
parser.advance(); // consume iterator
|
|
24
|
+
|
|
25
|
+
// Expect colon
|
|
26
|
+
let Some(colon_token) = parser.peek_clone() else {
|
|
27
|
+
return Statement::error(iterator_token.clone(), "Expected ':' after iterator".to_string());
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
if colon_token.kind != TokenKind::Colon {
|
|
31
|
+
let message = format!("Expected ':' after iterator, got {:?}", colon_token.kind);
|
|
32
|
+
return Statement::error(colon_token.clone(), message);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
parser.advance(); // consume ':'
|
|
36
|
+
|
|
37
|
+
// Collect all indented statements
|
|
38
|
+
let tokens = parser.collect_until(
|
|
39
|
+
|t| (t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF)
|
|
40
|
+
);
|
|
41
|
+
let loop_body = parser.parse_block(tokens.clone(), global_store);
|
|
42
|
+
|
|
43
|
+
let mut value_map = HashMap::new();
|
|
44
|
+
|
|
45
|
+
value_map.insert("iterator".to_string(), Value::Identifier(iterator_name));
|
|
46
|
+
value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
|
|
47
|
+
|
|
48
|
+
Statement {
|
|
49
|
+
kind: StatementKind::Loop,
|
|
50
|
+
value: Value::Map(value_map),
|
|
51
|
+
indent: loop_token.indent,
|
|
52
|
+
line: loop_token.line,
|
|
53
|
+
column: loop_token.column,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::token::TokenKind,
|
|
3
|
+
parser::{ statement::{ Statement, StatementKind }, Parser },
|
|
4
|
+
shared::value::Value,
|
|
5
|
+
store::global::GlobalStore,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
|
|
9
|
+
parser.advance(); // consume 'bpm'
|
|
10
|
+
|
|
11
|
+
let Some(tempo_token) = parser.previous_clone() else {
|
|
12
|
+
return Statement::unknown();
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Expect a number or identifier
|
|
16
|
+
let Some(value_token) = parser.peek_clone() else {
|
|
17
|
+
return Statement::error(
|
|
18
|
+
tempo_token,
|
|
19
|
+
"Expected a number or identifier after 'bpm'".to_string()
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
let value = match value_token.kind {
|
|
24
|
+
TokenKind::Number => {
|
|
25
|
+
parser.advance();
|
|
26
|
+
Value::Number(value_token.lexeme.parse().unwrap_or(0.0))
|
|
27
|
+
}
|
|
28
|
+
TokenKind::Identifier => {
|
|
29
|
+
parser.advance();
|
|
30
|
+
Value::Identifier(value_token.lexeme.clone())
|
|
31
|
+
}
|
|
32
|
+
_ => {
|
|
33
|
+
return Statement::error(
|
|
34
|
+
value_token.clone(),
|
|
35
|
+
format!("Expected a number or identifier after 'bpm', got {:?}", value_token.kind)
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
Statement {
|
|
41
|
+
kind: StatementKind::Tempo,
|
|
42
|
+
value,
|
|
43
|
+
indent: tempo_token.indent,
|
|
44
|
+
line: tempo_token.line,
|
|
45
|
+
column: tempo_token.column,
|
|
46
|
+
}
|
|
47
|
+
}
|