Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 4 additions & 2 deletions front/lexer/src/lexer/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ use super::Lexer;

impl<'a> Lexer<'a> {
pub(crate) fn string(&mut self) -> String {
if self.peek() == '"' { self.advance(); }

let mut string_literal = String::new();
while !self.is_at_end() && self.peek() != '"' {
if self.peek() == '\n' {
panic!("Unterminated string (newline in string literal).");
}

let c = self.advance();

if c == '\\' {
Expand Down
5 changes: 4 additions & 1 deletion front/parser/src/parser/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ pub fn is_expression_start(token_type: &TokenType) -> bool {
| TokenType::Lbrack
| TokenType::Asm
| TokenType::Deref
| TokenType::CharLiteral(_)
)
}

Expand Down Expand Up @@ -218,7 +219,9 @@ pub fn parse_type_from_stream(tokens: &mut Peekable<Iter<Token>>) -> Option<Wave
let type_token = tokens.next()?;

if let TokenType::Identifier(name) = &type_token.token_type {
while matches!(tokens.peek().map(|t| &t.token_type), Some(TokenType::Whitespace)) {
while matches!(tokens.peek().map(|t| &t.token_type),
Some(TokenType::Whitespace | TokenType::Newline)
) {
tokens.next();
}

Expand Down
41 changes: 30 additions & 11 deletions llvm_temporary/src/llvm_temporary/expression/rvalue/assign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::llvm_temporary::llvm_codegen::generate_address_ir;
use inkwell::types::{AnyTypeEnum, BasicTypeEnum};
use inkwell::values::{BasicValue, BasicValueEnum};
use parser::ast::{AssignOperator, Expression};
use crate::llvm_temporary::statement::variable::{coerce_basic_value, CoercionMode};

pub(crate) fn gen_assign_operation<'ctx, 'a>(
env: &mut ExprGenEnv<'ctx, 'a>,
Expand All @@ -14,6 +15,34 @@ pub(crate) fn gen_assign_operation<'ctx, 'a>(
env.context, env.builder, target, env.variables, env.module, env.struct_types, env.struct_field_indices
);

let element_type = match ptr.get_type().get_element_type() {
AnyTypeEnum::IntType(t) => BasicTypeEnum::IntType(t),
AnyTypeEnum::FloatType(t) => BasicTypeEnum::FloatType(t),
AnyTypeEnum::PointerType(t) => BasicTypeEnum::PointerType(t),
AnyTypeEnum::ArrayType(t) => BasicTypeEnum::ArrayType(t),
AnyTypeEnum::StructType(t) => BasicTypeEnum::StructType(t),
AnyTypeEnum::VectorType(t) => BasicTypeEnum::VectorType(t),
_ => panic!("Unsupported LLVM element type"),
};

if matches!(operator, AssignOperator::Assign) {
let mut rhs = env.gen(value, Some(element_type));

if rhs.get_type() != element_type {
rhs = coerce_basic_value(
env.context,
env.builder,
rhs,
element_type,
"assign_cast",
CoercionMode::Implicit,
);
}

env.builder.build_store(ptr, rhs).unwrap();
return rhs;
}

let current_val = env.builder.build_load(ptr, "load_current").unwrap();

let new_val = env.gen(value, Some(current_val.get_type()));
Expand Down Expand Up @@ -55,17 +84,7 @@ pub(crate) fn gen_assign_operation<'ctx, 'a>(
AssignOperator::RemAssign => env.builder.build_float_rem(lhs, rhs, "rem_assign").unwrap().as_basic_value_enum(),
},

_ => panic!("Type mismatch or unsupported type in AssignOperation"),
};

let element_type = match ptr.get_type().get_element_type() {
AnyTypeEnum::IntType(t) => BasicTypeEnum::IntType(t),
AnyTypeEnum::FloatType(t) => BasicTypeEnum::FloatType(t),
AnyTypeEnum::PointerType(t) => BasicTypeEnum::PointerType(t),
AnyTypeEnum::ArrayType(t) => BasicTypeEnum::ArrayType(t),
AnyTypeEnum::StructType(t) => BasicTypeEnum::StructType(t),
AnyTypeEnum::VectorType(t) => BasicTypeEnum::VectorType(t),
_ => panic!("Unsupported LLVM element type"),
_ => panic!("AssignOperation (+=, -=, ...) only supports numeric types"),
};

let result_casted = match (result, element_type) {
Expand Down
69 changes: 69 additions & 0 deletions llvm_temporary/src/llvm_temporary/expression/rvalue/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,75 @@ pub(crate) fn gen<'ctx, 'a>(
_ => panic!("Unsupported mixed-type operator (float + int)"),
}
}
(BasicValueEnum::PointerValue(lp), BasicValueEnum::PointerValue(rp)) => {
let i64_ty = env.context.i64_type();
let li = env.builder.build_ptr_to_int(lp, i64_ty, "l_ptr2int").unwrap();
let ri = env.builder.build_ptr_to_int(rp, i64_ty, "r_ptr2int").unwrap();

let mut result = match operator {
Operator::Equal => env.builder.build_int_compare(IntPredicate::EQ, li, ri, "ptreq").unwrap(),
Operator::NotEqual => env.builder.build_int_compare(IntPredicate::NE, li, ri, "ptrne").unwrap(),
_ => panic!("Unsupported pointer operator: {:?}", operator),
};

if let Some(inkwell::types::BasicTypeEnum::IntType(target_ty)) = expected_type {
if result.get_type() != target_ty {
result = env.builder.build_int_cast(result, target_ty, "cast_result").unwrap();
}
}

return result.as_basic_value_enum();
}

(BasicValueEnum::PointerValue(lp), BasicValueEnum::IntValue(ri)) => {
let i64_ty = env.context.i64_type();
let li = env.builder.build_ptr_to_int(lp, i64_ty, "l_ptr2int").unwrap();

let ri = if ri.get_type().get_bit_width() == 64 {
ri
} else {
env.builder.build_int_cast(ri, i64_ty, "r_i64").unwrap()
};

let mut result = match operator {
Operator::Equal => env.builder.build_int_compare(IntPredicate::EQ, li, ri, "ptreq0").unwrap(),
Operator::NotEqual => env.builder.build_int_compare(IntPredicate::NE, li, ri, "ptrne0").unwrap(),
_ => panic!("Unsupported ptr/int operator: {:?}", operator),
};

if let Some(inkwell::types::BasicTypeEnum::IntType(target_ty)) = expected_type {
if result.get_type() != target_ty {
result = env.builder.build_int_cast(result, target_ty, "cast_result").unwrap();
}
}

return result.as_basic_value_enum();
}

(BasicValueEnum::IntValue(li), BasicValueEnum::PointerValue(rp)) => {
let i64_ty = env.context.i64_type();
let li = if li.get_type().get_bit_width() == 64 {
li
} else {
env.builder.build_int_cast(li, i64_ty, "l_i64").unwrap()
};

let ri = env.builder.build_ptr_to_int(rp, i64_ty, "r_ptr2int").unwrap();

let mut result = match operator {
Operator::Equal => env.builder.build_int_compare(IntPredicate::EQ, li, ri, "ptreq0").unwrap(),
Operator::NotEqual => env.builder.build_int_compare(IntPredicate::NE, li, ri, "ptrne0").unwrap(),
_ => panic!("Unsupported int/ptr operator: {:?}", operator),
};

if let Some(inkwell::types::BasicTypeEnum::IntType(target_ty)) = expected_type {
if result.get_type() != target_ty {
result = env.builder.build_int_cast(result, target_ty, "cast_result").unwrap();
}
}

return result.as_basic_value_enum();
}

_ => panic!("Type mismatch in binary expression"),
}
Expand Down
86 changes: 85 additions & 1 deletion llvm_temporary/src/llvm_temporary/expression/rvalue/calls.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
use inkwell::types::BasicTypeEnum;
use inkwell::types::{AsTypeRef, BasicTypeEnum};
use super::ExprGenEnv;
use inkwell::values::{BasicMetadataValueEnum, BasicValue, BasicValueEnum};
use parser::ast::{Expression, WaveType};
use crate::llvm_temporary::statement::variable::{coerce_basic_value, CoercionMode};

fn normalize_struct_name(raw: &str) -> &str {
raw.strip_prefix("struct.").unwrap_or(raw).trim_start_matches('%')
}

fn resolve_struct_key<'ctx>(
st: inkwell::types::StructType<'ctx>,
struct_types: &std::collections::HashMap<String, inkwell::types::StructType<'ctx>>,
) -> String {
if let Some(raw) = st.get_name().and_then(|n| n.to_str().ok()) {
return normalize_struct_name(raw).to_string();
}

let st_ref = st.as_type_ref();
for (name, ty) in struct_types {
if ty.as_type_ref() == st_ref {
return name.clone();
}
}

panic!("LLVM struct type has no name and cannot be matched to struct_types");
}


pub(crate) fn gen_method_call<'ctx, 'a>(
env: &mut ExprGenEnv<'ctx, 'a>,
object: &Expression,
Expand Down Expand Up @@ -59,6 +82,67 @@ pub(crate) fn gen_method_call<'ctx, 'a>(
}
}

{
let obj_preview = env.gen(object, None);
let obj_ty = obj_preview.get_type();

let struct_name_opt: Option<String> = match obj_ty {
BasicTypeEnum::StructType(st) => Some(resolve_struct_key(st, env.struct_types)),
BasicTypeEnum::PointerType(p) if p.get_element_type().is_struct_type() => {
Some(resolve_struct_key(p.get_element_type().into_struct_type(), env.struct_types))
}
_ => None,
};

if let Some(struct_name) = struct_name_opt {
let fn_name = format!("{}_{}", struct_name, name);

if let Some(function) = env.module.get_function(&fn_name) {
let fn_type = function.get_type();
let param_types = fn_type.get_param_types();
let expected_self = param_types.get(0).cloned();

let mut obj_val = obj_preview;
if let Some(et) = expected_self {
obj_val = coerce_basic_value(
env.context,
env.builder,
obj_val,
et,
"self_cast",
CoercionMode::Implicit,
);
}

let mut call_args: Vec<BasicMetadataValueEnum> = Vec::new();
call_args.push(obj_val.into());

for (i, arg_expr) in args.iter().enumerate() {
let expected_ty = param_types.get(i + 1).cloned();
let mut arg_val = env.gen(arg_expr, expected_ty);
if let Some(et) = expected_ty {
arg_val = coerce_basic_value(
env.context, env.builder, arg_val, et, &format!("arg{}_cast", i),
CoercionMode::Implicit
);
}
call_args.push(arg_val.into());
}

let call_site = env
.builder
.build_call(function, &call_args, &format!("call_{}", fn_name))
.unwrap();

if function.get_type().get_return_type().is_some() {
return call_site.try_as_basic_value().left().unwrap();
} else {
return env.context.i32_type().const_zero().as_basic_value_enum();
}
}
}
}

// method-style call: fn(self, ...)
let function = env
.module
Expand Down
51 changes: 20 additions & 31 deletions llvm_temporary/src/llvm_temporary/expression/rvalue/structs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::ExprGenEnv;
use inkwell::values::{BasicValue, BasicValueEnum};
use parser::ast::{Expression, WaveType};
use crate::llvm_temporary::llvm_codegen::generate_address_ir;

pub(crate) fn gen_struct_literal<'ctx, 'a>(
env: &mut ExprGenEnv<'ctx, 'a>,
Expand All @@ -27,7 +28,11 @@ pub(crate) fn gen_struct_literal<'ctx, 'a>(
.get(field_name)
.unwrap_or_else(|| panic!("Field '{}' not found in struct '{}'", field_name, name));

let field_val = env.gen(field_expr, None);
let expected_field_ty = struct_ty
.get_field_type_at_index(*idx)
.unwrap_or_else(|| panic!("No field type at index {} for struct '{}'", idx, name));

let field_val = env.gen(field_expr, Some(expected_field_ty));

let field_ptr = env
.builder
Expand All @@ -48,40 +53,24 @@ pub(crate) fn gen_field_access<'ctx, 'a>(
object: &Expression,
field: &str,
) -> BasicValueEnum<'ctx> {
let var_name = match object {
Expression::Variable(name) => name,
other => panic!("FieldAccess on non-variable object not supported yet: {:?}", other),
};

let var_info = env
.variables
.get(var_name)
.unwrap_or_else(|| panic!("Variable '{}' not found for field access", var_name));

let struct_name = match &var_info.ty {
WaveType::Struct(name) => name,
other_ty => panic!(
"Field access on non-struct type {:?} for variable '{}'",
other_ty, var_name
),
let full = Expression::FieldAccess {
object: Box::new(object.clone()),
field: field.to_string(),
};

let field_indices = env
.struct_field_indices
.get(struct_name)
.unwrap_or_else(|| panic!("Field index map for struct '{}' not found", struct_name));

let idx = field_indices
.get(field)
.unwrap_or_else(|| panic!("Field '{}' not found in struct '{}'", field, struct_name));

let field_ptr = env
.builder
.build_struct_gep(var_info.ptr, *idx, &format!("{}.{}", var_name, field))
.unwrap();
let ptr = generate_address_ir(
env.context,
env.builder,
&full,
env.variables,
env.module,
env.struct_types,
env.struct_field_indices,
);

env.builder
.build_load(field_ptr, &format!("load_{}_{}", var_name, field))
.build_load(ptr, &format!("load_field_{}", field))
.unwrap()
.as_basic_value_enum()
}

Loading