This commit is contained in:
Masashi 2025-12-20 01:56:02 +05:30
commit 22afdb20a4
13 changed files with 2055 additions and 1188 deletions

File diff suppressed because it is too large Load diff

1174
game/client.c.bak Normal file

File diff suppressed because it is too large Load diff

View file

@ -67,6 +67,7 @@ pub enum ASTNodeKind {
Function(Function),
Extern(Extern),
Load(Load),
Const(Const),
Struct(Struct),
Enum(Enum),
Impl(Impl),
@ -80,6 +81,13 @@ pub struct Use {
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct Const {
pub name: String,
pub typ: Option<TypeAnnot>,
pub value: Expr,
}
// ? implies OPTIONAL here
// \( implies the presence of (. same for /)
@ -265,6 +273,8 @@ pub enum BinOp {
Or,
BitwiseAnd,
BitwiseOr,
LShift,
RShift,
Eq,
Neq,
Lt,
@ -314,6 +324,7 @@ pub enum TypedASTNodeKind {
Function(TypedFunction),
Extern(TypedExtern),
Load(TypedLoad),
Const(TypedConst),
Struct(TypedStruct),
Enum(TypedEnum),
Impl(TypedImpl),
@ -347,6 +358,13 @@ pub struct TypedLoad {
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct TypedConst {
pub name: String,
pub typ: Option<TypeAnnot>,
pub value: TypedExpr,
}
#[derive(Debug, Clone)]
pub struct TypedStruct {
pub name: String,

View file

@ -65,6 +65,7 @@ pub struct CVarDecl {
pub name: String,
pub ty: CType,
pub initializer: Option<CExpr>,
pub is_const: bool,
}
#[derive(Debug, Clone, PartialEq)]
@ -120,6 +121,8 @@ pub enum CBinaryOp {
Or,
BitwiseAnd,
BitwiseOr,
LShift,
RShift,
}
impl CBinaryOp {
@ -140,6 +143,8 @@ impl CBinaryOp {
CBinaryOp::Or => "||",
CBinaryOp::BitwiseAnd => "&",
CBinaryOp::BitwiseOr => "|",
CBinaryOp::LShift => "<<",
CBinaryOp::RShift => ">>",
}
}
}

View file

@ -23,6 +23,7 @@ impl DeclarationTranspiler {
name: field.name.clone(),
ty: field_type,
initializer: None,
is_const: false,
});
}
@ -53,6 +54,7 @@ impl DeclarationTranspiler {
name: name.clone(),
ty: param_type,
initializer: None,
is_const: false,
});
}
@ -81,6 +83,7 @@ impl DeclarationTranspiler {
name: field_name,
ty: c_type,
initializer: None,
is_const: false,
});
}
@ -100,6 +103,7 @@ impl DeclarationTranspiler {
name: field_name,
ty: CType::Struct(struct_name),
initializer: None,
is_const: false,
});
}
@ -115,11 +119,13 @@ impl DeclarationTranspiler {
name: "discriminant".to_string(),
ty: CType::Int,
initializer: None,
is_const: false,
},
CVarDecl {
name: "data".to_string(),
ty: CType::Struct(union_name_clone),
initializer: None,
is_const: false,
},
];
@ -160,6 +166,7 @@ impl DeclarationTranspiler {
name: format!("field{}", i),
ty: field_type,
initializer: None,
is_const: false,
});
}
Ok(CType::UnnamedStruct(c_fields))

View file

