Skip to content

Commit 2933a79

Browse files
committed
Update dependencies and improve performance slightly
1 parent 6d81e77 commit 2933a79

7 files changed

Lines changed: 98 additions & 39 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ctrc-graph/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ thiserror = "2.0.17"
1111
zetaruntime = { path = "../zeta_utilities" }
1212
iris-math = { path = "../iris-math" }
1313
ir = { path = "../ir" }
14+
smallvec = "2.0.0-alpha.12"
1415
dashmap = "7.0.0-rc2"
1516
codex-dependency-graph = { path = "../codex-dependency-graph" }

ctrc-graph/src/ctrc_diagnostics.rs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::collections::HashMap;
2+
use smallvec::SmallVec;
23
use zetaruntime::string_pool::StringPool;
34
use ir::errors::reporter::{ErrorReporter, CTRCLeakInfo};
5+
use ir::hir::StrId;
46
use ir::span::SourceSpan;
57
use crate::ctrc_pvg_graph::{CTRCAnalysisResult, AliasID};
68

@@ -55,11 +57,18 @@ impl<'a> CTRCDiagnostics<'a> {
5557
potential_cycles: vec![], // Will be filled by cycle detection
5658
};
5759

58-
// Create a dummy span for now - in a real implementation, you'd track spans through the analysis
5960
let span = SourceSpan::new(file_name, 1, 1);
61+
62+
const START: &'static str = "Potential memory leak detected for variable '";
63+
const END: &'static str = "'";
64+
65+
let mut buf: SmallVec<u8, 64> = SmallVec::with_capacity(START.len() + variable_name.len() + END.len());
66+
buf.extend_from_slice(START.as_bytes());
67+
buf.extend_from_slice(variable_name.as_bytes());
68+
buf.extend_from_slice(END.as_bytes());
6069

6170
reporter.add_ctrc_error(
62-
format!("Potential memory leak detected for variable '{}'", variable_name),
71+
StrId::from(self.string_pool.intern_bytes(buf.as_slice())),
6372
Some(span),
6473
Some(leak_info),
6574
);
@@ -105,7 +114,7 @@ impl<'a> CTRCDiagnostics<'a> {
105114
};
106115

