From a222b3807ea2537238c40e0cf963449dbf542312 Mon Sep 17 00:00:00 2001 From: Masashi Date: Sat, 20 Dec 2025 03:16:16 +0530 Subject: [PATCH] unsafe --- src/import_resolver.rs | 29 +++- src/main.rs | 315 +++++++++++++++++++++++++++-------------- tests/arrays.c | 21 +++ tests/basic_types.c | 21 +++ tests/control_flow.c | 29 +++- tests/functions.c | 23 ++- tests/structs.c | 25 +++- 7 files changed, 354 insertions(+), 109 deletions(-) diff --git a/src/import_resolver.rs b/src/import_resolver.rs index 4c3a360..067e276 100644 --- a/src/import_resolver.rs +++ b/src/import_resolver.rs @@ -81,6 +81,8 @@ struct ParsedFile { nodes: Vec, /// Hash of the file content at parse time content_hash: u64, + /// Whether this file is in unsafe mode + is_unsafe: bool, } /// Tracks global symbols and their definitions @@ -124,6 +126,8 @@ pub struct ImportResolver { processing_stack: HashSet, /// Dependency graph: file -> list of files it depends on dependency_graph: HashMap>, + /// Whether any file in the current compilation is unsafe + has_unsafe_files: bool, } impl ImportResolver { @@ -133,6 +137,7 @@ impl ImportResolver { symbol_registry: GlobalSymbolRegistry::default(), processing_stack: HashSet::new(), dependency_graph: HashMap::new(), + has_unsafe_files: false, } } @@ -191,6 +196,7 @@ impl ImportResolver { })?; let content_hash = Self::hash_content(&source); + let is_unsafe = source.trim_start().starts_with("# UNSAFE"); // Check if we have a valid cached version if let Some(cached) = self.parse_cache.get(filename) { @@ -211,6 +217,7 @@ impl ImportResolver { ParsedFile { nodes: nodes.clone(), content_hash, + is_unsafe, }, ); @@ -295,6 +302,13 @@ impl ImportResolver { let nodes = self.parse_file(filename)?; let mut result = Vec::new(); + // Check if this file is unsafe + if let Some(cached) = self.parse_cache.get(filename) { + if cached.is_unsafe { + self.has_unsafe_files = true; + } + } + // Collect dependencies let deps = self.collect_dependencies(filename, &nodes); self.dependency_graph @@ -393,10 +407,23 @@ impl ImportResolver { Ok(result) } + /// Check if the current compilation contains any unsafe files + pub fn has_unsafe_files(&self) -> bool { + self.has_unsafe_files + } + /// Resolve all imports starting from the given file pub fn resolve(&mut self, filename: &str) -> Result, ImportError> { println!("Starting import resolution..."); - self.resolve_imports_recursive(filename) + self.has_unsafe_files = false; // Reset for new compilation + let result = self.resolve_imports_recursive(filename); + // Check if the main file is unsafe + if let Ok(source) = fs::read_to_string(filename) { + if source.trim_start().starts_with("# UNSAFE") { + self.has_unsafe_files = true; + } + } + result } } diff --git a/src/main.rs b/src/main.rs index 83cd7c1..85f7886 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,103 @@ use clap::Parser; use std::fs; use suicmez::{ + ast::*, codegen::transpiler::Transpiler, import_resolver::ImportResolver, lambda_lower::LambdaLowerer, monomorphize::{Monomorphizer, check_no_typevars}, - typechecker::TypeChecker, + typechecker::{Type, TypeChecker}, }; +/// Convert ASTNode to TypedASTNode for unsafe mode (with dummy types) +fn convert_to_typed_ast(nodes: &[ASTNode]) -> Vec { + nodes.iter().map(|node| { + let dummy_type = Type::Unit; // Use unit type as dummy + let dummy_expr = TypedExpr { + kind: TypedExprKind::Int(0), // dummy expression + span: Span::new(&(0..0), "dummy".to_string()), + attributes: vec![], + ty: dummy_type.clone(), + }; + + let kind = match &node.kind { + ASTNodeKind::Function(f) => TypedASTNodeKind::Function(TypedFunction { + name: f.name.clone(), + parameters: f.parameters.clone(), + args: f.args.iter().map(|(name, typ)| { + (BindingId(0), name.clone(), typ.clone()) // dummy binding id + }).collect(), + return_type: f.return_type.clone(), + body: dummy_expr.clone(), + ty: dummy_type.clone(), + }), + ASTNodeKind::Const(c) => TypedASTNodeKind::Const(TypedConst { + name: c.name.clone(), + typ: c.typ.clone(), + value: dummy_expr.clone(), + }), + ASTNodeKind::Struct(s) => TypedASTNodeKind::Struct(TypedStruct { + name: s.name.clone(), + parameters: s.parameters.clone(), + fields: s.fields.iter().map(|f| TypedField { + name: f.name.clone(), + field_type: f.field_type.clone(), + span: f.span.clone(), + }).collect(), + }), + ASTNodeKind::Enum(e) => TypedASTNodeKind::Enum(TypedEnum { + name: e.name.clone(), + parameters: e.parameters.clone(), + variants: e.variants.iter().map(|v| TypedVariant { + name: v.name.clone(), + fields: v.fields.clone(), + span: v.span.clone(), + }).collect(), + }), + ASTNodeKind::Impl(i) => TypedASTNodeKind::Impl(TypedImpl { + target: i.target.clone(), + trait_name: i.trait_name.clone(), + methods: i.methods.iter().map(|m| TypedFunction { + name: m.name.clone(), + parameters: m.parameters.clone(), + args: m.args.iter().map(|(name, typ)| { + (BindingId(0), name.clone(), typ.clone()) + }).collect(), + return_type: m.return_type.clone(), + body: dummy_expr.clone(), + ty: dummy_type.clone(), + }).collect(), + }), + ASTNodeKind::Trait(t) => TypedASTNodeKind::Trait(TypedTrait { + name: t.name.clone(), + methods: t.methods.clone(), + parameters: t.parameters.clone(), + associated_types: vec![], + }), + ASTNodeKind::Extern(e) => TypedASTNodeKind::Extern(TypedExtern { + name: e.name.clone(), + args: e.args.clone(), + return_type: e.return_type.clone(), + from: e.from.clone(), + span: e.span.clone(), + }), + ASTNodeKind::Load(l) => TypedASTNodeKind::Load(TypedLoad { + library: l.library.clone(), + alias: l.alias.clone(), + span: l.span.clone(), + }), + ASTNodeKind::Use(u) => TypedASTNodeKind::Use(u.clone()), + }; + + TypedASTNode { + kind, + span: node.span.clone(), + attributes: node.attributes.clone(), + ty: dummy_type, + } + }).collect() +} + #[derive(Parser)] #[command(author, version, about = "A compiler for the Sui language")] struct Args { @@ -206,6 +296,8 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> { } })?; + let is_unsafe = resolver.has_unsafe_files(); + println!( "Import resolution complete! {} total nodes loaded", ast_nodes.len() @@ -226,59 +318,126 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> { lowered_nodes.len() ); - // Typecheck the AST - let mut typechecker = TypeChecker::new(); - let typed_nodes = typechecker - .typecheck_program(&lowered_nodes) - .map_err(|e| format_type_error(&source, &e))?; + let typed_nodes = if is_unsafe { + println!("Unsafe mode detected - skipping type checking"); + // Convert AST nodes to typed nodes with dummy types + convert_to_typed_ast(&lowered_nodes) + } else { + // Typecheck the AST + let mut typechecker = TypeChecker::new(); + typechecker + .typecheck_program(&lowered_nodes) + .map_err(|e| format_type_error(&source, &e))? + }; - println!( - "Type checking passed! {} nodes typechecked.", - typed_nodes.len() - ); + if is_unsafe { + println!("Unsafe mode - skipping monomorphization and type variable checks"); + } else { + println!( + "Type checking passed! {} nodes typechecked.", + typed_nodes.len() + ); - // Debug: show typed nodes - println!("\nTyped AST nodes before monomorphization:"); - for (i, node) in typed_nodes.iter().enumerate() { - let node_type = match &node.kind { - suicmez::ast::TypedASTNodeKind::Function(f) => { - format!("Function({})", f.name) - } - suicmez::ast::TypedASTNodeKind::Const(c) => { - format!("Const({})", c.name) - } - suicmez::ast::TypedASTNodeKind::Struct(s) => { - format!("Struct({}) with {} params", s.name, s.parameters.len()) - } - suicmez::ast::TypedASTNodeKind::Enum(e) => { - format!("Enum({}) with {} params", e.name, e.parameters.len()) - } - suicmez::ast::TypedASTNodeKind::Impl(imp) => { - format!("Impl({})", imp.target) - } - suicmez::ast::TypedASTNodeKind::Trait(t) => { - format!("Trait({})", t.name) - } - suicmez::ast::TypedASTNodeKind::Extern(e) => { - format!("Extern({})", e.name) - } - suicmez::ast::TypedASTNodeKind::Load(l) => { - format!("Load({})", l.alias) - } - suicmez::ast::TypedASTNodeKind::Use(u) => { - format!("Use({})", u.path) - } - }; - println!(" [{}] {}", i, node_type); + // Debug: show typed nodes + println!("\nTyped AST nodes before monomorphization:"); + for (i, node) in typed_nodes.iter().enumerate() { + let node_type = match &node.kind { + suicmez::ast::TypedASTNodeKind::Function(f) => { + format!("Function({})", f.name) + } + suicmez::ast::TypedASTNodeKind::Const(c) => { + format!("Const({})", c.name) + } + suicmez::ast::TypedASTNodeKind::Struct(s) => { + format!("Struct({}) with {} params", s.name, s.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Enum(e) => { + format!("Enum({}) with {} params", e.name, e.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Impl(imp) => { + format!("Impl({})", imp.target) + } + suicmez::ast::TypedASTNodeKind::Trait(t) => { + format!("Trait({})", t.name) + } + suicmez::ast::TypedASTNodeKind::Extern(e) => { + format!("Extern({})", e.name) + } + suicmez::ast::TypedASTNodeKind::Load(l) => { + format!("Load({})", l.alias) + } + suicmez::ast::TypedASTNodeKind::Use(u) => { + format!("Use({})", u.path) + } + }; + println!(" [{}] {}", i, node_type); + } } - // Monomorphize the AST - let monomorphizer = Monomorphizer::new(); - let mono_nodes = monomorphizer - .monomorphize_program(&typed_nodes) - .map_err(|e| { + let final_nodes = if is_unsafe { + // Skip monomorphization for unsafe mode + typed_nodes + } else { + // Monomorphize the AST + let monomorphizer = Monomorphizer::new(); + let mono_nodes = monomorphizer + .monomorphize_program(&typed_nodes) + .map_err(|e| { + format!( + "Monomorphization error: {}{}", + e.message, + if let Some(span) = &e.span { + format!(" at {}:{}", span.file, span.start) + } else { + String::new() + } + ) + })?; + + println!( + "Monomorphization passed! {} nodes after specialization.", + mono_nodes.len() + ); + + // Print detailed info about each node + println!("\nMonomorphized AST nodes:"); + for (i, node) in mono_nodes.iter().enumerate() { + let node_type = match &node.kind { + suicmez::ast::TypedASTNodeKind::Function(f) => { + format!("Function({})", f.name) + } + suicmez::ast::TypedASTNodeKind::Const(c) => { + format!("Const({})", c.name) + } + suicmez::ast::TypedASTNodeKind::Struct(s) => { + format!("Struct({}) with {} params", s.name, s.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Enum(e) => { + format!("Enum({}) with {} params", e.name, e.parameters.len()) + } + suicmez::ast::TypedASTNodeKind::Impl(imp) => { + format!("Impl({})", imp.target) + } + suicmez::ast::TypedASTNodeKind::Trait(t) => { + format!("Trait({})", t.name) + } + suicmez::ast::TypedASTNodeKind::Extern(e) => { + format!("Extern({})", e.name) + } + suicmez::ast::TypedASTNodeKind::Load(l) => { + format!("Load({})", l.alias) + } + suicmez::ast::TypedASTNodeKind::Use(u) => { + format!("Use({})", u.path) + } + }; + println!(" [{}] {}", i, node_type); + } + + // Check that no type variables remain + check_no_typevars(&mono_nodes).map_err(|e| { format!( - "Monomorphization error: {}{}", + "Type variable check failed: {}{}", e.message, if let Some(span) = &e.span { format!(" at {}:{}", span.file, span.start) @@ -288,65 +447,15 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> { ) })?; - println!( - "Monomorphization passed! {} nodes after specialization.", - mono_nodes.len() - ); + println!("Type variable check passed! No type variables remain in AST."); - // Print detailed info about each node - println!("\nMonomorphized AST nodes:"); - for (i, node) in mono_nodes.iter().enumerate() { - let node_type = match &node.kind { - suicmez::ast::TypedASTNodeKind::Function(f) => { - format!("Function({})", f.name) - } - suicmez::ast::TypedASTNodeKind::Const(c) => { - format!("Const({})", c.name) - } - suicmez::ast::TypedASTNodeKind::Struct(s) => { - format!("Struct({}) with {} params", s.name, s.parameters.len()) - } - suicmez::ast::TypedASTNodeKind::Enum(e) => { - format!("Enum({}) with {} params", e.name, e.parameters.len()) - } - suicmez::ast::TypedASTNodeKind::Impl(imp) => { - format!("Impl({})", imp.target) - } - suicmez::ast::TypedASTNodeKind::Trait(t) => { - format!("Trait({})", t.name) - } - suicmez::ast::TypedASTNodeKind::Extern(e) => { - format!("Extern({})", e.name) - } - suicmez::ast::TypedASTNodeKind::Load(l) => { - format!("Load({})", l.alias) - } - suicmez::ast::TypedASTNodeKind::Use(u) => { - format!("Use({})", u.path) - } - }; - println!(" [{}] {}", i, node_type); - } - - // Check that no type variables remain - check_no_typevars(&mono_nodes).map_err(|e| { - format!( - "Type variable check failed: {}{}", - e.message, - if let Some(span) = &e.span { - format!(" at {}:{}", span.file, span.start) - } else { - String::new() - } - ) - })?; - - println!("Type variable check passed! No type variables remain in AST."); + mono_nodes + }; // Generate C code let mut transpiler = Transpiler::new(debug); let c_code = transpiler - .transpile_program(&mono_nodes) + .transpile_program(&final_nodes) .map_err(|e| format!("Code generation error: {}", e))?; // Write C code to file diff --git a/tests/arrays.c b/tests/arrays.c index e9aed4f..7e33cc5 100644 --- a/tests/arrays.c +++ b/tests/arrays.c @@ -23,7 +23,28 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat } +struct Color { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; +struct Shader { + int id; +}; +static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 }; +static const TypeInfo sui_typeinfo_Color = { + .field_count = 4, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Color +}; +static const uint8_t sui_bitmap_Shader[] = { 0 }; +static const TypeInfo sui_typeinfo_Shader = { + .field_count = 1, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Shader +}; int suic_main(void); diff --git a/tests/basic_types.c b/tests/basic_types.c index 27443d9..eb6eb33 100644 --- a/tests/basic_types.c +++ b/tests/basic_types.c @@ -23,7 +23,28 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat } +struct Color { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; +struct Shader { + int id; +}; +static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 }; +static const TypeInfo sui_typeinfo_Color = { + .field_count = 4, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Color +}; +static const uint8_t sui_bitmap_Shader[] = { 0 }; +static const TypeInfo sui_typeinfo_Shader = { + .field_count = 1, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Shader +}; int suic_main(void); diff --git a/tests/control_flow.c b/tests/control_flow.c index edba436..69edccc 100644 --- a/tests/control_flow.c +++ b/tests/control_flow.c @@ -1,4 +1,4 @@ -#include "../libsuicmez/libsuicmez.h" +#include "libsuicmez/libsuicmez.h" #include #include #include @@ -23,13 +23,38 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat } +struct Color { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; +struct Shader { + int id; +}; +static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 }; +static const TypeInfo sui_typeinfo_Color = { + .field_count = 4, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Color +}; +static const uint8_t sui_bitmap_Shader[] = { 0 }; +static const TypeInfo sui_typeinfo_Shader = { + .field_count = 1, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Shader +}; int suic_main(void); int suic_main(void) { - (true ? 1 : 0); + if (true) { + 1; + } else { + 0; + } int i = 0; while ((i < 5)) { i = (i + 1); diff --git a/tests/functions.c b/tests/functions.c index 08378bb..ec00f8d 100644 --- a/tests/functions.c +++ b/tests/functions.c @@ -1,4 +1,4 @@ -#include "../libsuicmez/libsuicmez.h" +#include "libsuicmez/libsuicmez.h" #include #include #include @@ -23,7 +23,28 @@ static void* suic_alloc_struct(const TypeInfo* type, size_t size, void* init_dat } +struct Color { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; +struct Shader { + int id; +}; +static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 }; +static const TypeInfo sui_typeinfo_Color = { + .field_count = 4, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Color +}; +static const uint8_t sui_bitmap_Shader[] = { 0 }; +static const TypeInfo sui_typeinfo_Shader = { + .field_count = 1, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Shader +}; int add(int x, int y); int suic_main(void); diff --git a/tests/structs.c b/tests/structs.c index 6faa376..16bda91 100644 --- a/tests/structs.c +++ b/tests/structs.c @@ -31,6 +31,15 @@ struct Person { char* name; int age; }; +struct Color { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; +struct Shader { + int id; +}; static const uint8_t sui_bitmap_Point[] = { 0, 0 }; static const TypeInfo sui_typeinfo_Point = { @@ -44,13 +53,25 @@ static const TypeInfo sui_typeinfo_Person = { .pointer_count = 1, .pointer_bitmap = sui_bitmap_Person }; +static const uint8_t sui_bitmap_Color[] = { 0, 0, 0, 0 }; +static const TypeInfo sui_typeinfo_Color = { + .field_count = 4, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Color +}; +static const uint8_t sui_bitmap_Shader[] = { 0 }; +static const TypeInfo sui_typeinfo_Shader = { + .field_count = 1, + .pointer_count = 0, + .pointer_bitmap = sui_bitmap_Shader +}; int suic_main(void); int suic_main(void) { - struct Point* p = suic_alloc_struct(&sui_typeinfo_Point, sizeof(struct Point), &(struct Point){ .x = 5, .y = 10 }); - struct Person* person = suic_alloc_struct(&sui_typeinfo_Person, sizeof(struct Person), &(struct Person){ .name = suic_alloc_array(NULL, sizeof(char), 6, "Alice"), .age = 30 }); + struct Point* p = (struct Point){ .x = 5, .y = 10 }; + struct Person* person = (struct Person){ .name = suic_alloc_array(NULL, sizeof(char), 6, "Alice"), .age = 30 }; int _ = ((*p).x + (*person).age); return 0; }