@ -30,6 +30,7 @@ impl StatementsTranspiler {
name: name.clone(),
ty,
initializer,
is_const: false,
};
(name, decl)
@ -182,6 +183,7 @@ impl StatementsTranspiler {
name: name.clone(),
ty: c_type,
initializer,
is_const: false,
};
Ok(CStmt::VarDecl(var_decl))
}
@ -233,6 +235,7 @@ impl StatementsTranspiler {
name: var_name.clone(),
ty: CType::Int,
initializer: Some(start_expr),
is_const: false,
};
let cond = CExpr::BinOp(
@ -284,6 +287,7 @@ impl StatementsTranspiler {
)),
Box::new(CExpr::Var(idx_name.clone())),
)),
is_const: false,
});
let mut body_stmts = vec![bind];
@ -333,6 +337,7 @@ impl StatementsTranspiler {
Box::new(CExpr::Var(arr_name.clone())),
Box::new(CExpr::Var(idx_name.clone())),
)),
is_const: false,
});
let mut body_stmts = vec![bind];
@ -468,6 +473,8 @@ impl StatementsTranspiler {
BinOp::Or => Ok(CBinaryOp::Or),
BinOp::BitwiseAnd => Ok(CBinaryOp::BitwiseAnd),
BinOp::BitwiseOr => Ok(CBinaryOp::BitwiseOr),
BinOp::LShift => Ok(CBinaryOp::LShift),
BinOp::RShift => Ok(CBinaryOp::RShift),
}
}
@ -481,7 +488,7 @@ impl StatementsTranspiler {
}
}
fn type_to_ctype(&self, ty: &Type) -> Result<CType, String> {
pub fn type_to_ctype(&self, ty: &Type) -> Result<CType, String> {
match ty {
Type::Int => Ok(CType::Int),
Type::U8 => Ok(CType::U8),
@ -509,6 +516,7 @@ impl StatementsTranspiler {
name: format!("field{}", i),
ty: c_type,
initializer: None,
is_const: false,
});
}
Ok(CType::UnnamedStruct(fields))
@ -565,6 +573,7 @@ impl StatementsTranspiler {
name: format!("field{}", i),
ty: field_type,
initializer: None,
is_const: false,
});
}
Ok(CType::UnnamedStruct(c_fields))

View file

