@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.
Files changed (107) hide show
  1. package/.devalang +1 -1
  2. package/Cargo.toml +46 -46
  3. package/README.md +48 -30
  4. package/docs/CHANGELOG.md +28 -6
  5. package/docs/COMMANDS.md +31 -0
  6. package/docs/CONFIG.md +6 -4
  7. package/docs/ROADMAP.md +5 -1
  8. package/docs/TODO.md +10 -35
  9. package/examples/exported.deva +1 -1
  10. package/examples/index.deva +8 -1
  11. package/examples/samples/hat-808.wav +0 -0
  12. package/out-tsc/bin/devalang.exe +0 -0
  13. package/package.json +41 -42
  14. package/project-version.json +5 -5
  15. package/rust/audio/engine.rs +130 -0
  16. package/rust/audio/interpreter.rs +143 -0
  17. package/rust/audio/loader.rs +46 -0
  18. package/rust/audio/mod.rs +5 -1
  19. package/rust/audio/player.rs +54 -0
  20. package/rust/audio/render.rs +57 -0
  21. package/rust/cli/build.rs +73 -45
  22. package/rust/cli/check.rs +47 -111
  23. package/rust/cli/init.rs +1 -1
  24. package/rust/cli/mod.rs +203 -2
  25. package/rust/cli/play.rs +191 -0
  26. package/rust/{utils/config.rs → config/loader.rs} +3 -2
  27. package/rust/config/mod.rs +16 -0
  28. package/rust/core/builder/mod.rs +69 -27
  29. package/rust/core/debugger/lexer.rs +27 -0
  30. package/rust/core/debugger/mod.rs +12 -49
  31. package/rust/core/debugger/preprocessor.rs +27 -0
  32. package/rust/core/error/mod.rs +60 -0
  33. package/rust/core/lexer/{at.rs → handler/at.rs} +1 -1
  34. package/rust/core/lexer/{brace.rs → handler/brace.rs} +1 -1
  35. package/rust/core/lexer/{colon.rs → handler/colon.rs} +1 -1
  36. package/rust/core/lexer/{comment.rs → handler/comment.rs} +3 -3
  37. package/rust/core/lexer/{dot.rs → handler/dot.rs} +1 -1
  38. package/rust/core/lexer/{equal.rs → handler/equal.rs} +1 -1
  39. package/rust/core/lexer/{identifier.rs → handler/identifier.rs} +1 -1
  40. package/rust/core/lexer/{indent.rs → handler/indent.rs} +10 -5
  41. package/rust/core/lexer/handler/mod.rs +238 -0
  42. package/rust/core/lexer/{newline.rs → handler/newline.rs} +6 -10
  43. package/rust/core/lexer/{number.rs → handler/number.rs} +1 -1
  44. package/rust/core/lexer/handler/string.rs +66 -0
  45. package/rust/core/lexer/mod.rs +25 -14
  46. package/rust/core/lexer/token.rs +55 -0
  47. package/rust/core/mod.rs +5 -2
  48. package/rust/core/parser/handler/at.rs +166 -0
  49. package/rust/core/parser/handler/bank.rs +38 -0
  50. package/rust/core/parser/handler/dot.rs +112 -0
  51. package/rust/core/parser/handler/identifier.rs +134 -0
  52. package/rust/core/parser/handler/loop_.rs +55 -0
  53. package/rust/core/parser/handler/mod.rs +6 -0
  54. package/rust/core/parser/handler/tempo.rs +47 -0
  55. package/rust/core/parser/mod.rs +204 -166
  56. package/rust/core/parser/statement.rs +91 -0
  57. package/rust/core/preprocessor/loader.rs +116 -0
  58. package/rust/core/preprocessor/mod.rs +2 -24
  59. package/rust/core/preprocessor/module.rs +37 -56
  60. package/rust/core/preprocessor/processor.rs +41 -0
  61. package/rust/core/preprocessor/resolver/bank.rs +38 -51
  62. package/rust/core/preprocessor/resolver/loop_.rs +126 -65
  63. package/rust/core/preprocessor/resolver/mod.rs +119 -80
  64. package/rust/core/preprocessor/resolver/tempo.rs +40 -61
  65. package/rust/core/preprocessor/resolver/trigger.rs +93 -155
  66. package/rust/core/shared/duration.rs +8 -0
  67. package/rust/core/shared/mod.rs +2 -0
  68. package/rust/core/shared/value.rs +18 -0
  69. package/rust/core/store/export.rs +28 -0
  70. package/rust/core/store/global.rs +39 -0
  71. package/rust/core/store/import.rs +28 -0
  72. package/rust/core/store/mod.rs +4 -0
  73. package/rust/core/store/variable.rs +28 -0
  74. package/rust/core/utils/mod.rs +2 -0
  75. package/rust/core/utils/validation.rs +35 -0
  76. package/rust/lib.rs +0 -1
  77. package/rust/main.rs +22 -18
  78. package/rust/utils/logger.rs +69 -34
  79. package/rust/utils/mod.rs +3 -5
  80. package/rust/utils/watcher.rs +10 -2
  81. package/templates/minimal/.devalang +1 -1
  82. package/templates/welcome/.devalang +1 -1
  83. package/rust/core/lexer/bracket.rs +0 -41
  84. package/rust/core/lexer/driver.rs +0 -286
  85. package/rust/core/lexer/quote.rs +0 -61
  86. package/rust/core/parser/at.rs +0 -142
  87. package/rust/core/parser/bank.rs +0 -42
  88. package/rust/core/parser/dot.rs +0 -137
  89. package/rust/core/parser/identifer.rs +0 -91
  90. package/rust/core/parser/loop_.rs +0 -62
  91. package/rust/core/parser/tempo.rs +0 -42
  92. package/rust/core/parser/variable.rs +0 -129
  93. package/rust/core/preprocessor/dependencies.rs +0 -54
  94. package/rust/core/preprocessor/resolver/at.rs +0 -24
  95. package/rust/core/types/cli.rs +0 -182
  96. package/rust/core/types/config.rs +0 -15
  97. package/rust/core/types/mod.rs +0 -8
  98. package/rust/core/types/module.rs +0 -41
  99. package/rust/core/types/parser.rs +0 -73
  100. package/rust/core/types/statement.rs +0 -105
  101. package/rust/core/types/store.rs +0 -116
  102. package/rust/core/types/token.rs +0 -83
  103. package/rust/core/types/variable.rs +0 -32
  104. package/rust/runner/executer.rs +0 -44
  105. package/rust/runner/mod.rs +0 -1
  106. /package/rust/{utils → core/utils}/path.rs +0 -0
  107. /package/rust/utils/{loader.rs → spinner.rs} +0 -0
