This commit is contained in:
Masashi 2025-12-20 03:16:16 +05:30
commit a222b3807e
7 changed files with 355 additions and 110 deletions

View file

@ -81,6 +81,8 @@ struct ParsedFile {
nodes: Vec<ASTNode>,
/// 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<String>,
/// Dependency graph: file -> list of files it depends on
dependency_graph: HashMap<String, HashSet<String>>,
/// 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<Vec<ASTNode>, 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
}
}

View file

@ -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<TypedASTNode> {
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

View file

@ -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);

View file

@ -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);

View file

@ -1,4 +1,4 @@
#include "../libsuicmez/libsuicmez.h"
#include "libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
@ -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);

View file

@ -1,4 +1,4 @@
#include "../libsuicmez/libsuicmez.h"
#include "libsuicmez/libsuicmez.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
@ -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);

View file

@ -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;
}