Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
3105630
refactor: removed an unnecessary const qualifier, and a mistakenly ad…
tahadostifam Jul 11, 2026
3fe485d
feat: almost finished Token/Suffix definiton but still need to make a…
tahadostifam Jul 11, 2026
382490d
refactor: removed whitespace and newlines in stdlib/random.cyrus
tahadostifam Jul 11, 2026
ec77b81
feat: implemented Writer interface and StringWriter
tahadostifam Jul 11, 2026
8778853
refactor: stdlib/math/checked.cyrus
tahadostifam Jul 11, 2026
9aadb23
fix: unwraps replaced with try operator for more safety in resolver
tahadostifam Jul 11, 2026
0b001b5
fix: bug fix integer overflow in string push_str
tahadostifam Jul 11, 2026
2dde8b9
fix: replaced malloc/free with allocator.alloc/free
tahadostifam Jul 11, 2026
5112ff0
feat: added new testcase and fixed bugs in std
tahadostifam Jul 11, 2026
b97abf7
feat: implemented write_all for io/Writer and StringWriter
tahadostifam Jul 11, 2026
9c7db17
fix: bug fix analyzer how analyzed interface / objects methods, issue…
tahadostifam Jul 11, 2026
81ef5ff
feat: added testcase for multi writer
tahadostifam Jul 11, 2026
f7e16d1
feat: added float support for formatter
tahadostifam Jul 12, 2026
81128b1
feat: added format support for Integer/Float Literal
tahadostifam Jul 12, 2026
6bfe439
feat: extend src/parse/lex/tokens.cyrus, fixed failing testcase tests…
tahadostifam Jul 12, 2026
557fc2a
refactor: remove some lines
tahadostifam Jul 12, 2026
7f9c630
feat: suffix support for float added
tahadostifam Jul 12, 2026
077ee86
refactor: renamed Formatter interface to Format
tahadostifam Jul 12, 2026
7722381
fix: changed parser to expect optional comma for StructLike Enum Variant
tahadostifam Jul 12, 2026
76f8b3f
fix: bug fix parse_enum
tahadostifam Jul 12, 2026
81adcea
fix: bug fix SelfType out of context use invalid logic; function unre…
tahadostifam Jul 12, 2026
14dc3cb
test: added testcase tests/issues/#402.cyrus
tahadostifam Jul 12, 2026
bf0f683
fix: StringSuffix completed in src/parse/lex/tokens.cyrus
tahadostifam Jul 12, 2026
9bf5d48
fix: removed invalid tokens (int, uint, char) from lexer
tahadostifam Jul 12, 2026
00d393d
fix: bug fix lexer by removing an unnecessary read_char() in read_cha…
tahadostifam Jul 13, 2026
83913fb
fix: bug fix parse_stmt for an invalid bool logic
tahadostifam Jul 13, 2026
67538c1
fix: removed dead (code) branch from parse_for_loop
tahadostifam Jul 13, 2026
f2347ef
fix: bug fix parse_tuple_value and added trailing comma support
tahadostifam Jul 13, 2026
2b7e8a1
fix: renamed a dangerous shadowing variable in is_type_arg_start
tahadostifam Jul 13, 2026
9579643
fix: bug fix cascading error in resolve_import
tahadostifam Jul 13, 2026
8e91486
fix: bug fix resolve_module_import_expr to handle shadowing of generi…
tahadostifam Jul 13, 2026
0d88e6b
fix: bug fix normalize_unresolved_type to catch non_type symbols as e…
tahadostifam Jul 13, 2026
aff84b6
fix: double file read removed from fs_module_loader load_module
tahadostifam Jul 13, 2026
7ee2955
fix: bug fix early return when a import module fails
tahadostifam Jul 13, 2026
253657c
fix: lexer was formatting TokenKind::DoubleColon mistakenly
tahadostifam Jul 13, 2026
636f99d
fix: lexer was formatting PrefixOperator::Bang mistakenly
tahadostifam Jul 13, 2026
bf855d4
fix: bug fix in AST
tahadostifam Jul 13, 2026
c0da8ca
fix: bug fix TypedAST to clear generic params after instantiation
tahadostifam Jul 13, 2026
bdd2d01
fix: bug fix substitute_type
tahadostifam Jul 13, 2026
4151d59
fix: bug fix analyze_enum_stmt
tahadostifam Jul 13, 2026
061b588
fix: bug fix analyze_block_stmt
tahadostifam Jul 13, 2026
21b8cae
fix: bug fix analyze_pattern in analyze/control_flow.rs
tahadostifam Jul 13, 2026
5baf9c1
fix: bug fix analyze_dynamic
tahadostifam Jul 13, 2026
5de71ce
fix: bug fix interface assignability in is_named_type_assignable_to
tahadostifam Jul 13, 2026
4f75349
fix: removed orphan file crates/cyrusc_analyzer/src/lint/var_usage.rs
tahadostifam Jul 13, 2026
0faf097
fix: bug fix linker
tahadostifam Jul 13, 2026
51d7504
refactor: changed &str to &PathBuf in cyrusc_compiler/{linker,context…
tahadostifam Jul 13, 2026
d5e1ea3
fix: bug fix get_final_build_directory_path, prevented of using env::…
tahadostifam Jul 13, 2026
ccc7053
fix: bug fix mangle_sema_type SemaType::InterfaceObject
tahadostifam Jul 13, 2026
3afde6c
fix: bug fix lookup_field_index_at_offset
tahadostifam Jul 13, 2026
5e42ab2
fix: removed dead method is_scalar of CIRType
tahadostifam Jul 13, 2026
bb653c6
fix: deduplicate cir_fat_ptr_type in CIRLower
tahadostifam Jul 13, 2026
7b35281
fix: prevent integer overflow in crates/cyrusc_diagcentral/src/report…
tahadostifam Jul 13, 2026
4030529
fix: line/column must start from 1 for diags, fixed in crates/cyrusc_…
tahadostifam Jul 13, 2026
9cde37a
fix: deduplicate cir_fat_ptr_type in CIRLower
tahadostifam Jul 13, 2026
121080f
fix: changed InvalidChar diag to InvalidEscapeSequence in lexer
tahadostifam Jul 13, 2026
fd12ecd
fix: format for LeftBracket and RightBracket in impl fmt::Display for…
tahadostifam Jul 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ testsuite: build
-d tests \
--output ./tmp/tests \
--compiler $(COMPILER) \
--flags "--stdlib=$(STDLIB) --quiet"
--flags "--stdlib=$(STDLIB) --quiet --jobs 1"

testsuite-fail: build
$(PY_CMD) ./tests/test_suite.py \
-d tests \
--output ./tmp/tests \
--compiler $(COMPILER) \
--fail \
--flags "--stdlib=$(STDLIB) --quiet"
--flags "--stdlib=$(STDLIB) --quiet --jobs 1"
2 changes: 1 addition & 1 deletion crates/cyrusc_analyzer/src/analyze/block_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ impl<'a> AnalysisContext<'a> {
let mut terminated = false;

let stmts = std::mem::take(&mut block_stmt.stmts);
let mut final_stmts = Vec::with_capacity(block_stmt.stmts.len());
let mut final_stmts = Vec::with_capacity(stmts.len());

for mut stmt in stmts {
let stmt_state = self.analyze_stmt(&mut stmt);
Expand Down
34 changes: 28 additions & 6 deletions crates/cyrusc_analyzer/src/analyze/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,19 @@ impl<'a> AnalysisContext<'a> {

match enum_variant {
TypedEnumVariant::Tuple { fields, .. } => {
if fields.len() != items.len() {}
if fields.len() != items.len() {
this.reporter.report(Diag {
level: DiagLevel::Error,
kind: Box::new(AnalyzerDiagKind::EnumVariantArgCountMismatch {
variant_name: ident.as_string(),
expected: fields.len() as u32,
provided: items.len() as u32,
}),
loc: Some(pattern.loc),
hint: None,
});
return;
}

*exporting_pattern_count += 1;

Expand Down Expand Up @@ -414,11 +426,7 @@ impl<'a> AnalysisContext<'a> {
}

// .StructVariant { x, y, .. }
TypedSwitchCasePatternKind::EnumStructVariant {
ident,
items,
has_rest: _,
} => {
TypedSwitchCasePatternKind::EnumStructVariant { ident, items, has_rest } => {
let Some(enum_variant) = find_variant(inst_enum_decl, ident) else {
this.reporter.report(Diag {
level: DiagLevel::Error,
Expand Down Expand Up @@ -449,6 +457,20 @@ impl<'a> AnalysisContext<'a> {
TypedEnumVariant::Struct { fields, .. } => {
let mut has_error = false;

if !has_rest && fields.len() != items.len() {
this.reporter.report(Diag {
level: DiagLevel::Error,
kind: Box::new(AnalyzerDiagKind::EnumVariantArgCountMismatch {
variant_name: ident.as_string(),
expected: fields.len() as u32,
provided: items.len() as u32,
}),
loc: Some(pattern.loc),
hint: None,
});
return;
}

for item in items {
let exists = fields.iter().any(|field| field.name == item.name);

Expand Down
14 changes: 7 additions & 7 deletions crates/cyrusc_analyzer/src/analyze/enum_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl<'a> AnalysisContext<'a> {
pub(crate) fn analyze_enum_stmt(&mut self, enum_stmt: &mut TypedEnumStmt) {
let mut enum_decl = self.decl_tables.enum_decl(enum_stmt.enum_decl_id);

if enum_stmt.is_generic() {
if !enum_stmt.is_generic() {
let object_type = SemaType::Named(NamedType {
type_decl_id: TypeDeclID::Enum(enum_stmt.enum_decl_id),
type_args: TypedTypeArgs::new(),
Expand Down Expand Up @@ -58,19 +58,19 @@ impl<'a> AnalysisContext<'a> {

self.analyze_generic_bounds(&enum_decl.generic_params);

let object_type_decl_id = TypeDeclID::Enum(enum_decl_id);

if !enum_decl.is_generic() {
self.analyze_object_methods(object_type_decl_id, &enum_decl.methods);
}

self.analyze_object_implements_interfaces(
&object_name,
enum_decl.is_generic(),
&enum_decl.impls,
&enum_decl.methods,
);

let object_type_decl_id = TypeDeclID::Enum(enum_decl_id);

if !enum_decl.is_generic() {
self.analyze_object_methods(object_type_decl_id, &enum_decl.methods);
}

self.decl_tables.with_enum_decl_mut(enum_decl_id, |_enum_decl| {
_enum_decl.variants = enum_decl.variants.clone();
});
Expand Down
12 changes: 9 additions & 3 deletions crates/cyrusc_analyzer/src/analyze/interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ impl<'a> AnalysisContext<'a> {
let mut methods: Vec<String> = Vec::new();

for (_, method_decl_id) in interface.methods.iter() {
let method_decl = self.decl_tables.method_decl(*method_decl_id);
let mut method_decl = self.decl_tables.method_decl(*method_decl_id);

self.analyze_method_decl(TypeDeclID::Interface(interface.interface_decl_id), &mut method_decl);

self.decl_tables.with_method_decl_mut(*method_decl_id, |_method_decl| {
*_method_decl = method_decl.clone();
});

let func_decl = method_decl.func_decl;

let params_start = if let Some(self_modifier) = func_decl.params.get_self_modifier() {
Expand Down Expand Up @@ -137,6 +144,7 @@ impl<'a> AnalysisContext<'a> {

for (_, method_decl_id) in interface_decl.methods.iter() {
let interface_method_decl = self.decl_tables.method_decl(*method_decl_id);

let func_decl = instantiate_method_decl(
&interface_method_decl,
&interface_decl.generic_params,
Expand Down Expand Up @@ -232,7 +240,6 @@ impl<'a> AnalysisContext<'a> {

for (_, method_decl_id) in interface_decl.methods.iter() {
// interface method

let interface_method_decl = &mut this.decl_tables.method_decl(*method_decl_id).func_decl;

let self_modifier = interface_method_decl.params.get_self_modifier_mut().unwrap();
Expand All @@ -242,7 +249,6 @@ impl<'a> AnalysisContext<'a> {
interface_method_decl.ret_type = this.substitute_type(&interface_method_decl.ret_type);

// object method

let Some(method_decl_id) = method_decls.get(&interface_method_decl.name) else {
continue;
};
Expand Down
16 changes: 11 additions & 5 deletions crates/cyrusc_analyzer/src/analyze/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use crate::{context::AnalysisContext, infer::InferCtx};
use cyrusc_typed_ast::{
debug_assert_func_decl_resolved,
decls::{MethodDecl, MethodDeclID, MethodDecls},
stmts::{TypedFuncParamKind, TypedTypeArgs},
types::{NamedType, SemaType, TypeDeclID},
Expand All @@ -16,6 +17,9 @@ impl<'a> AnalysisContext<'a> {

self.analyze_method_decl(object_type_decl_id, &mut method_decl);

#[cfg(debug_assertions)]
debug_assert_func_decl_resolved!(&method_decl.func_decl);

self.decl_tables.with_method_decl_mut(*method_decl_id, |_method_decl| {
*_method_decl = method_decl;
});
Expand All @@ -42,7 +46,7 @@ impl<'a> AnalysisContext<'a> {
// If the method is non-generic, eagerly lower all SelfType occurrences
// to the concrete object type. Generic methods defer SelfType substitution
// to the call-site via the instantiated generic environment.
if !method_decl.func_decl.is_generic() {
if !method_decl.func_decl.is_generic() && !object_type_decl_id.is_interface() {
let concrete_self_type = SemaType::Named(NamedType {
type_decl_id: object_type_decl_id,
type_args: TypedTypeArgs::new(),
Expand Down Expand Up @@ -90,10 +94,6 @@ impl<'a> AnalysisContext<'a> {
match param_kind {
TypedFuncParamKind::FuncParam(func_param) => {
func_param.ty = self.substitute_self_type(func_param.ty.clone(), concrete_self_type);

if let Some(infer) = &self.func_env.infer {
func_param.ty = infer.resolve(&func_param.ty);
}
}
TypedFuncParamKind::SelfModifier(self_modifier) => {
self_modifier.ty = self.substitute_self_type(self_modifier.ty.clone(), concrete_self_type);
Expand All @@ -106,6 +106,12 @@ impl<'a> AnalysisContext<'a> {
}
}

if let Some(ret_type) =
self.normalize_sema_type(method_decl.func_decl.ret_type.clone(), method_decl.func_decl.loc, 0)
{
method_decl.func_decl.ret_type = ret_type;
}

let mut substituted_ret_type =
self.substitute_self_type(method_decl.func_decl.ret_type.clone(), concrete_self_type);

Expand Down
12 changes: 6 additions & 6 deletions crates/cyrusc_analyzer/src/analyze/struct_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,18 @@ impl<'a> AnalysisContext<'a> {

self.analyze_generic_bounds(&struct_decl.generic_params);

let object_type_decl_id = TypeDeclID::Struct(struct_decl_id);

if !struct_decl.is_generic() {
self.analyze_object_methods(object_type_decl_id, &struct_decl.methods);
}

self.analyze_object_implements_interfaces(
&object_name,
struct_decl.is_generic(),
&struct_decl.impls,
&struct_decl.methods,
);

let object_type_decl_id = TypeDeclID::Struct(struct_decl_id);

if !struct_decl.is_generic() {
self.analyze_object_methods(object_type_decl_id, &struct_decl.methods);
}
}

fn analyze_struct_fields(&mut self, struct_decl_id: StructDeclID, struct_fields: &mut [TypedStructField]) {
Expand Down
12 changes: 6 additions & 6 deletions crates/cyrusc_analyzer/src/analyze/union_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,18 @@ impl<'a> AnalysisContext<'a> {

self.analyze_generic_bounds(&union_decl.generic_params);

let object_type_decl_id = TypeDeclID::Union(union_decl_id);

if !union_decl.is_generic() {
self.analyze_object_methods(object_type_decl_id, &union_decl.methods);
}

self.analyze_object_implements_interfaces(
&object_name,
union_decl.is_generic(),
&union_decl.impls,
&union_decl.methods,
);

let object_type_decl_id = TypeDeclID::Union(union_decl_id);

if !union_decl.is_generic() {
self.analyze_object_methods(object_type_decl_id, &union_decl.methods);
}
}

fn analyze_union_fields(&mut self, union_decl_id: UnionDeclID, union_fields: &mut [TypedUnionField]) {
Expand Down
4 changes: 2 additions & 2 deletions crates/cyrusc_analyzer/src/analyze/vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl<'a> AnalysisContext<'a> {
};

if let Some(ty) = &global_var.ty {
if !self.validate_variable_type(ty, global_var.expr.is_some(), global_var.loc) {
if !self.validate_variable_type(ty, global_var.expr.is_some() || global_var.is_undef, global_var.loc) {
return;
}

Expand Down Expand Up @@ -154,7 +154,7 @@ impl<'a> AnalysisContext<'a> {
self.report_const_qualified_type_assigned_to_non_const_variable(var.loc);
}

if !self.validate_variable_type(ty, var.rhs.is_some(), var.loc) {
if !self.validate_variable_type(ty, var.rhs.is_some() || var.is_undef, var.loc) {
return;
}

Expand Down
10 changes: 9 additions & 1 deletion crates/cyrusc_analyzer/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,14 @@ pub enum AnalyzerDiagKind {
#[error("Cannot infer dynamic interface type.")]
CannotInferDynamicInterfaceType,

#[error("Cannot apply 'dynamic' to an already dynamic value.")]
#[error("Cannot apply dynamic to an already dynamic value.")]
InvalidMultipleDynamicType,

#[error("Cannot apply dynamic to type '{type_name}'.")]
InvalidDynamicType {
type_name: String
},

#[error(
"Method '{method_name}' requires mutable access to 'self', but instance of type '{type_name}' is declared 'const'."
)]
Expand Down Expand Up @@ -470,6 +475,9 @@ pub enum AnalyzerDiagKind {
#[error("Symbol '{symbol_name}' is not an enum.")]
NonEnumSymbol { symbol_name: String },

#[error("Symbol '{symbol_name}' is not a type.")]
NonTypeSymbol { symbol_name: String },

#[error("Cannot use {elements} elements in an array of size {expected}.")]
ArrayElementsCountMismatch { elements: u32, expected: u32 },

Expand Down
12 changes: 8 additions & 4 deletions crates/cyrusc_analyzer/src/env/generic_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,14 @@ impl GenericEnv {
#[inline]
pub fn substitute_sema_type(&self, ty: &SemaType) -> SemaType {
match ty {
SemaType::Unresolved(_) | SemaType::InferVar(_) | SemaType::Plain(_) | SemaType::Placeholder => ty.clone(),
SemaType::SelfType(self_type) => SemaType::SelfType(self_type.clone()),

SemaType::Err(_)
| SemaType::Unresolved(_)
| SemaType::InferVar(_)
| SemaType::Plain(_)
| SemaType::Placeholder => ty.clone(),

SemaType::Named(named_type) => {
let type_args = named_type
.type_args
Expand Down Expand Up @@ -154,9 +161,6 @@ impl GenericEnv {
Some(ty) => ty.clone(),
None => ty.clone(),
},
SemaType::SelfType(self_type) => SemaType::SelfType(self_type.clone()),

SemaType::Err(_) => ty.clone(),
}
}
}
Expand Down
9 changes: 0 additions & 9 deletions crates/cyrusc_analyzer/src/lint/var_usage.rs

This file was deleted.

2 changes: 1 addition & 1 deletion crates/cyrusc_analyzer/src/monomorph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ impl<'a> AnalysisContext<'a> {
}
}
TypedExprKind::EnumInit(enum_init) => match &mut enum_init.arg {
TypedEnumInitArgs::Unit => todo!(),
TypedEnumInitArgs::Unit => {}
TypedEnumInitArgs::Tuple(elements) => {
for element in elements {
self.specialize_expr(element, decl_map);
Expand Down
23 changes: 17 additions & 6 deletions crates/cyrusc_analyzer/src/normalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,21 @@ impl<'a> AnalysisContext<'a> {
indirection: u8,
) -> Option<SemaType> {
let ty = match unresolved_type {
UnresolvedType::Decl(symbol_id) => self
.lookup_symbol_as_decl_id(symbol_id)
.and_then(|decl_id| self.resolve_symbol_type(decl_id, loc, indirection))?,
UnresolvedType::Decl(symbol_id) => self.lookup_symbol_as_decl_id(symbol_id).and_then(|decl_id| {
if decl_id.as_type_decl_id().is_none() {
let symbol_name = self.formatter.format_decl(decl_id);

self.reporter.report(Diag {
level: DiagLevel::Error,
kind: Box::new(AnalyzerDiagKind::NonTypeSymbol { symbol_name }),
loc: Some(loc),
hint: None,
});
return None;
}

self.resolve_symbol_type(decl_id, loc, indirection)
})?,

UnresolvedType::GenericInst {
base_symbol_id,
Expand Down Expand Up @@ -282,7 +294,7 @@ impl<'a> AnalysisContext<'a> {
let elements: Vec<_> = tuple_type
.elements
.into_iter()
.filter_map(|(ty, loc)| {
.filter_map(|(ty, loc)| {
self.normalize_sema_type(ty, tuple_type.loc, indirection)
.map(|ty| (ty, loc))
})
Expand All @@ -299,7 +311,6 @@ impl<'a> AnalysisContext<'a> {
}))
}

// TODO: Implement slices.
fn normalize_array_capacity(
&mut self,
mut array: TypedArrayType,
Expand Down Expand Up @@ -378,7 +389,7 @@ impl<'a> AnalysisContext<'a> {
for type_arg in type_args.iter_mut() {
match type_arg {
TypedTypeArg::Type(ty, loc) => {
*ty = match self.normalize_and_check_type_formation(ty.clone(), *loc, indirection) {
*ty = match self.normalize_sema_type(ty.clone(), *loc, indirection) {
Some(sema_type) => sema_type,
None => continue,
};
Expand Down
Loading
Loading