Skip to content

Commit

Permalink
Added pointer advancement operation.
Browse files Browse the repository at this point in the history
Still need to fix bug from earlier commit.
  • Loading branch information
SLiV9 committed Jun 22, 2024
1 parent 3abee2c commit b76d435
Show file tree
Hide file tree
Showing 24 changed files with 151 additions and 51 deletions.
20 changes: 10 additions & 10 deletions examples/format_slice_implementation.pn
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import "vendor:libc/stdlib.pn";

// Of course print_slice needs to be generic over the element type (here i32).
fn print_slice(data: []i32)
Expand All @@ -9,7 +8,7 @@ fn print_slice(data: []i32)
goto end;
}

var buf: &[...]char8 = 0x0;
var buf: &[..]char8 = 0x0;
var buflen: usize = 0;

// Do a dry run followed by a real run.
Expand All @@ -25,9 +24,9 @@ fn print_slice(data: []i32)
{
&fmt = &fmt0;
}
var head: &[...]char8 = add_offset!(&buf, real * writlen);
var head: &[..]char8 = &buf .. real * writlen;
var len: usize = buflen - real * writlen;
writlen = writlen + __snprintf!(&head, len, fmt, data[i]);
writlen = writlen + snprintf(&head, len, fmt, data[i]);

if i == |data|
{
Expand All @@ -39,28 +38,29 @@ fn print_slice(data: []i32)
}

terminator:
var head: &[...]char8 = add_offset!(&buf, real * writlen);
var head: &[..]char8 = &buf .. real * writlen;
var len: usize = buflen - real * writlen;
writlen = writlen + __snprintf!(&head, len, "]\0");
writlen = writlen + snprintf(&head, len, "]\0", 0);

if real > 0
{
goto print;
}

buflen = writlen;
&buf = cast malloc(buflen);
&buf = alloca(buflen);
real = 1;
loop;
}

print:
print!(buf, "\n");

free(cast &buf);

end:
}

// This is not the correct signature because variadics.
// builtin fn __snprintf(buf: &[...]char8, buflen: usize, fmt: [...]char8, value: i32) -> usize;
extern fn snprintf(buf: &[]char8, buflen: usize, fmt: []char8, value: i32) -> usize;

// This is not a real function.
extern fn alloca(buflen: usize) -> &[]char8;
2 changes: 1 addition & 1 deletion examples/libc/call_malloc.pn
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import "vendor:libc/stdlib.pn";
fn main() -> u8
{
var result = -1;
var ptr: &[...]u8 = malloc(10);
var ptr: &[..]u8 = malloc(10);
if &ptr == 0x0
goto after_free;
var i: usize = 0;
Expand Down
2 changes: 1 addition & 1 deletion examples/libc/call_malloc_array_of_i64.pn
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn main() -> u8
done:
result = ptr[5];
error_occurred:
free(cast &ptr as &[...]u8);
free(cast &ptr as &[..]u8);
after_free:
return: result as u8
}
2 changes: 1 addition & 1 deletion examples/libc/call_strrchr.pn
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ fn main() -> i32
{
var buffer = "Hallo\0";
var m: char8 = 108;
var ptr_into_buffer: &[...]char8 = strrchr(buffer, m);
var ptr_into_buffer: &[..]char8 = strrchr(buffer, m);
ptr_into_buffer[0] = 109;
var diff = strcmp(buffer, "Halmo\0");
return: diff
Expand Down
2 changes: 1 addition & 1 deletion penne.todo
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Functionality:
✔ Think about (disallowing) cast between pointer and integer @done (2022-12-24 18:39)
The only use case I care about is debugging and maybe offsets.
✔ printf()/format() needs a %p @done (2023-11-04 20:25)
builtin function (&T, usize) -> &T
builtin function (&T, usize) -> &T @done (2024-06-22 20:10)
Not needed if you can cast &[]u8 to &T and &[]T.
No, it is needed for writing to buffers at dynamic offsets.
✔ Cast between pointer types (specifically from &T to &[]u8 and back) @done (2023-08-05 17:40)
Expand Down
1 change: 1 addition & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ pub enum BinaryOp
BitwiseXor,
ShiftLeft,
ShiftRight,
AdvancePointer,
}

