@devaloop/devalang 0.0.1-alpha.1
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 +45 -0
- package/LICENSE +21 -0
- package/README.md +161 -0
- package/docs/COMMANDS.md +31 -0
- package/docs/ROADMAP.md +27 -0
- package/docs/SYNTAX.md +148 -0
- package/docs/TODO.md +66 -0
- package/examples/exported.deva +7 -0
- package/examples/index.deva +9 -0
- package/examples/samples/kick-808.wav +0 -0
- package/out-tsc/bin/devalang.exe +0 -0
- package/out-tsc/bin/index.js +13 -0
- package/out-tsc/index.js +2 -0
- package/out-tsc/scripts/postbuild.js +11 -0
- package/out-tsc/scripts/version/bump.js +52 -0
- package/out-tsc/scripts/version/fetch.js +34 -0
- package/out-tsc/scripts/version/index.js +32 -0
- package/out-tsc/scripts/version/sync.js +32 -0
- package/package.json +43 -0
- package/project-version.json +6 -0
- package/rust/audio/mod.rs +1 -0
- package/rust/cli/build.rs +51 -0
- package/rust/cli/check.rs +124 -0
- package/rust/cli/mod.rs +3 -0
- package/rust/cli/new.rs +1 -0
- package/rust/core/builder/mod.rs +37 -0
- package/rust/core/debugger/mod.rs +57 -0
- package/rust/core/lexer/mod.rs +333 -0
- package/rust/core/mod.rs +6 -0
- package/rust/core/parser/at.rs +142 -0
- package/rust/core/parser/bank.rs +42 -0
- package/rust/core/parser/dot.rs +107 -0
- package/rust/core/parser/identifer.rs +91 -0
- package/rust/core/parser/loop_.rs +62 -0
- package/rust/core/parser/mod.rs +201 -0
- package/rust/core/parser/tempo.rs +42 -0
- package/rust/core/parser/variable.rs +129 -0
- package/rust/core/preprocessor/dependencies.rs +54 -0
- package/rust/core/preprocessor/mod.rs +26 -0
- package/rust/core/preprocessor/module.rs +70 -0
- package/rust/core/preprocessor/resolver/at.rs +24 -0
- package/rust/core/preprocessor/resolver/bank.rs +59 -0
- package/rust/core/preprocessor/resolver/loop_.rs +82 -0
- package/rust/core/preprocessor/resolver/mod.rs +113 -0
- package/rust/core/preprocessor/resolver/tempo.rs +70 -0
- package/rust/core/preprocessor/resolver/trigger.rs +176 -0
- package/rust/core/types/cli.rs +160 -0
- package/rust/core/types/mod.rs +7 -0
- package/rust/core/types/module.rs +41 -0
- package/rust/core/types/parser.rs +73 -0
- package/rust/core/types/statement.rs +105 -0
- package/rust/core/types/store.rs +116 -0
- package/rust/core/types/token.rs +83 -0
- package/rust/core/types/variable.rs +32 -0
- package/rust/lib.rs +1 -0
- package/rust/main.rs +49 -0
- package/rust/runner/executer.rs +44 -0
- package/rust/runner/mod.rs +1 -0
- package/rust/utils/loader.rs +19 -0
- package/rust/utils/logger.rs +49 -0
- package/rust/utils/mod.rs +5 -0
- package/rust/utils/path.rs +46 -0
- package/rust/utils/signature.rs +17 -0
- package/rust/utils/version.rs +15 -0
- package/tsconfig.json +113 -0
- package/typescript/bin/index.ts +14 -0
- package/typescript/index.ts +1 -0
- package/typescript/scripts/postbuild.ts +8 -0
- package/typescript/scripts/version/bump.ts +45 -0
- package/typescript/scripts/version/fetch.ts +23 -0
- package/typescript/scripts/version/index.ts +26 -0
- package/typescript/scripts/version/sync.ts +24 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::core::{
|
|
4
|
+
parser::parse_with_resolving_with_module,
|
|
5
|
+
types::{
|
|
6
|
+
module::Module,
|
|
7
|
+
statement::{ Statement, StatementKind, StatementResolved, StatementResolvedValue },
|
|
8
|
+
token::{ TokenDuration, TokenParamValue },
|
|
9
|
+
variable::VariableValue,
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
pub fn resolve_trigger_statement(
|
|
14
|
+
stmt: &Statement,
|
|
15
|
+
entity: String,
|
|
16
|
+
duration: TokenDuration,
|
|
17
|
+
module: &Module
|
|
18
|
+
) -> StatementResolved {
|
|
19
|
+
let mut entity_value = VariableValue::Unknown;
|
|
20
|
+
|
|
21
|
+
if let Some(value) = module.variable_table.variables.get(&entity) {
|
|
22
|
+
entity_value = value.clone();
|
|
23
|
+
} else {
|
|
24
|
+
entity_value = VariableValue::Text(entity.clone());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let duration_raw_value = match duration {
|
|
28
|
+
TokenDuration::Auto => "auto",
|
|
29
|
+
TokenDuration::Infinite => "infinite",
|
|
30
|
+
TokenDuration::Number(n) => &n.to_string(),
|
|
31
|
+
TokenDuration::Identifier(ref id) => id.as_str(),
|
|
32
|
+
_ => "unknown",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
let duration_variable_value = module.variable_table.variables.get(duration_raw_value);
|
|
36
|
+
let mut parsed_duration_value = TokenDuration::Unknown;
|
|
37
|
+
|
|
38
|
+
if duration_variable_value.is_some() {
|
|
39
|
+
parsed_duration_value = duration_variable_value
|
|
40
|
+
.as_ref()
|
|
41
|
+
.map_or(TokenDuration::Unknown, |value| {
|
|
42
|
+
match value {
|
|
43
|
+
VariableValue::Text(text) => TokenDuration::Identifier(text.clone()),
|
|
44
|
+
VariableValue::Number(num) => TokenDuration::Number(*num),
|
|
45
|
+
VariableValue::Boolean(_) => TokenDuration::Unknown,
|
|
46
|
+
_ => {
|
|
47
|
+
eprintln!("⚠️ Invalid duration type for Trigger: {:?}", value);
|
|
48
|
+
TokenDuration::Unknown
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
} else if let Ok(num) = duration_raw_value.parse::<f32>() {
|
|
53
|
+
parsed_duration_value = TokenDuration::Number(num);
|
|
54
|
+
} else if duration_raw_value == "auto" {
|
|
55
|
+
parsed_duration_value = TokenDuration::Auto;
|
|
56
|
+
} else if duration_raw_value == "infinite" {
|
|
57
|
+
parsed_duration_value = TokenDuration::Infinite;
|
|
58
|
+
} else {
|
|
59
|
+
eprintln!("⚠️ Invalid duration format: {}", duration_raw_value);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
match &stmt.value {
|
|
63
|
+
VariableValue::Text(text) => {
|
|
64
|
+
if let Some(value) = module.variable_table.variables.get(text) {
|
|
65
|
+
let parsed_entity_value: StatementResolvedValue = match value {
|
|
66
|
+
VariableValue::Array(arr) => {
|
|
67
|
+
StatementResolvedValue::Array(
|
|
68
|
+
parse_with_resolving_with_module(arr.clone(), module)
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
VariableValue::Map(map) => {
|
|
72
|
+
let mut resolved_map = HashMap::new();
|
|
73
|
+
|
|
74
|
+
for (key, value) in map {
|
|
75
|
+
let resolved_value = match value {
|
|
76
|
+
TokenParamValue::String(text) =>
|
|
77
|
+
StatementResolvedValue::String(text.clone()),
|
|
78
|
+
TokenParamValue::Number(num) =>
|
|
79
|
+
StatementResolvedValue::Number(*num),
|
|
80
|
+
TokenParamValue::Boolean(b) => StatementResolvedValue::Boolean(*b),
|
|
81
|
+
_ => {
|
|
82
|
+
eprintln!(
|
|
83
|
+
"⚠️ Unsupported variable type for Trigger map: {:?}",
|
|
84
|
+
value
|
|
85
|
+
);
|
|
86
|
+
StatementResolvedValue::Unknown
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
resolved_map.insert(key.clone(), resolved_value);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
StatementResolvedValue::Map(resolved_map)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
| VariableValue::Text(_)
|
|
96
|
+
| VariableValue::Number(_)
|
|
97
|
+
| VariableValue::Boolean(_) => {
|
|
98
|
+
StatementResolvedValue::String(text.clone())
|
|
99
|
+
}
|
|
100
|
+
_ => {
|
|
101
|
+
eprintln!("⚠️ Unsupported variable type for Trigger entity: {:?}", value);
|
|
102
|
+
StatementResolvedValue::Unknown
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
StatementResolved {
|
|
107
|
+
kind: StatementKind::Trigger {
|
|
108
|
+
entity: entity.clone(),
|
|
109
|
+
duration: parsed_duration_value,
|
|
110
|
+
},
|
|
111
|
+
value: parsed_entity_value,
|
|
112
|
+
indent: stmt.indent,
|
|
113
|
+
line: stmt.line,
|
|
114
|
+
column: stmt.column,
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
eprintln!("⚠️ Trigger variable '{}' not found", text);
|
|
118
|
+
StatementResolved {
|
|
119
|
+
kind: StatementKind::Trigger {
|
|
120
|
+
entity: entity.clone(),
|
|
121
|
+
duration: parsed_duration_value,
|
|
122
|
+
},
|
|
123
|
+
value: StatementResolvedValue::Unknown,
|
|
124
|
+
indent: stmt.indent,
|
|
125
|
+
line: stmt.line,
|
|
126
|
+
column: stmt.column,
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
VariableValue::Map(map) => {
|
|
131
|
+
let mut resolved_map = HashMap::new();
|
|
132
|
+
|
|
133
|
+
// TODO Handle nested maps and arrays
|
|
134
|
+
|
|
135
|
+
StatementResolved {
|
|
136
|
+
kind: StatementKind::Trigger {
|
|
137
|
+
entity: entity.clone(),
|
|
138
|
+
duration: parsed_duration_value,
|
|
139
|
+
},
|
|
140
|
+
value: StatementResolvedValue::Map(resolved_map),
|
|
141
|
+
indent: stmt.indent,
|
|
142
|
+
line: stmt.line,
|
|
143
|
+
column: stmt.column,
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
VariableValue::Null => {
|
|
147
|
+
StatementResolved {
|
|
148
|
+
kind: StatementKind::Trigger {
|
|
149
|
+
entity: entity.clone(),
|
|
150
|
+
duration: parsed_duration_value,
|
|
151
|
+
},
|
|
152
|
+
value: StatementResolvedValue::Map(HashMap::new()),
|
|
153
|
+
indent: stmt.indent,
|
|
154
|
+
line: stmt.line,
|
|
155
|
+
column: stmt.column,
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// TODO Parse other parameters
|
|
160
|
+
|
|
161
|
+
_ => {
|
|
162
|
+
eprintln!("⚠️ Invalid value type for Trigger statement: {:?}", stmt.value);
|
|
163
|
+
|
|
164
|
+
StatementResolved {
|
|
165
|
+
kind: StatementKind::Trigger {
|
|
166
|
+
entity: entity.clone(),
|
|
167
|
+
duration: parsed_duration_value,
|
|
168
|
+
},
|
|
169
|
+
value: StatementResolvedValue::Unknown,
|
|
170
|
+
indent: stmt.indent,
|
|
171
|
+
line: stmt.line,
|
|
172
|
+
column: stmt.column,
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
use clap::{ Parser, Subcommand };
|
|
2
|
+
use crate::utils::version::get_version;
|
|
3
|
+
|
|
4
|
+
#[derive(Parser)]
|
|
5
|
+
#[command(name = "devalang")]
|
|
6
|
+
#[command(author = "Devaloop")]
|
|
7
|
+
#[command(version = get_version())]
|
|
8
|
+
#[command(about = "🦊 Devalang – A programming language for music and sound.")]
|
|
9
|
+
pub struct Cli {
|
|
10
|
+
#[command(subcommand)]
|
|
11
|
+
pub command: CliCommands,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#[derive(Subcommand)]
|
|
15
|
+
pub enum CliTemplateCommand {
|
|
16
|
+
/// Lists all available templates for Devalang projects.
|
|
17
|
+
List,
|
|
18
|
+
/// Displays information about a specific template.
|
|
19
|
+
Info {
|
|
20
|
+
name: String,
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
pub enum CompilationMode {
|
|
25
|
+
/// Real-time compilation mode, for compiling files as soon as possible.
|
|
26
|
+
RealTime,
|
|
27
|
+
|
|
28
|
+
/// Batch compilation mode, for compiling files one by one.
|
|
29
|
+
Batch,
|
|
30
|
+
|
|
31
|
+
/// Check mode, used for analyzing the code without compiling it.
|
|
32
|
+
Check,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[derive(Subcommand)]
|
|
36
|
+
pub enum CliCommands {
|
|
37
|
+
/// Build the program and generate output files.
|
|
38
|
+
///
|
|
39
|
+
/// ### Arguments
|
|
40
|
+
/// - `entry` - The entry point of the program to build. Defaults to "./src".
|
|
41
|
+
/// - `output` - The directory where the output files will be generated. Defaults to "./output".
|
|
42
|
+
/// - `watch` - Whether to watch for changes and rebuild. Defaults to "true".
|
|
43
|
+
///
|
|
44
|
+
/// ### Example
|
|
45
|
+
/// ```bash
|
|
46
|
+
/// devalang build --entry ./src --output ./output --watch true
|
|
47
|
+
/// ```
|
|
48
|
+
///
|
|
49
|
+
Build {
|
|
50
|
+
#[arg(short, long, default_value = "./src")]
|
|
51
|
+
/// The entry point of the program to build.
|
|
52
|
+
///
|
|
53
|
+
/// ### Default value
|
|
54
|
+
/// - `./src`
|
|
55
|
+
///
|
|
56
|
+
entry: String,
|
|
57
|
+
|
|
58
|
+
#[arg(short, long, default_value = "./output")]
|
|
59
|
+
/// The directory where the output files will be generated.
|
|
60
|
+
///
|
|
61
|
+
/// ### Default value
|
|
62
|
+
/// - `./output`
|
|
63
|
+
///
|
|
64
|
+
output: String,
|
|
65
|
+
|
|
66
|
+
#[arg(short, long, default_value = "true")]
|
|
67
|
+
/// Whether to watch for changes and rebuild.
|
|
68
|
+
///
|
|
69
|
+
/// ### Default value
|
|
70
|
+
/// - `true`
|
|
71
|
+
///
|
|
72
|
+
watch: String,
|
|
73
|
+
|
|
74
|
+
#[arg(long, default_value = "real-time")]
|
|
75
|
+
/// The mode of compilation.
|
|
76
|
+
///
|
|
77
|
+
/// ### Default value
|
|
78
|
+
/// - `real-time`
|
|
79
|
+
///
|
|
80
|
+
/// ### Possible values
|
|
81
|
+
/// - `real-time` - Compiles files as soon as possible.
|
|
82
|
+
/// - `batch` - Compiles files one by one.
|
|
83
|
+
/// - `check` - Analyzes the code without compiling it.
|
|
84
|
+
///
|
|
85
|
+
compilation_mode: String,
|
|
86
|
+
|
|
87
|
+
#[arg(short, long, default_value = "false")]
|
|
88
|
+
/// Whether to print debug information.
|
|
89
|
+
///
|
|
90
|
+
/// ### Default value
|
|
91
|
+
/// - `false`
|
|
92
|
+
///
|
|
93
|
+
debug: String,
|
|
94
|
+
|
|
95
|
+
#[arg(short, long, default_value = "false")]
|
|
96
|
+
/// Whether to compress the output files.
|
|
97
|
+
///
|
|
98
|
+
/// ### Default value
|
|
99
|
+
/// - `false`
|
|
100
|
+
///
|
|
101
|
+
compress: String,
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/// Analyze the program for errors and warnings.
|
|
105
|
+
///
|
|
106
|
+
/// ### Arguments
|
|
107
|
+
/// - `entry` - The entry point of the program to analyze. Defaults to "./src".
|
|
108
|
+
/// - `watch` - Whether to watch for changes and re-analyze. Defaults to "true".
|
|
109
|
+
///
|
|
110
|
+
/// ### Example
|
|
111
|
+
/// ```bash
|
|
112
|
+
/// devalang check --entry ./src --watch true --compilation-mode real-time
|
|
113
|
+
/// ```
|
|
114
|
+
Check {
|
|
115
|
+
#[arg(short, long, default_value = "./src")]
|
|
116
|
+
/// The entry point of the program to analyze.
|
|
117
|
+
///
|
|
118
|
+
/// ### Default value
|
|
119
|
+
/// - `./src`
|
|
120
|
+
///
|
|
121
|
+
entry: String,
|
|
122
|
+
|
|
123
|
+
#[arg(short, long, default_value = "./output")]
|
|
124
|
+
/// The directory where the output files will be generated.
|
|
125
|
+
///
|
|
126
|
+
/// ### Default value
|
|
127
|
+
/// - `./output`
|
|
128
|
+
///
|
|
129
|
+
output: String,
|
|
130
|
+
|
|
131
|
+
#[arg(short, long, default_value = "false")]
|
|
132
|
+
/// Whether to watch for changes and re-analyze.
|
|
133
|
+
///
|
|
134
|
+
/// ### Default value
|
|
135
|
+
/// - `false`
|
|
136
|
+
///
|
|
137
|
+
watch: String,
|
|
138
|
+
|
|
139
|
+
#[arg(short, long, default_value = "real-time")]
|
|
140
|
+
/// The mode of compilation.
|
|
141
|
+
///
|
|
142
|
+
/// ### Default value
|
|
143
|
+
/// - `real-time`
|
|
144
|
+
///
|
|
145
|
+
/// ### Possible values
|
|
146
|
+
/// - `real-time` - Analyzes files as soon as possible.
|
|
147
|
+
/// - `batch` - Analyzes files one by one.
|
|
148
|
+
/// - `check` - Analyzes the code without compiling it.
|
|
149
|
+
///
|
|
150
|
+
compilation_mode: String,
|
|
151
|
+
|
|
152
|
+
#[arg(short, long, default_value = "false")]
|
|
153
|
+
/// Whether to print debug information.
|
|
154
|
+
///
|
|
155
|
+
/// ### Default value
|
|
156
|
+
/// - `false`
|
|
157
|
+
///
|
|
158
|
+
debug: String,
|
|
159
|
+
},
|
|
160
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
use crate::core::types::{
|
|
2
|
+
statement::Statement,
|
|
3
|
+
store::{ ExportTable, ImportTable, VariableTable },
|
|
4
|
+
token::Token,
|
|
5
|
+
variable::VariableValue,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
#[derive(Debug, Clone)]
|
|
9
|
+
pub struct Module {
|
|
10
|
+
pub path: String,
|
|
11
|
+
pub tokens: Vec<Token>,
|
|
12
|
+
pub statements: Vec<Statement>,
|
|
13
|
+
pub variable_table: VariableTable,
|
|
14
|
+
pub export_table: ExportTable,
|
|
15
|
+
pub import_table: ImportTable,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
impl Module {
|
|
19
|
+
pub fn new(path: String) -> Self {
|
|
20
|
+
Module {
|
|
21
|
+
path,
|
|
22
|
+
tokens: Vec::new(),
|
|
23
|
+
statements: Vec::new(),
|
|
24
|
+
variable_table: VariableTable::new(),
|
|
25
|
+
export_table: ExportTable::new(),
|
|
26
|
+
import_table: ImportTable::new(),
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
pub fn add_statement(&mut self, statement: Statement) {
|
|
31
|
+
self.statements.push(statement);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
pub fn set_variable(&mut self, name: String, value: VariableValue) {
|
|
35
|
+
self.variable_table.set(name, value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pub fn get_variable(&self, name: &str) -> Option<&VariableValue> {
|
|
39
|
+
self.variable_table.get(name)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
use crate::core::types::{
|
|
2
|
+
store::{ ExportTable, ImportTable, VariableTable },
|
|
3
|
+
token::{ Token, TokenKind },
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
#[derive(Debug, Clone)]
|
|
7
|
+
pub struct Parser {
|
|
8
|
+
pub tokens: Vec<Token>,
|
|
9
|
+
pub token_index: usize,
|
|
10
|
+
pub variable_table: VariableTable,
|
|
11
|
+
pub export_table: ExportTable,
|
|
12
|
+
pub import_table: ImportTable,
|
|
13
|
+
pub current_module: String,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
impl Parser {
|
|
17
|
+
pub fn new(tokens: Vec<Token>) -> Self {
|
|
18
|
+
Self {
|
|
19
|
+
tokens,
|
|
20
|
+
token_index: 0,
|
|
21
|
+
variable_table: VariableTable::new(),
|
|
22
|
+
export_table: ExportTable::new(),
|
|
23
|
+
import_table: ImportTable::new(),
|
|
24
|
+
current_module: String::new(),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pub fn set_tokens(&mut self, tokens: Vec<Token>) {
|
|
29
|
+
self.tokens = tokens;
|
|
30
|
+
self.token_index = 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pub fn peek(&self) -> Option<&Token> {
|
|
34
|
+
self.tokens.get(self.token_index)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
pub fn next(&mut self) -> Option<&Token> {
|
|
38
|
+
let tok = self.tokens.get(self.token_index);
|
|
39
|
+
self.token_index += 1;
|
|
40
|
+
tok
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
pub fn expect(&mut self, kind: TokenKind) -> Result<&Token, String> {
|
|
44
|
+
let tok = self.next().ok_or("Unexpected end of input")?;
|
|
45
|
+
if tok.kind == kind {
|
|
46
|
+
Ok(tok)
|
|
47
|
+
} else {
|
|
48
|
+
Err(format!("Expected {:?}, got {:?}", kind, tok.kind))
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
pub fn collect_until<F>(&mut self, condition: F) -> Vec<Token> where F: Fn(&Token) -> bool {
|
|
53
|
+
let mut collected = Vec::new();
|
|
54
|
+
while let Some(token) = self.peek() {
|
|
55
|
+
if token.kind == TokenKind::Newline || token.kind == TokenKind::Indent {
|
|
56
|
+
self.next(); // Skip newlines and indents
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if token.kind == TokenKind::EOF {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
if condition(token) {
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
collected.push(self.next().unwrap().clone());
|
|
66
|
+
}
|
|
67
|
+
collected
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
pub fn is_eof(&self) -> bool {
|
|
71
|
+
self.token_index >= self.tokens.len()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
use serde::Serialize;
|
|
3
|
+
use crate::core::types::{ token::{ Token, TokenDuration, TokenParam }, variable::VariableValue };
|
|
4
|
+
|
|
5
|
+
#[derive(Debug, Clone, Serialize)]
|
|
6
|
+
pub struct Statement {
|
|
7
|
+
pub kind: StatementKind,
|
|
8
|
+
pub value: VariableValue,
|
|
9
|
+
pub indent: usize,
|
|
10
|
+
pub line: usize,
|
|
11
|
+
pub column: usize,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#[derive(Debug, Clone, Serialize)]
|
|
15
|
+
pub struct StatementResolved {
|
|
16
|
+
pub kind: StatementKind,
|
|
17
|
+
pub value: StatementResolvedValue,
|
|
18
|
+
pub indent: usize,
|
|
19
|
+
pub line: usize,
|
|
20
|
+
pub column: usize,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#[derive(Debug, Clone, Serialize)]
|
|
24
|
+
pub enum StatementValue {
|
|
25
|
+
Boolean(bool),
|
|
26
|
+
Number(f32),
|
|
27
|
+
String(String),
|
|
28
|
+
Array(Vec<Statement>),
|
|
29
|
+
Map(HashMap<String, VariableValue>),
|
|
30
|
+
Unknown,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#[derive(Debug, Clone, Serialize)]
|
|
34
|
+
pub enum StatementResolvedValue {
|
|
35
|
+
Boolean(bool),
|
|
36
|
+
Number(f32),
|
|
37
|
+
String(String),
|
|
38
|
+
Array(Vec<StatementResolved>),
|
|
39
|
+
Map(HashMap<String, StatementResolvedValue>),
|
|
40
|
+
Unknown,
|
|
41
|
+
Null,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#[derive(Debug, Clone, Serialize)]
|
|
45
|
+
pub enum StatementIterator {
|
|
46
|
+
Identifier(String),
|
|
47
|
+
Number(f32),
|
|
48
|
+
Array(Vec<Statement>),
|
|
49
|
+
Map(HashMap<String, VariableValue>),
|
|
50
|
+
Unknown,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
#[derive(Debug, Serialize, Clone)]
|
|
54
|
+
/// Represents the kind of a statement
|
|
55
|
+
pub enum StatementKind {
|
|
56
|
+
// Trigger statements
|
|
57
|
+
Trigger {
|
|
58
|
+
entity: String,
|
|
59
|
+
duration: TokenDuration,
|
|
60
|
+
// params: Vec<TokenParam>,
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
// Variable statements
|
|
64
|
+
Let {
|
|
65
|
+
name: String,
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
// Loop statements
|
|
69
|
+
Loop {
|
|
70
|
+
iterator: StatementIterator,
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
// Conditional statements
|
|
74
|
+
// If {
|
|
75
|
+
// // condition: ConditionParts,
|
|
76
|
+
// condition_state: bool,
|
|
77
|
+
// body: Vec<Statement>,
|
|
78
|
+
// },
|
|
79
|
+
|
|
80
|
+
// Keyword statements
|
|
81
|
+
Tempo,
|
|
82
|
+
Bank,
|
|
83
|
+
|
|
84
|
+
// At (@) statements
|
|
85
|
+
Include(String),
|
|
86
|
+
Export,
|
|
87
|
+
Import {
|
|
88
|
+
names: Vec<String>,
|
|
89
|
+
source: String,
|
|
90
|
+
},
|
|
91
|
+
Load {
|
|
92
|
+
source: String,
|
|
93
|
+
alias: String,
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
// Error & Unknown statements
|
|
97
|
+
Unknown,
|
|
98
|
+
Error,
|
|
99
|
+
|
|
100
|
+
// Empty or ignored statements
|
|
101
|
+
Comment(String),
|
|
102
|
+
Indent,
|
|
103
|
+
Dedent,
|
|
104
|
+
NewLine,
|
|
105
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::core::types::{ module::Module, variable::VariableValue };
|
|
4
|
+
|
|
5
|
+
#[derive(Debug, Default)]
|
|
6
|
+
pub struct GlobalStore {
|
|
7
|
+
pub modules: HashMap<String, Module>,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
impl GlobalStore {
|
|
11
|
+
pub fn new() -> Self {
|
|
12
|
+
GlobalStore {
|
|
13
|
+
modules: HashMap::new(),
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
pub fn insert_module(&mut self, path: String, module: Module) {
|
|
18
|
+
self.modules.insert(path, module);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
pub fn update_module(&mut self, path: String, module: Module) {
|
|
22
|
+
if !self.modules.contains_key(&path) {
|
|
23
|
+
eprintln!("❌ Module {} not found in global store for update", path);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Remove the existing module if it exists
|
|
28
|
+
self.modules.remove(&path);
|
|
29
|
+
|
|
30
|
+
// Insert the updated module
|
|
31
|
+
self.modules.insert(path, module);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
pub fn get_module(&self, path: &str) -> Option<&Module> {
|
|
35
|
+
self.modules.get(path)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pub fn remove_module(&mut self, path: &str) -> Option<Module> {
|
|
39
|
+
self.modules.remove(path)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#[derive(Debug, Default, Clone)]
|
|
44
|
+
pub struct VariableTable {
|
|
45
|
+
pub variables: HashMap<String, VariableValue>,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
impl VariableTable {
|
|
49
|
+
pub fn new() -> Self {
|
|
50
|
+
VariableTable {
|
|
51
|
+
variables: HashMap::new(),
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fn set(&mut self, name: String, value: VariableValue) {
|
|
56
|
+
self.variables.insert(name, value);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
pub fn get(&self, name: &str) -> Option<&VariableValue> {
|
|
60
|
+
self.variables.get(name)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
pub fn remove(&mut self, name: &str) -> Option<VariableValue> {
|
|
64
|
+
self.variables.remove(name)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
#[derive(Debug, Default, Clone)]
|
|
69
|
+
pub struct ExportTable {
|
|
70
|
+
pub exports: HashMap<String, VariableValue>,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
impl ExportTable {
|
|
74
|
+
pub fn new() -> Self {
|
|
75
|
+
ExportTable {
|
|
76
|
+
exports: HashMap::new(),
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pub fn add_export(&mut self, name: String, value: VariableValue) {
|
|
81
|
+
self.exports.insert(name, value);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
pub fn get_export(&self, name: &str) -> Option<&VariableValue> {
|
|
85
|
+
self.exports.get(name)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pub fn remove_export(&mut self, name: &str) -> Option<VariableValue> {
|
|
89
|
+
self.exports.remove(name)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#[derive(Debug, Default, Clone)]
|
|
94
|
+
pub struct ImportTable {
|
|
95
|
+
pub imports: HashMap<String, VariableValue>,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
impl ImportTable {
|
|
99
|
+
pub fn new() -> Self {
|
|
100
|
+
ImportTable {
|
|
101
|
+
imports: HashMap::new(),
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
pub fn add_import(&mut self, name: String, value: VariableValue) {
|
|
106
|
+
self.imports.insert(name, value);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
pub fn get_import(&self, name: &str) -> Option<&VariableValue> {
|
|
110
|
+
self.imports.get(name)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
pub fn remove_import(&mut self, name: &str) -> Option<VariableValue> {
|
|
114
|
+
self.imports.remove(name)
|
|
115
|
+
}
|
|
116
|
+
}
|