@devaloop/devalang 0.0.1-alpha.2 → 0.0.1-alpha.4
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 +1 -1
- package/Cargo.toml +46 -46
- package/README.md +48 -30
- package/docs/CHANGELOG.md +28 -6
- package/docs/COMMANDS.md +31 -0
- package/docs/CONFIG.md +6 -4
- package/docs/ROADMAP.md +5 -1
- package/docs/TODO.md +10 -35
- package/examples/exported.deva +1 -1
- package/examples/index.deva +8 -1
- package/examples/samples/hat-808.wav +0 -0
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +41 -42
- package/project-version.json +5 -5
- package/rust/audio/engine.rs +130 -0
- package/rust/audio/interpreter.rs +143 -0
- package/rust/audio/loader.rs +46 -0
- package/rust/audio/mod.rs +5 -1
- package/rust/audio/player.rs +54 -0
- package/rust/audio/render.rs +57 -0
- package/rust/cli/build.rs +73 -45
- package/rust/cli/check.rs +47 -111
- package/rust/cli/init.rs +1 -1
- package/rust/cli/mod.rs +203 -2
- package/rust/cli/play.rs +191 -0
- package/rust/{utils/config.rs → config/loader.rs} +3 -2
- package/rust/config/mod.rs +16 -0
- package/rust/core/builder/mod.rs +69 -27
- package/rust/core/debugger/lexer.rs +27 -0
- package/rust/core/debugger/mod.rs +12 -49
- package/rust/core/debugger/preprocessor.rs +27 -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 +116 -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/bank.rs +38 -51
- package/rust/core/preprocessor/resolver/loop_.rs +126 -65
- package/rust/core/preprocessor/resolver/mod.rs +119 -80
- package/rust/core/preprocessor/resolver/tempo.rs +40 -61
- package/rust/core/preprocessor/resolver/trigger.rs +93 -155
- 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 +22 -18
- package/rust/utils/logger.rs +69 -34
- package/rust/utils/mod.rs +3 -5
- package/rust/utils/watcher.rs +10 -2
- package/templates/minimal/.devalang +1 -1
- package/templates/welcome/.devalang +1 -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/types/cli.rs +0 -182
- package/rust/core/types/config.rs +0 -15
- 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
package/rust/core/builder/mod.rs
CHANGED
|
@@ -1,37 +1,79 @@
|
|
|
1
|
-
use crate::
|
|
2
|
-
use
|
|
1
|
+
use crate::audio::render::render_audio_with_modules;
|
|
2
|
+
use crate::core::parser::statement::Statement;
|
|
3
|
+
use crate::core::store::global::GlobalStore;
|
|
4
|
+
use crate::utils::logger::Logger;
|
|
5
|
+
use std::{ collections::HashMap, fs::create_dir_all };
|
|
3
6
|
use std::io::Write;
|
|
4
7
|
|
|
5
|
-
pub
|
|
6
|
-
let mut ast_string = String::new();
|
|
8
|
+
pub struct Builder {}
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
})
|
|
13
|
-
.unwrap_or_else(|err| {
|
|
14
|
-
eprintln!("Error serializing AST: {}", err);
|
|
15
|
-
std::process::exit(1);
|
|
16
|
-
});
|
|
10
|
+
impl Builder {
|
|
11
|
+
pub fn new() -> Self {
|
|
12
|
+
Builder {}
|
|
13
|
+
}
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
pub fn build_ast(&self, modules: &HashMap<String, Vec<Statement>>) {
|
|
16
|
+
let output_path = "./output";
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
for (name, statements) in modules {
|
|
19
|
+
let formatted_name = name.split("/").last().unwrap_or(name);
|
|
20
|
+
let formatted_name = formatted_name.replace(".deva", "");
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
create_dir_all(format!("{}/ast", output_path)).expect("Failed to create AST directory");
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
24
|
+
let file_path = format!("{}/ast/{}.json", output_path, formatted_name);
|
|
25
|
+
let mut file = std::fs::File::create(file_path).expect("Failed to create AST file");
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
let content = serde_json
|
|
28
|
+
::to_string_pretty(&statements)
|
|
29
|
+
.expect("Failed to serialize AST");
|
|
30
|
+
|
|
31
|
+
file.write_all(content.as_bytes()).expect("Failed to write AST to file");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
pub fn build_audio(
|
|
36
|
+
&self,
|
|
37
|
+
modules: &HashMap<String, Vec<Statement>>,
|
|
38
|
+
normalized_output_dir: &str,
|
|
39
|
+
global_store: &mut GlobalStore
|
|
40
|
+
) {
|
|
41
|
+
let logger = Logger::new();
|
|
42
|
+
|
|
43
|
+
let audio_engines = render_audio_with_modules(
|
|
44
|
+
modules.clone(),
|
|
45
|
+
&normalized_output_dir,
|
|
46
|
+
global_store
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
create_dir_all(format!("{}/audio", normalized_output_dir)).expect("Failed to create audio directory");
|
|
50
|
+
|
|
51
|
+
for (module_name, mut audio_engine) in audio_engines {
|
|
52
|
+
let formatted_module_name = module_name
|
|
53
|
+
.split('/')
|
|
54
|
+
.last()
|
|
55
|
+
.unwrap_or(&module_name)
|
|
56
|
+
.replace(".deva", "");
|
|
57
|
+
|
|
58
|
+
let output_path = format!(
|
|
59
|
+
"{}/audio/{}.wav",
|
|
60
|
+
normalized_output_dir,
|
|
61
|
+
formatted_module_name
|
|
62
|
+
);
|
|
34
63
|
|
|
35
|
-
|
|
36
|
-
|
|
64
|
+
match audio_engine.generate_wav_file(&output_path) {
|
|
65
|
+
Ok(_) => {}
|
|
66
|
+
Err(msg) => {
|
|
67
|
+
logger.log_error_with_stacktrace(
|
|
68
|
+
&format!(
|
|
69
|
+
"Unable to generate WAV file for module '{}': {}",
|
|
70
|
+
formatted_module_name,
|
|
71
|
+
msg
|
|
72
|
+
),
|
|
73
|
+
&module_name
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
37
79
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
use std::{ collections::HashMap, fs::create_dir_all };
|
|
2
|
+
use crate::core::{ debugger::Debugger, lexer::token::Token, parser::statement::Statement };
|
|
3
|
+
|
|
4
|
+
pub fn write_lexer_log_file(
|
|
5
|
+
output_dir: &str,
|
|
6
|
+
file_name: &str,
|
|
7
|
+
modules: HashMap<String, Vec<Token>>
|
|
8
|
+
) {
|
|
9
|
+
let debugger = Debugger::new();
|
|
10
|
+
let mut content = String::new();
|
|
11
|
+
|
|
12
|
+
let log_directory = format!("{}/logs", output_dir);
|
|
13
|
+
|
|
14
|
+
create_dir_all(&log_directory).expect("Failed to create log directory");
|
|
15
|
+
|
|
16
|
+
for (path, tokens) in modules {
|
|
17
|
+
content.push_str(&format!("--- Resolved Tokens for {} ---\n", path));
|
|
18
|
+
|
|
19
|
+
for token in tokens {
|
|
20
|
+
content.push_str(&format!("{:?}\n", token));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
content.push_str("\n");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
debugger.write_log_file(&log_directory, file_name, &content);
|
|
27
|
+
}
|
|
@@ -1,57 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
pub mod preprocessor;
|
|
2
|
+
pub mod lexer;
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
4
|
+
use std::io::Write;
|
|
5
|
+
|
|
6
|
+
pub struct Debugger {}
|
|
6
7
|
|
|
7
8
|
impl Debugger {
|
|
8
|
-
pub fn new(
|
|
9
|
-
Debugger {
|
|
10
|
-
module: module.clone(),
|
|
11
|
-
}
|
|
9
|
+
pub fn new() -> Self {
|
|
10
|
+
Debugger {}
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
pub fn
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let lexer_path = format!("{}{}", output_dir, LEXER_FILENAME);
|
|
19
|
-
let statements_path = format!("{}{}", output_dir, STATEMENTS_FILENAME);
|
|
20
|
-
|
|
21
|
-
// Collect debug information
|
|
22
|
-
let tokens = self.module.tokens
|
|
23
|
-
.iter()
|
|
24
|
-
.map(|token| format!("{:?}", token))
|
|
25
|
-
.collect::<Vec<String>>();
|
|
26
|
-
let statements = resolved_statements
|
|
27
|
-
.iter()
|
|
28
|
-
.map(|stmt| format!("{:?}", stmt))
|
|
29
|
-
.collect::<Vec<String>>();
|
|
13
|
+
pub fn write_log_file(&self, path: &str, filename: &str, content: &str) {
|
|
14
|
+
std::fs::create_dir_all(path).expect("Failed to create directory");
|
|
15
|
+
let file_path = format!("{}/{}", path, filename);
|
|
16
|
+
let mut file = std::fs::File::create(file_path).expect("Failed to create file");
|
|
30
17
|
|
|
31
|
-
|
|
32
|
-
clear_debug_directory(output_dir);
|
|
33
|
-
create_debug_directory(output_dir);
|
|
34
|
-
|
|
35
|
-
// Writing files
|
|
36
|
-
write_tokens_debug_to_file(&tokens, &lexer_path);
|
|
37
|
-
write_statements_debug_to_file(&statements, &statements_path);
|
|
18
|
+
file.write_all(content.as_bytes()).expect("Failed to write to file");
|
|
38
19
|
}
|
|
39
20
|
}
|
|
40
|
-
|
|
41
|
-
fn clear_debug_directory(path: &str) {
|
|
42
|
-
std::fs::remove_dir_all(path);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
fn create_debug_directory(path: &str) {
|
|
46
|
-
std::fs::create_dir_all(path);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
fn write_statements_debug_to_file(statements: &Vec<String>, path: &str) {
|
|
50
|
-
let content = statements.join("\n");
|
|
51
|
-
std::fs::write(path, content).expect("Unable to write statements to file");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
fn write_tokens_debug_to_file(tokens: &Vec<String>, path: &str) {
|
|
55
|
-
let content = tokens.join("\n");
|
|
56
|
-
std::fs::write(path, content).expect("Unable to write tokens to file");
|
|
57
|
-
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
use std::{ collections::HashMap, fs::create_dir_all };
|
|
2
|
+
use crate::core::{ debugger::Debugger, parser::statement::Statement };
|
|
3
|
+
|
|
4
|
+
pub fn write_preprocessor_log_file(
|
|
5
|
+
output_dir: &str,
|
|
6
|
+
file_name: &str,
|
|
7
|
+
modules: HashMap<String, Vec<Statement>>
|
|
8
|
+
) {
|
|
9
|
+
let debugger = Debugger::new();
|
|
10
|
+
let mut content = String::new();
|
|
11
|
+
|
|
12
|
+
let log_directory = format!("{}/logs", output_dir);
|
|
13
|
+
|
|
14
|
+
create_dir_all(&log_directory).expect("Failed to create log directory");
|
|
15
|
+
|
|
16
|
+
for (path, stmts) in modules {
|
|
17
|
+
content.push_str(&format!("--- Resolved Statements for {} ---\n", path));
|
|
18
|
+
|
|
19
|
+
for stmt in stmts {
|
|
20
|
+
content.push_str(&format!("{:?}\n", stmt));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
content.push_str("\n");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
debugger.write_log_file(&log_directory, file_name, &content);
|
|
27
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
use crate::core::parser::{ statement::{ Statement, StatementKind }, Parser };
|
|
2
|
+
|
|
3
|
+
pub struct ErrorHandler {
|
|
4
|
+
errors: Vec<Error>,
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
pub struct Error {
|
|
8
|
+
pub message: String,
|
|
9
|
+
pub line: usize,
|
|
10
|
+
pub column: usize,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
impl ErrorHandler {
|
|
14
|
+
pub fn new() -> Self {
|
|
15
|
+
Self { errors: Vec::new() }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
pub fn add_error(&mut self, message: String, line: usize, column: usize) {
|
|
19
|
+
let error_statement = Error {
|
|
20
|
+
message,
|
|
21
|
+
line,
|
|
22
|
+
column,
|
|
23
|
+
};
|
|
24
|
+
self.errors.push(error_statement);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub fn has_errors(&self) -> bool {
|
|
28
|
+
!self.errors.is_empty()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pub fn get_errors(&self) -> &Vec<Error> {
|
|
32
|
+
&self.errors
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
pub fn clear_errors(&mut self) {
|
|
36
|
+
self.errors.clear();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
pub fn detect_from_statements(&mut self, parser: &mut Parser, statements: &[Statement]) {
|
|
40
|
+
for stmt in statements {
|
|
41
|
+
match &stmt.kind {
|
|
42
|
+
StatementKind::Unknown => {
|
|
43
|
+
self.add_error(
|
|
44
|
+
"Unknown statement".to_string(),
|
|
45
|
+
stmt.line,
|
|
46
|
+
stmt.column
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
StatementKind::Error { message } => {
|
|
50
|
+
self.add_error(
|
|
51
|
+
message.clone(),
|
|
52
|
+
stmt.line,
|
|
53
|
+
stmt.column
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
_ => {}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use crate::core::
|
|
1
|
+
use crate::core::lexer::token::{Token, TokenKind};
|
|
2
2
|
|
|
3
3
|
pub fn handle_comment_lexer(
|
|
4
4
|
char: char,
|
|
@@ -21,8 +21,8 @@ pub fn handle_comment_lexer(
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
tokens.push(Token {
|
|
24
|
-
kind: TokenKind::Comment
|
|
25
|
-
lexeme:
|
|
24
|
+
kind: TokenKind::Comment,
|
|
25
|
+
lexeme: comment.trim().to_string(),
|
|
26
26
|
line: *line,
|
|
27
27
|
column: *column,
|
|
28
28
|
indent: *current_indent,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use crate::core::
|
|
1
|
+
use crate::core::lexer::token::{ Token, TokenKind };
|
|
2
2
|
|
|
3
3
|
pub fn handle_indent_lexer(
|
|
4
4
|
chars: &mut std::iter::Peekable<std::str::Chars>,
|
|
@@ -7,19 +7,26 @@ pub fn handle_indent_lexer(
|
|
|
7
7
|
tokens: &mut Vec<Token>,
|
|
8
8
|
line: &mut usize,
|
|
9
9
|
column: &mut usize
|
|
10
|
-
)
|
|
10
|
+
) {
|
|
11
11
|
*current_indent = 0;
|
|
12
|
+
let mut col = *column;
|
|
12
13
|
|
|
13
14
|
while let Some(&c) = chars.peek() {
|
|
14
15
|
if c == ' ' {
|
|
15
16
|
*current_indent += 1;
|
|
16
17
|
chars.next();
|
|
17
|
-
|
|
18
|
+
col += 1;
|
|
19
|
+
} else if c == '\t' {
|
|
20
|
+
*current_indent += 4; // tabulation = 4 espaces
|
|
21
|
+
chars.next();
|
|
22
|
+
col += 4;
|
|
18
23
|
} else {
|
|
19
24
|
break;
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
27
|
|
|
28
|
+
*column = col;
|
|
29
|
+
|
|
23
30
|
let last_indent = *indent_stack.last().unwrap();
|
|
24
31
|
if *current_indent > last_indent {
|
|
25
32
|
indent_stack.push(*current_indent);
|
|
@@ -42,6 +49,4 @@ pub fn handle_indent_lexer(
|
|
|
42
49
|
});
|
|
43
50
|
}
|
|
44
51
|
}
|
|
45
|
-
|
|
46
|
-
(tokens.clone(), indent_stack.clone(), *line, *column)
|
|
47
52
|
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
pub mod at;
|
|
2
|
+
pub mod brace;
|
|
3
|
+
pub mod colon;
|
|
4
|
+
pub mod comment;
|
|
5
|
+
pub mod dot;
|
|
6
|
+
pub mod equal;
|
|
7
|
+
pub mod identifier;
|
|
8
|
+
pub mod newline;
|
|
9
|
+
pub mod number;
|
|
10
|
+
pub mod indent;
|
|
11
|
+
pub mod string;
|
|
12
|
+
|
|
13
|
+
use crate::core::lexer::{
|
|
14
|
+
handler::{
|
|
15
|
+
at::handle_at_lexer,
|
|
16
|
+
brace::{ handle_lbrace_lexer, handle_rbrace_lexer },
|
|
17
|
+
colon::handle_colon_lexer,
|
|
18
|
+
comment::handle_comment_lexer,
|
|
19
|
+
dot::handle_dot_lexer,
|
|
20
|
+
equal::handle_equal_lexer,
|
|
21
|
+
identifier::handle_identifier_lexer,
|
|
22
|
+
indent::handle_indent_lexer,
|
|
23
|
+
newline::handle_newline_lexer,
|
|
24
|
+
number::handle_number_lexer,
|
|
25
|
+
string::handle_string_lexer,
|
|
26
|
+
},
|
|
27
|
+
token::{ Token, TokenKind },
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
fn advance_char<I: Iterator<Item = char>>(
|
|
31
|
+
chars: &mut std::iter::Peekable<I>,
|
|
32
|
+
line: &mut usize,
|
|
33
|
+
column: &mut usize
|
|
34
|
+
) -> Option<char> {
|
|
35
|
+
let c = chars.next()?;
|
|
36
|
+
if c == '\n' {
|
|
37
|
+
*line += 1;
|
|
38
|
+
*column = 1;
|
|
39
|
+
} else {
|
|
40
|
+
*column += 1;
|
|
41
|
+
}
|
|
42
|
+
Some(c)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pub fn handle_content_lexing(content: String) -> Vec<Token> {
|
|
46
|
+
let mut tokens = Vec::new();
|
|
47
|
+
|
|
48
|
+
let mut line = 1;
|
|
49
|
+
let mut column = 1;
|
|
50
|
+
|
|
51
|
+
let mut indent_stack: Vec<usize> = vec![0];
|
|
52
|
+
let mut current_indent = 0;
|
|
53
|
+
let mut at_line_start = true;
|
|
54
|
+
|
|
55
|
+
let mut chars = content.chars().peekable();
|
|
56
|
+
|
|
57
|
+
while chars.peek().is_some() {
|
|
58
|
+
if at_line_start {
|
|
59
|
+
handle_indent_lexer(
|
|
60
|
+
&mut chars,
|
|
61
|
+
&mut current_indent,
|
|
62
|
+
&mut indent_stack,
|
|
63
|
+
&mut tokens,
|
|
64
|
+
&mut line,
|
|
65
|
+
&mut column
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
at_line_start = false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let Some(ch) = advance_char(&mut chars, &mut line, &mut column) else {
|
|
72
|
+
break;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
match ch {
|
|
76
|
+
'\n' => {
|
|
77
|
+
handle_newline_lexer(
|
|
78
|
+
ch,
|
|
79
|
+
&mut chars,
|
|
80
|
+
&mut tokens,
|
|
81
|
+
&mut line,
|
|
82
|
+
&mut column,
|
|
83
|
+
&mut at_line_start,
|
|
84
|
+
&mut current_indent
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
' ' | '\t' => {
|
|
88
|
+
// Already handled by indent_lexer
|
|
89
|
+
}
|
|
90
|
+
'#' => {
|
|
91
|
+
handle_comment_lexer(
|
|
92
|
+
ch,
|
|
93
|
+
&mut chars,
|
|
94
|
+
&mut current_indent,
|
|
95
|
+
&mut indent_stack,
|
|
96
|
+
&mut tokens,
|
|
97
|
+
&mut line,
|
|
98
|
+
&mut column
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
':' => {
|
|
102
|
+
handle_colon_lexer(
|
|
103
|
+
ch,
|
|
104
|
+
&mut chars,
|
|
105
|
+
&mut current_indent,
|
|
106
|
+
&mut indent_stack,
|
|
107
|
+
&mut tokens,
|
|
108
|
+
&mut line,
|
|
109
|
+
&mut column
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
'=' => {
|
|
113
|
+
handle_equal_lexer(
|
|
114
|
+
ch,
|
|
115
|
+
&mut chars,
|
|
116
|
+
&mut current_indent,
|
|
117
|
+
&mut indent_stack,
|
|
118
|
+
&mut tokens,
|
|
119
|
+
&mut line,
|
|
120
|
+
&mut column
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
'{' => {
|
|
124
|
+
handle_lbrace_lexer(
|
|
125
|
+
ch,
|
|
126
|
+
&mut chars,
|
|
127
|
+
&mut current_indent,
|
|
128
|
+
&mut indent_stack,
|
|
129
|
+
&mut tokens,
|
|
130
|
+
&mut line,
|
|
131
|
+
&mut column
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
'}' => {
|
|
135
|
+
handle_rbrace_lexer(
|
|
136
|
+
ch,
|
|
137
|
+
&mut chars,
|
|
138
|
+
&mut current_indent,
|
|
139
|
+
&mut indent_stack,
|
|
140
|
+
&mut tokens,
|
|
141
|
+
&mut line,
|
|
142
|
+
&mut column
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
'.' => {
|
|
146
|
+
handle_dot_lexer(
|
|
147
|
+
ch,
|
|
148
|
+
&mut chars,
|
|
149
|
+
&mut current_indent,
|
|
150
|
+
&mut indent_stack,
|
|
151
|
+
&mut tokens,
|
|
152
|
+
&mut line,
|
|
153
|
+
&mut column
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
'@' => {
|
|
157
|
+
handle_at_lexer(
|
|
158
|
+
ch,
|
|
159
|
+
&mut chars,
|
|
160
|
+
&mut current_indent,
|
|
161
|
+
&mut indent_stack,
|
|
162
|
+
&mut tokens,
|
|
163
|
+
&mut line,
|
|
164
|
+
&mut column
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
'\"' | '\'' => {
|
|
168
|
+
handle_string_lexer(
|
|
169
|
+
ch,
|
|
170
|
+
&mut chars,
|
|
171
|
+
&mut current_indent,
|
|
172
|
+
&mut indent_stack,
|
|
173
|
+
&mut tokens,
|
|
174
|
+
&mut line,
|
|
175
|
+
&mut column
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
c if c.is_ascii_digit() => {
|
|
179
|
+
handle_number_lexer(
|
|
180
|
+
c,
|
|
181
|
+
&mut chars,
|
|
182
|
+
&mut current_indent,
|
|
183
|
+
&mut indent_stack,
|
|
184
|
+
&mut tokens,
|
|
185
|
+
&mut line,
|
|
186
|
+
&mut column
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
c if c.is_ascii_alphabetic() => {
|
|
190
|
+
handle_identifier_lexer(
|
|
191
|
+
c,
|
|
192
|
+
&mut chars,
|
|
193
|
+
&mut current_indent,
|
|
194
|
+
&mut indent_stack,
|
|
195
|
+
&mut tokens,
|
|
196
|
+
&mut line,
|
|
197
|
+
&mut column
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
_ => {
|
|
201
|
+
// Ignore unknown char
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
while indent_stack.len() > 1 {
|
|
207
|
+
indent_stack.pop();
|
|
208
|
+
current_indent = *indent_stack.last().unwrap();
|
|
209
|
+
tokens.push(Token {
|
|
210
|
+
kind: TokenKind::Dedent,
|
|
211
|
+
lexeme: String::new(),
|
|
212
|
+
line,
|
|
213
|
+
column,
|
|
214
|
+
indent: current_indent,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
tokens.push(Token {
|
|
219
|
+
kind: TokenKind::EOF,
|
|
220
|
+
lexeme: String::new(),
|
|
221
|
+
line: line + 1,
|
|
222
|
+
column: 0,
|
|
223
|
+
indent: 0,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// NOTE: Debug only
|
|
227
|
+
// for token in &tokens {
|
|
228
|
+
// println!(
|
|
229
|
+
// "{:?} @ line {}, col {}, indent {}",
|
|
230
|
+
// token.kind,
|
|
231
|
+
// token.line,
|
|
232
|
+
// token.column,
|
|
233
|
+
// token.indent
|
|
234
|
+
// );
|
|
235
|
+
// }
|
|
236
|
+
|
|
237
|
+
tokens
|
|
238
|
+
}
|
|
@@ -1,23 +1,19 @@
|
|
|
1
|
-
use crate::core::
|
|
1
|
+
use crate::core::lexer::token::{ Token, TokenKind };
|
|
2
2
|
|
|
3
3
|
pub fn handle_newline_lexer(
|
|
4
|
-
|
|
4
|
+
ch: char,
|
|
5
5
|
chars: &mut std::iter::Peekable<std::str::Chars>,
|
|
6
6
|
tokens: &mut Vec<Token>,
|
|
7
7
|
line: &mut usize,
|
|
8
8
|
column: &mut usize,
|
|
9
9
|
at_line_start: &mut bool,
|
|
10
|
-
current_indent: &mut usize
|
|
10
|
+
current_indent: &mut usize
|
|
11
11
|
) {
|
|
12
12
|
tokens.push(Token {
|
|
13
13
|
kind: TokenKind::Newline,
|
|
14
|
-
lexeme:
|
|
14
|
+
lexeme: ch.to_string(),
|
|
15
15
|
line: *line,
|
|
16
|
-
column:
|
|
17
|
-
indent:
|
|
16
|
+
column: 0,
|
|
17
|
+
indent: 0,
|
|
18
18
|
});
|
|
19
|
-
|
|
20
|
-
*line += 1;
|
|
21
|
-
*column = 1;
|
|
22
|
-
*at_line_start = true;
|
|
23
19
|
}
|