#[must_use]
Expand Down
2 changes: 1 addition & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2717,7 +2717,7 @@ fn show_type_inner(value_type: &ValueType) -> String
}
ValueType::EndlessArray { element_type } =>
{
format!("[...]{}", show_type_inner(element_type))
format!("[..]{}", show_type_inner(element_type))
}
ValueType::Arraylike { element_type } =>
{
Expand Down
15 changes: 14 additions & 1 deletion src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,19 @@ impl Generatable for Expression
unsafe {
LLVMBuildLShr(llvm.builder, left, right, cstr!(""))
},
BinaryOp::AdvancePointer =>
{
let mut indices = vec![right];
unsafe {
LLVMBuildGEP(
llvm.builder,
left,
indices.as_mut_ptr(),
indices.len() as u32,
cstr!(""),
)
}
}
};
Ok(result)
}
Expand Down Expand Up @@ -2748,7 +2761,7 @@ fn format_endless(
};
if let Some(address) = cstr_address
{
// Assume that [...]char8 is nul terminated.
// Assume that [..]char8 is nul terminated.
let nul_terminated_cstr = unsafe { address };
buffer.add_specifier("%s");
buffer.insert(nul_terminated_cstr);
Expand Down
12 changes: 11 additions & 1 deletion src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub enum Token
ShiftRight, // >>
Arrow, // ->
PipeForType, // |:
Dots, // ..

// Keywords.
Fn,
Expand Down Expand Up @@ -248,7 +249,16 @@ fn lex_line(
'%' => Ok(Token::Modulo),
':' => Ok(Token::Colon),
';' => Ok(Token::Semicolon),
'.' => Ok(Token::Dot),
'.' => match iter.peek()
{
Some((_, '.')) =>
{
iter.next();
source_offset_end += 1;
Ok(Token::Dots)
}
_ => Ok(Token::Dot),
},
',' => Ok(Token::Comma),
'=' => match iter.peek()
{
Expand Down
28 changes: 23 additions & 5 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -770,11 +770,9 @@ fn parse_inner_type(tokens: &mut Tokens) -> Result<ValueType, Error>
element_type: Box::new(element_type),
})
}
Some(Token::Dot) =>
Some(Token::Dots) =>
{
tokens.pop_front();
consume(Token::Dot, tokens)?;
consume(Token::Dot, tokens)?;
consume(Token::BracketRight, tokens)?;
let element_type = parse_inner_type(tokens)?;
Ok(ValueType::EndlessArray {
Expand Down Expand Up @@ -1647,10 +1645,30 @@ fn parse_primary_expression(tokens: &mut Tokens) -> Result<Expression, Error>
Token::Ampersand =>
{
let reference = parse_addressed_reference(location, tokens)?;
Ok(Expression::Deref {
let pointer = Expression::Deref {
reference,
deref_type: None,
})
};
if let Some(Token::Dots) = peek(tokens)
{
tokens.pop_front();
let location_of_op = tokens.last_location.clone();

let offset = parse_expression(tokens)?;
let location =
pointer.location().clone().combined_with(offset.location());
Ok(Expression::Binary {
op: BinaryOp::AdvancePointer,
left: Box::new(pointer),
right: Box::new(offset),
location,
location_of_op,
})
}
else
{
Ok(pointer)
}
}
Token::BracketLeft =>
{
Expand Down
3 changes: 2 additions & 1 deletion src/rebuilder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -851,7 +851,7 @@ where
}
ValueType::EndlessArray { element_type } =>
{
Ok(format!("[...]{}", element_type.rebuild(indentation)?))
Ok(format!("[..]{}", element_type.rebuild(indentation)?))
}
ValueType::Arraylike { element_type } =>
{
Expand Down Expand Up @@ -1023,6 +1023,7 @@ impl std::fmt::Display for BinaryOp
BinaryOp::BitwiseXor => write!(f, "^"),
BinaryOp::ShiftLeft => write!(f, "<<"),
BinaryOp::ShiftRight => write!(f, ">>"),
BinaryOp::AdvancePointer => write!(f, ".."),
}
}
}
Expand Down
36 changes: 26 additions & 10 deletions src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,6 +1075,20 @@ impl ComparisonOp
}
}

fn get_type_of_operand(
operand: &Expression,
) -> Result<common::ValueType, Errors>
{
match operand.value_type()
{
Some(Ok(vt)) => Ok(vt),
Some(Err(poison)) => Err(poison)?,
None => Err(Error::AmbiguousType {
location: operand.location().clone(),
})?,
}
}