107116
reporter.add_ctrc_error(
108-
"Potential reference cycle detected".to_string(),
117+
StrId::from(self.string_pool.intern("Potential reference cycle detected")),
109118
Some(span),
110119
Some(leak_info),
111120
);
@@ -134,9 +143,24 @@ impl<'a> CTRCDiagnostics<'a> {
134143
.unwrap_or("<unknown>");
135144

136145
let span = SourceSpan::new(file_name, 1, 1);
146+
147+
// Fast alternative to interning `String` directly.
148+
const START: &'static str = "Potential double-free detected for variable '";
149+
const MIDDLE: &'static str = "' (dropped ";
150+
const END: &'static str = " times)";
151+
152+
let string = count.to_string();
153+
let bytes = string.as_bytes();
154+
155+
let mut buf: SmallVec<u8, 64> = SmallVec::with_capacity(START.len() + variable_name.len() + MIDDLE.len() + bytes.len() + END.len());
156+
buf.extend_from_slice(START.as_bytes());
157+
buf.extend_from_slice(variable_name.as_bytes());
158+
buf.extend_from_slice(MIDDLE.as_bytes());
159+
buf.extend_from_slice(bytes);
160+
buf.extend_from_slice(END.as_bytes());
137161

138162
reporter.add_ctrc_error(
139-
format!("Potential double-free detected for variable '{}' (dropped {} times)", variable_name, count),
163+
StrId::from(self.string_pool.intern_bytes(buf.as_slice())),
140164
Some(span),
141165
None,
142166
);
@@ -152,10 +176,22 @@ impl<'a> CTRCDiagnostics<'a> {
152176
) {
153177
if result.has_memory_safety_issues() {
154178
let span = SourceSpan::new(file_name, 1, 1);
155-
179+
180+
const START: &'static str = "Module '";
181+
const MIDDLE: &'static str = "' has ";
182+
const END: &'static str = " potential memory safety issues";
183+
184+
let string = result.potential_leaks.len().to_string();
185+
let bytes = string.as_bytes();
186+
let mut buf: SmallVec<u8, 64> = SmallVec::with_capacity(START.len() + file_name.len() + MIDDLE.len() + bytes.len() + END.len());
187+
buf.extend_from_slice(START.as_bytes());
188+
buf.extend_from_slice(file_name.as_bytes());
189+
buf.extend_from_slice(MIDDLE.as_bytes());
190+
buf.extend_from_slice(bytes);
191+
buf.extend_from_slice(END.as_bytes());
192+
156193
reporter.add_ctrc_error(
157-
format!("Module '{}' has {} potential memory safety issues",
158-
file_name, result.potential_leaks.len()),
194+
StrId::from(self.string_pool.intern_bytes(buf.as_slice())),
159195
Some(span),
160196
None,
161197
);

ir/src/errors/reporter.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use zetaruntime::bump::GrowableBump;
55

66
use is_terminal::IsTerminal;
77
use owo_colors::OwoColorize;
8+
use crate::hir::StrId;
89

910
#[derive(Debug, Clone)]
1011
pub enum DiagnosticLevel {
@@ -27,11 +28,11 @@ pub struct Diagnostic<'a> {
2728
pub enum CompilerError<'a, 'bump> {
2829
TypeError(TypeError<'a, 'bump>),
2930
ParserError {
30-
message: String,
31+
message: StrId,
3132
span: Option<SourceSpan<'a>>,
3233
},
3334
CTRCError {
34-
message: String,
35+
message: StrId,
3536
span: Option<SourceSpan<'a>>,
3637
leak_info: Option<CTRCLeakInfo>,
3738
},
@@ -78,11 +79,11 @@ impl<'a, 'bump> ErrorReporter<'a, 'bump> {
7879
self.errors.push(CompilerError::TypeError(error));
7980
}
8081

81-
pub fn add_parser_error(&mut self, message: String, span: Option<SourceSpan<'a>>) {
82+
pub fn add_parser_error(&mut self, message: StrId, span: Option<SourceSpan<'a>>) {
8283
self.errors.push(CompilerError::ParserError { message, span });
8384
}
8485

85-
pub fn add_ctrc_error(&mut self, message: String, span: Option<SourceSpan<'a>>, leak_info: Option<CTRCLeakInfo>) {
86+
pub fn add_ctrc_error(&mut self, message: StrId, span: Option<SourceSpan<'a>>, leak_info: Option<CTRCLeakInfo>) {
8687
self.errors.push(CompilerError::CTRCError { message, span, leak_info });
8788
}
8889

@@ -103,8 +104,8 @@ impl<'a, 'bump> ErrorReporter<'a, 'bump> {
103104
fn report_error(&self, error: &CompilerError<'a, 'bump>) {
104105
match error {
105106
CompilerError::TypeError(te) => self.report_type_error(te),
106-
CompilerError::ParserError { message, span } => self.report_parser_error(message, span.as_ref()),
107-
CompilerError::CTRCError { message, span, leak_info } => self.report_ctrc_error(message, span.as_ref(), leak_info.as_ref()),
107+
CompilerError::ParserError { message, span } => self.report_parser_error(message.as_str(), span.as_ref()),
108+
CompilerError::CTRCError { message, span, leak_info } => self.report_ctrc_error(message.as_str(), span.as_ref(), leak_info.as_ref()),
108109
}
109110
}
110111

scribe-parser/src/diagnostics.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::sync::Arc;
22
use zetaruntime::string_pool::StringPool;
33
use ir::errors::reporter::ErrorReporter;
4+
use ir::hir::StrId;
45
use ir::span::SourceSpan;
56
use crate::parser::descent_parser::ParserError;
67

@@ -38,14 +39,14 @@ impl<'a> ParserDiagnostics<'a> {
3839
ParserError::LexerError(msg) => {
3940
let span = SourceSpan::new(self.file_name, 1, 1);
4041
reporter.add_parser_error(
41-
format!("Lexer error: {}", msg),
42+
StrId::from(self.string_pool.intern(format!("Lexer error: {}", msg).as_str())),
4243
Some(span),
4344
);
4445
}
4546
ParserError::UnexpectedToken { expected, found } => {
4647
let span = SourceSpan::new(self.file_name, 1, 1); // TODO: Get actual position
4748
reporter.add_parser_error(
48-
format!("Expected '{}', but found '{}'", expected, found),
49+
StrId::from(self.string_pool.intern(format!("Expected '{}', but found '{}'", expected, found).as_str())),
4950
Some(span),
5051
);
5152
}
@@ -56,7 +57,7 @@ impl<'a> ParserDiagnostics<'a> {
5657

5758
let span = SourceSpan::new(self.file_name, last_line, last_col);
5859
reporter.add_parser_error(
59-
"Unexpected end of file".to_string(),
60+
StrId::from(self.string_pool.intern("Unexpected end of file")),
6061
Some(span),
6162
);
6263
}
@@ -71,7 +72,7 @@ impl<'a> ParserDiagnostics<'a> {
7172
reporter: &mut ErrorReporter<'a, 'bump>,
7273
) {
7374
let span = SourceSpan::new(self.file_name, line, col);
74-
reporter.add_parser_error(message.to_string(), Some(span));
75+
reporter.add_parser_error(StrId::from(self.string_pool.intern(message)), Some(span));
7576
}
7677

7778
pub fn report_missing_semicolon<'bump>(
@@ -82,7 +83,7 @@ impl<'a> ParserDiagnostics<'a> {
8283
) {
8384
let span = SourceSpan::new(self.file_name, line, col);
8485
reporter.add_parser_error(
85-
"Missing semicolon".to_string(),
86+
StrId::from(self.string_pool.intern("Missing semicolon")),
8687
Some(span),
8788
);
8889
}
@@ -96,7 +97,7 @@ impl<'a> ParserDiagnostics<'a> {
9697
) {
9798
let span = SourceSpan::new(self.file_name, line, col);
9899
reporter.add_parser_error(
99-
format!("Missing {}", brace_type),
100+
StrId::from(self.string_pool.intern(format!("Missing {}", brace_type).as_str())),
100101
Some(span),
101102
);
102103
}
@@ -110,7 +111,7 @@ impl<'a> ParserDiagnostics<'a> {
110111
) {
111112
let span = SourceSpan::new(self.file_name, line, col);
112113
reporter.add_parser_error(
113-
format!("Invalid syntax in {}", context),
114+
StrId::from(self.string_pool.intern(format!("Invalid syntax in {}", context).as_str())),
114115
Some(span),
115116
);
116117
}

scribe-parser/src/grammar.pest

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ generic_placeholder = { ident ~ (":" ~ ident)? }
2424

2525
state_ref = { ident | "*" }
2626

27-
block_stmt = _{ if_stmt | while_stmt | for_stmt | match_stmt | fun_decl | struct_decl | enum_decl | unsafe_block | block }
27+
block_stmt = _{ if_stmt | while_stmt | for_stmt | match_stmt | fun_decl | destructor_decl | struct_decl | enum_decl | effect_decl | unsafe_block | block }
2828

29-
simple_stmt = _{ (import_stmt | let_stmt | const_stmt | return_stmt | expr_stmt | break_stmt | continue_stmt | defer_stmt) ~ stmt_terminator? }
29+
simple_stmt = _{ (import_stmt | let_stmt | shorthand_let_stmt | const_stmt | return_stmt | expr_stmt | break_stmt | continue_stmt | defer_stmt) ~ stmt_terminator? }
3030

3131
defer_stmt = { "defer" ~ (block | stmt) }
3232

@@ -50,7 +50,7 @@ sealed_keyword = { "sealed" }
5050

5151
import_stmt = { "import" ~ string ~ stmt_terminator? }
5252
package_stmt = { "package" ~ (ident ~ ("." ~ ident)*) ~ stmt_terminator? }
53-
let_stmt = { mut_keyword? ~ var_type ~ ident ~ "=" ~ expr ~ stmt_terminator? }
53+
let_stmt = { "let" ~ mut_keyword? ~ (var_type ~ ident ~ "=" | ident ~ ":=") ~ expr ~ stmt_terminator? }
5454
shorthand_let_stmt = { mut_keyword? ~ ident ~ ":=" ~ expr ~ stmt_terminator? }
5555
const_stmt = { "const" ~ var_type ~ ident ~ "=" ~ expr ~ stmt_terminator? }
5656
return_stmt = { "return" ~ expr? ~ stmt_terminator? }
@@ -60,6 +60,17 @@ for_stmt = { "for" ~ atom ~ ":=" ~ expr ~ block ~ stmt_terminator? }
6060

6161
stmt_ending = _{ "\n" | WHITESPACE* }
6262

63+
destructor_decl = {
64+
visibility_modifier? ~ "~" ~ ident ~ "(" ~ ")" ~ block ~ stmt_terminator?
65+
}
66+
67+
effect_decl = {
68+
visibility_modifier? ~ sealed_keyword? ~ "effect" ~ ident ~ permits_expr? ~ "(" ~ param_list ~ ")" ~ block
69+
}
70+
71+
effect_annotation = { "\\" ~ type_expr }
72+
73+
6374
match_stmt = { "match" ~ expr ~ "{" ~ match_arm* ~ "}" ~ stmt_terminator? }
6475
unsafe_block = { "unsafe" ~ block ~ stmt_terminator? }
6576
expr_stmt = { expr ~ stmt_terminator? }
@@ -75,9 +86,9 @@ struct_decl = { visibility_modifier? ~ "struct" ~ ident ~ generic_params? ~ fiel
7586
fun_decl = {
7687
visibility_modifier? ~ unsafe_modifier? ~
7788
(extern_modifier ~ string)? ~
78-
(inline_keyword | noinline_keyword)? ~
89+
(comptime_keyword | inline_keyword | noinline_keyword)? ~ // can't inline a comptime/noinline function and vice versa
7990
var_type ~ ident ~
80-
generic_params? ~ param_list ~ (block | arrow_expr)? ~ stmt_terminator?
91+
generic_params? ~ param_list ~ effect_annotation* ~ (block | arrow_expr)? ~ stmt_terminator?
8192
}
8293

8394
own_keyword = { "own" }
@@ -127,17 +138,21 @@ private_keyword = { "private" }
127138
module_keyword = { "module" }
128139
package_keyword = { "package" }
129140

141+
comptime_keyword = { "comptime" }
142+
130143
mut_keyword = { "mut" }
131-
keyword = _{ "true" | "false" | "if" | "else" | "while" | "return" | "for" | "enum" | "type" }
144+
keyword = _{ "true" | "false" | "if" | "else" | "while" | "return" | "for" | "enum" | "type" | "let" | "const" | "mut" | "struct" | "interface" | "impl" | "match" | "break" | "continue" | "unsafe" | "extern" | "inline" | "noinline" | "comptime" | "defer" | "import" | "package" | "this" }
132145

133146
ident = @{ !keyword ~ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
134147
number = @{ "-"? ~ ASCII_DIGIT+ }
148+
decimal = @{ "-"? ~ ASCII_DIGIT+ ~ "." ~ ASCII_DIGIT+ }
149+
char = @{ "'" ~ ("\\" ~ ANY | (!"'" ~ ANY)) ~ "'" }
135150
string = @{ "\"" ~ string_inner* ~ "\"" }
136151
string_inner = _{ "\\\"" | "\\\\" | (!"\"" ~ ANY) }
137152

138153
expr = { assignment }
139154

140-
assign_op = { "=" }
155+
assign_op = { ":=" | "=" }
141156
compound_assign_op = {
142157
"+="
143158
| "-="
@@ -165,24 +180,24 @@ boolean = { "true" | "false" }
165180
logic_or = { logic_and ~ ("||" ~ logic_and)* }
166181
logic_and = { bit_or ~ ("&&" ~ bit_or)* }
167182

168-
bit_or = { bit_xor ~ (("|" ~ "=") ~ bit_xor)* }
169-
bit_xor = { bit_and ~ (("^" ~ "=") ~ bit_and)* }
170-
bit_and = { equality ~ (("&" ~ "=") ~ equality)* }
183+
bit_or = { bit_xor ~ ("|" ~ bit_xor)* }
184+
bit_xor = { bit_and ~ ("^" ~ bit_and)* }
185+
bit_and = { equality ~ ("&" ~ equality)* }
171186

172-
equality = { comparison ~ (("==" | "~=") ~ comparison)* }
187+
equality = { comparison ~ (("==" | "!=" | "~=") ~ comparison)* }
173188
comparison = { shift ~ (comparison_operators ~ shift)* }
174189

175-
operator_shift = { (">>>" ~ "=") | ("<<<" ~ "=") | (">>" ~ "=") | ("<<" ~ "=") }
190+
operator_shift = { ">>>" | "<<<" | ">>" | "<<" }
176191
shift = { term ~ ((operator_shift) ~ term)* }
177192

178193
term = { factor ~ (operator_add_sub ~ factor)* }
179194
factor = { unary ~ (operator_mul_div ~ unary)* }
180195
unary = { ("~" | "-" | "+")* ~ primary }
181196

182-
operator_add_sub = { ("+" ~ "=") | ("-" ~ "=") }
183-
operator_mul_div = { ("*" ~ "=") | ("/" ~ "=") | ("%" ~ "=") }
197+
operator_add_sub = { "+" | "-" }
198+
operator_mul_div = { "*" | "/" | "%" }
184199

185-
comparison_operators = { "<" | ">" | "<=" | ">=" | "~=" | "==" }
200+
comparison_operators = { "<=" | ">=" | "<" | ">" | "~=" | "!=" | "==" }
186201

187202
primary = {
188203
atom ~ postfix
@@ -199,8 +214,11 @@ atom = _{ parenthesized_expr
199214
| class_initialization
200215
| boolean
201216
| array_literal
217+
| lambda_expr
202218
| ident
219+
| decimal
203220
| number
221+
| char
204222
| string
205223
| this_type }
206224

@@ -220,8 +238,8 @@ type_list = { var_type ~ ("," ~ var_type)* }
220238

221239
nullable_suffix = { "?" }
222240

223-
array_suffix = { "[" ~ atom ~ "]" }
224-
basic_type = { (ident ~ ("<" ~ type_list ~ ">")?) | "i32" | "u32" | "f64" | "uf64" | "i64" | "u64" | "i128" | "u128" | "u8" | "i8" | "i16" | "u16" | "boolean" }
241+
array_suffix = { "[" ~ expr ~ "]" }
242+
basic_type = { (ident ~ ("<" ~ type_list ~ ">")?) | "i32" | "u32" | "f32" | "f64" | "uf32" | "uf64" | "i64" | "u64" | "i128" | "u128" | "u8" | "i8" | "i16" | "u16" | "boolean" | "char" | "str" }
225243

226244
parenthesized_expr = { "(" ~ expr ~ ")" }
227245
operator_pow = { "^" }

src/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::time::Instant;
1717

1818
use clap::{ArgMatches, CommandFactory, Error, FromArgMatches, Parser, Subcommand};
1919
use snmalloc_rs::SnMalloc;
20+
use ir::hir::StrId;
2021

2122
#[global_allocator]
2223
static ALLOCATOR: SnMalloc = SnMalloc;
@@ -166,7 +167,7 @@ fn run_compiler(
166167
for module_with_arena in stdlib_modules_result {
167168
if module_with_arena.parser_diagnostics.has_errors() {
168169
for error in &module_with_arena.parser_diagnostics.errors {
169-
error_reporter.add_parser_error(error.to_string(), None);
170+
error_reporter.add_parser_error(StrId::from(arc.intern(error.to_string().as_str())), None);
170171
}
171172
}
172173
if module_with_arena.valid {
@@ -191,7 +192,7 @@ fn run_compiler(
191192
for module_with_arena in user_modules_result {
192193
if module_with_arena.parser_diagnostics.has_errors() {
193194
for error in &module_with_arena.parser_diagnostics.errors {
194-
error_reporter.add_parser_error(error.to_string(), None);
195+
error_reporter.add_parser_error(StrId::from(arc.intern(error.to_string().as_str())), None);
195196
}
196197
}
197198
if module_with_arena.valid {

0 commit comments

Comments
 (0)