@ -90,6 +90,39 @@ impl Transpiler {
self.lower_declarations_to_c_ir(node)?;
}
// Add builtin structs
if !self.structs.iter().any(|s| s.name == "Color") {
self.structs.push(CStructDecl {
name: "Color".to_string(),
fields: vec![
CVarDecl { name: "r".to_string(), ty: CType::U8, initializer: None, is_const: false },
CVarDecl { name: "g".to_string(), ty: CType::U8, initializer: None, is_const: false },
CVarDecl { name: "b".to_string(), ty: CType::U8, initializer: None, is_const: false },
CVarDecl { name: "a".to_string(), ty: CType::U8, initializer: None, is_const: false },
],
});
// Generate TypeInfo
let bitmap = Self::generate_pointer_bitmap(&vec![
CVarDecl { name: "r".to_string(), ty: CType::U8, initializer: None, is_const: false },
CVarDecl { name: "g".to_string(), ty: CType::U8, initializer: None, is_const: false },
CVarDecl { name: "b".to_string(), ty: CType::U8, initializer: None, is_const: false },
CVarDecl { name: "a".to_string(), ty: CType::U8, initializer: None, is_const: false },
]);
self.typeinfo_map.insert("Color".to_string(), bitmap);
}
if !self.structs.iter().any(|s| s.name == "Shader") {
self.structs.push(CStructDecl {
name: "Shader".to_string(),
fields: vec![
CVarDecl { name: "id".to_string(), ty: CType::Int, initializer: None, is_const: false },
],
});
let bitmap = Self::generate_pointer_bitmap(&vec![
CVarDecl { name: "id".to_string(), ty: CType::Int, initializer: None, is_const: false },
]);
self.typeinfo_map.insert("Shader".to_string(), bitmap);
}
self.lower_function_bodies_to_c_ir(nodes)?;
// Rename main to suic_main and track that we have a main
@ -238,6 +271,16 @@ impl Transpiler {
self.functions.push(func_decl);
}
}
TypedASTNodeKind::Const(c) => {
let value_code = self.stmt_transpiler.transpile_expr(&c.value)?;
let var_decl = CVarDecl {
name: c.name.clone(),
ty: self.stmt_transpiler.type_to_ctype(&c.value.ty)?,
initializer: Some(value_code),
is_const: true,
};
self.globals.push(var_decl);
}
TypedASTNodeKind::Extern(e) => {
// For externs, we might need to add function prototypes
// But for now, skip as they're handled differently
@ -408,6 +451,9 @@ impl Transpiler {
CType::FixedArray(elem_ty, size) => format!("{} {}[{}]", elem_ty.to_string(), var.name, size),
_ => format!("{} {}", var.ty.to_string(), var.name),
};
if var.is_const {
output = format!("const {}", output);
}
if let Some(init) = &var.initializer {
match (&var.ty, init) {
(CType::FixedArray(_, _), CExpr::ArrayLit(elements)) => {
@ -652,13 +698,14 @@ impl Transpiler {
"rl_pop_matrix" => "suic_rl_pop_matrix",
"rl_translate_f" => "suic_rl_translate_f",
"rl_rotate_f" => "suic_rl_rotate_f",
// UI Framework Utils
"draw_text" => "suic_draw_text",
"draw_rectangle" => "suic_draw_rectangle",
"draw_rectangle_lines" => "suic_draw_rectangle_lines",
"measure_text" => "suic_measure_text",
"draw_circle" => "suic_draw_circle",
"draw_line" => "suic_draw_line",
// UI Framework Utils
"draw_text" => "DrawText",
"draw_rectangle" => "DrawRectangle",
"draw_rectangle_lines" => "DrawRectangleLines",
"measure_text" => "MeasureText",
"draw_circle" => "DrawCircle",
"draw_line" => "DrawLine",
"draw_fps" => "DrawFPS",
// Player controller functions
"player_controller_create" => "suic_player_controller_create",
"player_controller_destroy" => "suic_player_controller_destroy",
@ -749,18 +796,7 @@ impl Transpiler {
"Vec3" => "suic_vec3".to_string(),
_ => format!("struct {}", struct_name),
};
// For built-in simple structs, generate compound literal directly
// For user-defined structs, use heap allocation
match struct_name.as_str() {
"Vec2" | "Vec3" => format!("({}){{ {} }}", c_type_name, field_inits.join(", ")),
_ => format!(
"suic_alloc_struct(&sui_typeinfo_{}, sizeof({}), &({}){{ {} }})",
struct_name,
c_type_name,
c_type_name,
field_inits.join(", ")
),
}
format!("({}){{ {} }}", c_type_name, field_inits.join(", "))
}
CExpr::EnumLit(enum_name, variant_name, args) => {
// Find the variant index - for simplicity, assume variants are in order

View file

@ -370,14 +370,22 @@ impl ImportResolver {
ASTNodeKind::Load(_) => {
result.push(node);
}
ASTNodeKind::Trait(t) => {
self.symbol_registry.register(
t.name.clone(),
filename.to_string(),
node.span.clone(),
)?;
result.push(node);
}
ASTNodeKind::Trait(t) => {
self.symbol_registry.register(
t.name.clone(),
filename.to_string(),
node.span.clone(),
)?;
result.push(node);
}
ASTNodeKind::Const(c) => {
self.symbol_registry.register(
c.name.clone(),
filename.to_string(),
node.span.clone(),
)?;
result.push(node);
}
}
}

View file

@ -146,6 +146,9 @@ pub enum Token {
#[token("trait")]
KeywordTrait,
#[token("const")]
KeywordConst,
// #[token("type")]
// KeywordType,
//
@ -182,6 +185,12 @@ pub enum Token {
#[token("**", priority = 3)]
Power,
#[token("<<")]
LShift,
#[token(">>")]
RShift,
#[token("$")]
Dollar,

View file

@ -244,6 +244,9 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> {
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())
}
@ -297,6 +300,9 @@ fn run_file(filename: &str, debug: bool) -> Result<(), String> {
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())
}

View file

@ -104,6 +104,9 @@ impl Monomorphizer {
for (_idx, node) in nodes.iter().enumerate() {
match &node.kind {
TypedASTNodeKind::Const(c) => {
result_nodes.push(node.clone());
}
TypedASTNodeKind::Function(f) => {
// Skip generic functions - they'll be added as specialized versions when needed
if !f.parameters.is_empty() {
@ -988,6 +991,9 @@ fn check_node_for_typevars(node: &TypedASTNode) -> Result<(), MonomorphizationEr
TypedASTNodeKind::Function(f) => {
check_function_for_typevars(f)?;
}
TypedASTNodeKind::Const(c) => {
// Consts should not have typevars
}
TypedASTNodeKind::Struct(s) => {
check_struct_for_typevars(s)?;
}

View file

@ -149,6 +149,16 @@ impl Parser {
attributes,
})
}
Some(Token::KeywordConst) => {
self.next();
let const_def = self.parse_const()?;
let end = self.peek_span().unwrap_or(start..start).end;
Ok(ASTNode {
kind: ASTNodeKind::Const(const_def),
span: Span::new(&(start..end), self.file.clone()),
attributes,
})
}
Some(Token::KeywordStruct) => {
self.next();
let struct_def = self.parse_struct()?;
@ -211,12 +221,33 @@ impl Parser {
}
Some(token) => {
let span = self.peek_span().unwrap_or(start..start);
self.error(format!("Unexpected token at top level: {:?}. Expected declarations like 'fn', 'struct', 'enum', 'impl', 'trait', 'use', 'load', or 'extern'", token), span)
self.error(format!("Unexpected token at top level: {:?}. Expected declarations like 'fn', 'struct', 'enum', 'impl', 'trait', 'const', 'use', 'load', or 'extern'", token), span)
}
None => self.error("Unexpected end of file at top level. Expected declarations like 'fn', 'struct', 'enum', etc.".to_string(), start..start),
}
}
fn parse_const(&mut self) -> Result<Const, ParseError> {
let start = self.peek_span().unwrap_or(0..0).start;
let name = match self.next() {
Some((Token::Variable(n), _)) => n,
Some((_, span)) => return self.error("Expected constant name after 'const' keyword. Example: const PI = 3.14".to_string(), span),
None => return self.error("Expected constant name after 'const' keyword. Example: const PI = 3.14".to_string(), start..start),
};
let typ = if matches!(self.peek(), Some(Token::Colon)) {
self.next();
Some(self.parse_type_annot()?)
} else {
None
};
self.expect(Token::Assign)?;
let value = self.parse_expr()?;
Ok(Const { name, typ, value })
}
fn parse_attribute(&mut self) -> Result<Attribute, ParseError> {
self.expect(Token::At)?;
let start = self.peek_span().unwrap_or(0..0).start;
@ -1173,14 +1204,44 @@ impl Parser {
Ok(left)
}
fn parse_bitwise_and_expr(&mut self) -> Result<Expr, ParseError> {
fn parse_shift_expr(&mut self) -> Result<Expr, ParseError> {
let mut left = self.parse_eq_expr()?;
loop {
let op = if matches!(self.peek(), Some(Token::LShift)) {
Some(BinOp::LShift)
} else if matches!(self.peek(), Some(Token::RShift)) {
Some(BinOp::RShift)
} else {
None
};
if let Some(op) = op {
let start = left.span.start;
self.next();
let right = self.parse_eq_expr()?;
let end = right.span.end;
left = Expr {
kind: ExprKind::BinOp(Box::new(left), op, Box::new(right)),
span: Span::new(&(start..end), self.file.clone()),
attributes: Vec::new(),
};
} else {
break;
}
}
Ok(left)
}
fn parse_bitwise_and_expr(&mut self) -> Result<Expr, ParseError> {
let mut left = self.parse_shift_expr()?;
loop {
if matches!(self.peek(), Some(Token::BitAnd)) {
let start = left.span.start;
self.next();
let right = self.parse_eq_expr()?;
let right = self.parse_shift_expr()?;
let end = right.span.end;
left = Expr {
kind: ExprKind::BinOp(Box::new(left), BinOp::BitwiseAnd, Box::new(right)),

View file

@ -370,6 +370,351 @@ impl TypeChecker {
}
fn add_builtin_functions(&mut self) {
// Builtin types
self.env.types.insert(
"Vector3".to_string(),
TypeInfo {
kind: TypeInfoKind::Struct(vec![
("x".to_string(), TypeAnnot::Var("float".to_string())),
("y".to_string(), TypeAnnot::Var("float".to_string())),
("z".to_string(), TypeAnnot::Var("float".to_string())),
]),
parameters: vec![],
},
);
self.env.types.insert(
"Color".to_string(),
TypeInfo {
kind: TypeInfoKind::Struct(vec![
("r".to_string(), TypeAnnot::Var("u8".to_string())),
("g".to_string(), TypeAnnot::Var("u8".to_string())),
("b".to_string(), TypeAnnot::Var("u8".to_string())),
("a".to_string(), TypeAnnot::Var("u8".to_string())),
]),
parameters: vec![],
},
);
self.env.types.insert(
"Shader".to_string(),
TypeInfo {
kind: TypeInfoKind::Struct(vec![
("id".to_string(), TypeAnnot::Var("int".to_string())),
]),
parameters: vec![],
},
);
self.env.types.insert(
"Vector2".to_string(),
TypeInfo {
kind: TypeInfoKind::Struct(vec![
("x".to_string(), TypeAnnot::Var("float".to_string())),
("y".to_string(), TypeAnnot::Var("float".to_string())),
]),
parameters: vec![],
},
);
self.env.types.insert(
"sockaddr_in".to_string(),
TypeInfo {
kind: TypeInfoKind::Struct(vec![
("sin_family".to_string(), TypeAnnot::Var("u16".to_string())),
("sin_port".to_string(), TypeAnnot::Var("u16".to_string())),
("sin_addr".to_string(), TypeAnnot::Cons("in_addr".to_string(), vec![])),
("sin_zero".to_string(), TypeAnnot::FixedArray(Box::new(TypeAnnot::Var("u8".to_string())), 8)),
]),
parameters: vec![],
},
);
// Builtin functions
// Raylib
self.env.functions.insert(
"init_window".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int, Type::Int, Type::String],
return_type: Type::Unit,
},
);
self.env.functions.insert(
"close_window".to_string(),
FunctionType {
type_params: vec![],
params: vec![],
return_type: Type::Unit,
},
);
self.env.functions.insert(
"window_should_close".to_string(),
FunctionType {
type_params: vec![],
params: vec![],
return_type: Type::Bool,
},
);
self.env.functions.insert(
"set_target_fps".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int],
return_type: Type::Unit,
},
);
self.env.functions.insert(
"disable_cursor".to_string(),
FunctionType {
type_params: vec![],
params: vec![],
return_type: Type::Unit,
},
);
self.env.functions.insert(
"get_char_pressed".to_string(),
FunctionType {
type_params: vec![],
params: vec![],
return_type: Type::Int,
},
);
self.env.functions.insert(
"is_key_pressed".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int],
return_type: Type::Bool,
},
);
self.env.functions.insert(
"is_key_down".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int],
return_type: Type::Bool,
},
);
self.env.functions.insert(
"get_mouse_delta".to_string(),
FunctionType {
type_params: vec![],
params: vec![],
return_type: Type::Struct("Vector2".to_string(), vec![]),
},
);
self.env.functions.insert(
"is_mouse_button_down".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int],
return_type: Type::Bool,
},
);
self.env.functions.insert(
"get_random_value".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int, Type::Int],
return_type: Type::Int,
},
);
self.env.functions.insert(
"get_frame_time".to_string(),
FunctionType {
type_params: vec![],
params: vec![],
return_type: Type::Float,
},
);
self.env.functions.insert(
"begin_drawing".to_string(),
FunctionType {
type_params: vec![],
params: vec![],
return_type: Type::Unit,
},
);
self.env.functions.insert(
"end_drawing".to_string(),
FunctionType {
type_params: vec![],
params: vec![],
return_type: Type::Unit,
},
);
self.env.functions.insert(
"clear_background".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int, Type::Int, Type::Int, Type::Int],
return_type: Type::Unit,
},
);
self.env.functions.insert(
"draw_text".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::String, Type::Int, Type::Int, Type::Int, Type::Int, Type::Int, Type::Int, Type::Int],
return_type: Type::Unit,
},
);
self.env.functions.insert(
"draw_fps".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int, Type::Int],
return_type: Type::Unit,
},
);
// Math functions
self.env.functions.insert(
"sinf".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Float],
return_type: Type::Float,
},
);
self.env.functions.insert(
"cosf".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Float],
return_type: Type::Float,
},
);
self.env.functions.insert(
"sqrtf".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Float],
return_type: Type::Float,
},
);
self.env.functions.insert(
"fmaxf".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Float, Type::Float],
return_type: Type::Float,
},
);
self.env.functions.insert(
"floorf".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Float],
return_type: Type::Float,
},
);
self.env.functions.insert(
"powf".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Float, Type::Float],
return_type: Type::Float,
},
);
self.env.functions.insert(
"expf".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Float],
return_type: Type::Float,
},
);
// Noise functions
self.env.functions.insert(
"grad2".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int, Type::Float, Type::Float],
return_type: Type::Float,
},
);
self.env.functions.insert(
"simplex_noise_2d".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Float, Type::Float],
return_type: Type::Float,
},
);
self.env.functions.insert(
"fbm_noise".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Float, Type::Float, Type::Int],
return_type: Type::Float,
},
);
self.env.functions.insert(
"get_terrain_height".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Float, Type::Float],
return_type: Type::Float,
},
);
// Socket functions
self.env.functions.insert(
"socket".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int, Type::Int, Type::Int],
return_type: Type::Int,
},
);
self.env.functions.insert(
"sendto".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int, Type::Ptr(Box::new(Type::U8)), Type::Int, Type::Int, Type::Ptr(Box::new(Type::Unit)), Type::Int],
return_type: Type::Int,
},
);
self.env.functions.insert(
"recvfrom".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int, Type::Ptr(Box::new(Type::U8)), Type::Int, Type::Int, Type::Ptr(Box::new(Type::Unit)), Type::Ptr(Box::new(Type::Int))],
return_type: Type::Int,
},
);
self.env.functions.insert(
"close".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int],
return_type: Type::Int,
},
);
self.env.functions.insert(
"htonl".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int],
return_type: Type::Int,
},
);
self.env.functions.insert(
"htons".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int],
return_type: Type::Int,
},
);
self.env.functions.insert(
"inet_pton".to_string(),
FunctionType {
type_params: vec![],
params: vec![Type::Int, Type::String, Type::Ptr(Box::new(Type::Unit))],
return_type: Type::Int,
},
);
// ODE Physics Engine functions
self.env.functions.insert(
"ode_init".to_string(),
@ -1564,6 +1909,19 @@ impl TypeChecker {
fn typecheck_node(&mut self, node: &ASTNode) -> Result<TypedASTNode, TypeError> {
let ty = match &node.kind {
ASTNodeKind::Const(c) => {
let typed_value = self.typecheck_expr(&c.value)?;
return Ok(TypedASTNode {
kind: TypedASTNodeKind::Const(TypedConst {
name: c.name.clone(),
typ: c.typ.clone(),
value: typed_value.clone(),
}),
span: node.span.clone(),
attributes: node.attributes.clone(),
ty: typed_value.ty,
});
}
ASTNodeKind::Function(f) => {
let typed_func = self.typecheck_function(f)?;
let ty = typed_func.ty.clone();
@ -1862,7 +2220,7 @@ impl TypeChecker {
let typed_right = self.typecheck_expr(right)?;
let result_type = match op {
BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Mod | BinOp::BitwiseAnd | BinOp::BitwiseOr => {
BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Mod | BinOp::BitwiseAnd | BinOp::BitwiseOr | BinOp::LShift | BinOp::RShift => {
if !self.types_compatible(&typed_left.ty, &typed_right.ty) {
return Err(TypeError {
kind: TypeErrorKind::TypeMismatch(