fn match_type_of_operands(
left: &Expression,
right: &Expression,
Expand Down Expand Up @@ -1123,7 +1137,14 @@ fn resolve_binary_op_type(
location_of_op: &Location,
) -> Result<resolved::ValueType, Errors>
{
let vt = match_type_of_operands(left, right, location_of_op)?;
let vt = if op == BinaryOp::AdvancePointer
{
get_type_of_operand(left)?
}
else
{
match_type_of_operands(left, right, location_of_op)?
};
analyze_operand_type(vt, op.valid_types(), location_of_op, left.location())
}

Expand Down Expand Up @@ -1155,6 +1176,8 @@ const VALID_TYPES_FOR_BITSHIFT: &[OperandValueType] = &[
OperandValueType::ValueType(ValueType::Uint64),
OperandValueType::ValueType(ValueType::Uint128),
];
const VALID_TYPES_FOR_POINTER: &[OperandValueType] =
&[OperandValueType::Pointer];

impl BinaryOp
{
Expand All @@ -1172,6 +1195,7 @@ impl BinaryOp
BinaryOp::BitwiseXor => VALID_TYPES_FOR_BITWISE,
BinaryOp::ShiftLeft => VALID_TYPES_FOR_BITSHIFT,
BinaryOp::ShiftRight => VALID_TYPES_FOR_BITSHIFT,
BinaryOp::AdvancePointer => VALID_TYPES_FOR_POINTER,
}
}
}
Expand All @@ -1182,15 +1206,7 @@ fn resolve_unary_op_type(
location_of_op: &Location,
) -> Result<resolved::ValueType, Errors>
{
let vt = match operand.value_type()
{
Some(Ok(vt)) => vt,
Some(Err(poison)) => Err(poison)?,
None => Err(Error::AmbiguousType {
location: operand.location().clone(),
})?,
};

let vt = get_type_of_operand(operand)?;
analyze_operand_type(
vt,
op.valid_types(),
Expand Down
26 changes: 23 additions & 3 deletions src/typer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1573,6 +1573,27 @@ impl Analyzable for Expression
{
match self
{
Expression::Binary {
op: op @ BinaryOp::AdvancePointer,
left,
right,
location,
location_of_op,
} =>
{
let contextual_type = typer.contextual_type.take();
typer.contextual_type = right.value_type().or(contextual_type);
let left = left.analyze(typer);
typer.contextual_type = Some(Ok(ValueType::Usize));
let right = right.analyze(typer);
Expression::Binary {
op,
left: Box::new(left),
right: Box::new(right),
location,
location_of_op,
}
}
Expression::Binary {
op,
left,
Expand All @@ -1582,10 +1603,9 @@ impl Analyzable for Expression
} =>
{
let contextual_type = typer.contextual_type.take();
typer.contextual_type =
right.value_type().or_else(|| contextual_type.clone());
typer.contextual_type = right.value_type().or(contextual_type);
let left = left.analyze(typer);
typer.contextual_type = left.value_type().or(contextual_type);
typer.contextual_type = left.value_type();
let right = right.analyze(typer);
Expression::Binary {
op,
Expand Down
9 changes: 9 additions & 0 deletions tests/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,15 @@ fn execute_pointer_stability_struct() -> Result<(), anyhow::Error>
Ok(())
}

#[test]
fn execute_pointer_arithmetic() -> Result<(), anyhow::Error>
{
let result =
execute_calculation("tests/samples/valid/pointer_arithmetic.pn")?;
assert_eq!(result, 200);
Ok(())
}

#[test]
fn execute_empty_array() -> Result<(), anyhow::Error>
{
Expand Down
2 changes: 1 addition & 1 deletion tests/samples/invalid/array_of_endless_array.pn
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

fn foo()
{
var y: [10][...]i32;
var y: [10][..]i32;
}
2 changes: 1 addition & 1 deletion tests/samples/invalid/endless_array_as_constant.pn
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

const A: [...]u8 = "Hello\0";
const A: [..]u8 = "Hello\0";
4 changes: 2 additions & 2 deletions tests/samples/invalid/endless_array_as_member.pn
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
struct SmallVec
{
legal: &[...]i32,
illegal_because_infinite_size: [...]i32,
legal: &[..]i32,
illegal_because_infinite_size: [..]i32,
}
4 changes: 2 additions & 2 deletions tests/samples/invalid/endless_array_as_variable.pn
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
fn foo()
{
var legal: &[...]i32;
var illegal_because_infinite_size: [...]i32;
var legal: &[..]i32;
var illegal_because_infinite_size: [..]i32;
}
2 changes: 1 addition & 1 deletion tests/samples/invalid/pointer_to_coerced.pn
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ fn all_uses_invalid()
{
var five_zeroes: [5]i32 = [0, 0, 0, 0, 0];
var ptr_to_five_zeroes: &[5]i32 = &five_zeroes;
// Invalid because use_ptr_to_ptr_to_endless might assign &[...]i32 to it.
// Invalid because use_ptr_to_ptr_to_endless might assign &[..]i32 to it.
use_ptr_to_ptr_to_endless(&&ptr_to_five_zeroes);

var ptr_to_ptr_to_five_zeroes: &&[5]i32 = &&ptr_to_five_zeroes;
Expand Down
Loading

0 comments on commit b76d435

Please sign in to comment.