@@ -1,37 +1,79 @@
1
- use crate::core::types::statement::{ StatementResolved };
2
- use std::fs::File;
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 fn build_ast(statements: &Vec<StatementResolved>) -> String {
6
- let mut ast_string = String::new();
8
+ pub struct Builder {}
7
9
 
8
- serde_json
9
- ::to_string_pretty(statements)
10
- .map(|json| {
11
- ast_string.push_str(&json);
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
- ast_string
19
- }
15
+ pub fn build_ast(&self, modules: &HashMap<String, Vec<Statement>>) {
16
+ let output_path = "./output";
20
17
 
21
- pub fn write_ast_to_file(ast: &str, file_path: &str) {
22
- clear_json_directory(&file_path);
23
- create_json_directory(&file_path);
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
- let file_path = format!("{}/ast.json", file_path);
22
+ create_dir_all(format!("{}/ast", output_path)).expect("Failed to create AST directory");
26
23
 
27
- let mut file = File::create(&file_path).expect("Unable to create AST file");
28
- file.write_all(ast.as_bytes()).expect("Unable to write AST to file");
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
- fn clear_json_directory(path: &str) {
32
- std::fs::remove_dir_all(path);
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
- fn create_json_directory(path: &str) {
36
- std::fs::create_dir_all(path);
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
- use crate::core::types::{ module::Module, statement::{ StatementResolved } };
1
+ pub mod preprocessor;
2
+ pub mod lexer;
2
3
 
3
- pub struct Debugger {
4
- pub module: Module,
5
- }
4
+ use std::io::Write;
5
+
6
+ pub struct Debugger {}
6
7
 
7
8
  impl Debugger {
8
- pub fn new(module: &Module) -> Self {
9
- Debugger {
10
- module: module.clone(),
11
- }
9
+ pub fn new() -> Self {
10
+ Debugger {}
12
11
  }
13
12
 
14
- pub fn write_files(&self, output_dir: &str, resolved_statements: Vec<StatementResolved>) {
15
- const LEXER_FILENAME: &str = "debug_lexer.log";
16
- const STATEMENTS_FILENAME: &str = "debug_statements.log";
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
- // Ensure the debug directory exists and is cleared
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::types::token::{ Token, TokenKind };
1
+ use crate::core::lexer::token::{Token, TokenKind};
2
2
 
3
3
  pub fn handle_at_lexer(
4
4
  char: char,
@@ -1,4 +1,4 @@
1
- use crate::core::types::token::{ Token, TokenKind };
1
+ use crate::core::lexer::token::{ Token, TokenKind };
2
2
 
3
3
  pub fn handle_rbrace_lexer(
4
4
  char: char,
@@ -1,4 +1,4 @@
1
- use crate::core::types::token::{Token, TokenKind};
1
+ use crate::core::lexer::token::{Token, TokenKind};
2
2
 
3
3
  pub fn handle_colon_lexer(
4
4
  char: char,
@@ -1,4 +1,4 @@
1
- use crate::core::types::token::{ Token, TokenKind };
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(comment.trim().to_string()),
25
- lexeme: char.to_string(),
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::types::token::{Token, TokenKind};
1
+ use crate::core::lexer::token::{ Token, TokenKind };
2
2
 
3
3
  pub fn handle_dot_lexer(
4
4
  char: char,
@@ -1,4 +1,4 @@
1
- use crate::core::types::token::{Token, TokenKind};
1
+ use crate::core::lexer::token::{Token, TokenKind};
2
2
 
3
3
  pub fn handle_equal_lexer(
4
4
  char: char,
@@ -1,4 +1,4 @@
1
- use crate::core::types::token::{ Token, TokenKind };
1
+ use crate::core::lexer::token::{ Token, TokenKind };
2
2
 
3
3
  pub fn handle_identifier_lexer(
4
4
  char: char,
@@ -1,4 +1,4 @@
1
- use crate::core::types::token::{ Token, TokenKind };
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
- ) -> (Vec<Token>, Vec<usize>, usize, usize) {
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
- *column += 1;
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::types::token::{Token, TokenKind};
1
+ use crate::core::lexer::token::{ Token, TokenKind };
2
2
 
3
3
  pub fn handle_newline_lexer(
4
- char: char,
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: char.to_string(),
14
+ lexeme: ch.to_string(),
15
15
  line: *line,
16
- column: *column,
17
- indent: *current_indent,
16
+ column: 0,
17
+ indent: 0,
18
18
  });
19
-
20
- *line += 1;
21
- *column = 1;
22
- *at_line_start = true;
23
19
  }
@@ -1,4 +1,4 @@
1
- use crate::core::types::token::{Token, TokenKind};
1
+ use crate::core::lexer::token::{ Token, TokenKind };
2
2
 
3
3
  pub fn handle_number_lexer(
4
4
  char: char,