Skip to content

Commit 8d24e01

Browse files
committed
feat: type casting on pointers
1 parent 15331ae commit 8d24e01

File tree

5 files changed

+255
-27
lines changed

5 files changed

+255
-27
lines changed

.vscode/launch.json

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,31 @@
44
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
55
"version": "0.2.0",
66
"configurations": [
7-
{
8-
"type": "codelldb",
9-
"request": "launch",
10-
"name": "Debug codelldb standard_lib",
11-
"cargo": {
7+
{
8+
"type": "codelldb",
9+
"request": "launch",
10+
"name": "Debug codelldb standard_lib",
11+
"cargo": {
12+
"args": [
13+
"build",
14+
"--bin=plc",
15+
"--package=plc_driver"
16+
],
17+
"filter": {
18+
"name": "plc",
19+
"kind": "bin"
20+
}
21+
},
22+
"program": "target/debug/plc",
1223
"args": [
13-
"build",
14-
"--bin=plc",
15-
"--package=plc_driver"
24+
"libs/stdlib/iec61131-st/*.st"
1625
],
17-
"filter": {
18-
"name": "plc",
19-
"kind": "bin"
20-
}
21-
},
22-
"program": "target/debug/plc",
23-
"args": ["libs/stdlib/iec61131-st/*.st"],
24-
"cwd": "${workspaceFolder}",
25-
"env": {
26-
"RUST_LOG": "rusty"
26+
"cwd": "${workspaceFolder}",
27+
"env": {
28+
"RUST_LOG": "rusty"
29+
},
30+
"terminal": "integrated"
2731
},
28-
"terminal": "integrated"
29-
},
3032
{
3133
"type": "codelldb",
3234
"request": "launch",
@@ -43,7 +45,11 @@
4345
}
4446
},
4547
"program": "target/debug/plc",
46-
"args": ["target/demo.st", "-g", "-c"],
48+
"args": [
49+
"target/demo.st",
50+
"-g",
51+
"-c"
52+
],
4753
"cwd": "${workspaceFolder}",
4854
"env": {
4955
"RUST_LOG": "rusty"
@@ -67,7 +73,8 @@
6773
},
6874
"args": [
6975
"target/demo.st",
70-
"tests/lit/util/printf.pli"
76+
"tests/lit/util/printf.pli",
77+
"-j=1"
7178
],
7279
"cwd": "${workspaceFolder}",
7380
"env": {
@@ -107,7 +114,6 @@
107114
"cwd": "${workspaceFolder}",
108115
"program": "target/demo",
109116
"terminal": "integrated"
110-
111117
}
112118
]
113-
}
119+
}

src/codegen/generators/expression_generator.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
232232
Ok(ExpressionValue::LValue(this_value))
233233
}
234234
AstStatement::ReferenceExpr(data) => {
235+
dbg!(&data, &expression);
235236
let res =
236237
self.generate_reference_expression(&data.access, data.base.as_deref(), expression)?;
237238
let val = match res {
@@ -614,6 +615,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
614615
}
615616

616617
// Generate the function pointer value (only for non-FB cases)
618+
dbg!(&base);
617619
let function_pointer_value = self.generate_expression_value(base)?;
618620
let function_pointer = match function_pointer_value {
619621
ExpressionValue::LValue(ptr) => {
@@ -2865,13 +2867,46 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
28652867
}
28662868

28672869
// `INT#target` (INT = base)
2868-
(ReferenceAccess::Cast(target), Some(_base)) => {
2870+
(ReferenceAccess::Cast(target), Some(base)) => {
2871+
// Check if this is a simple identifier cast or literal cast (use original logic)
28692872
if target.as_ref().is_identifier() {
28702873
let mr =
28712874
AstFactory::create_member_reference(target.as_ref().clone(), None, target.get_id());
28722875
self.generate_expression_value(&mr)
2873-
} else {
2876+
} else if target.as_ref().is_literal() {
2877+
// Handle literal casts with original logic
28742878
self.generate_expression_value(target.as_ref())
2879+
} else {
2880+
// TODO: We sohuld probably check if the parget is a pointer
2881+
2882+
// For complex expressions like void pointer casts, use bitcast logic
2883+
let base_type = self.annotations.get_type_or_void(base, self.index);
2884+
let base_type_name = base_type.get_name();
2885+
2886+
// Generate the value we're casting (the target)
2887+
let target_value = self.generate_expression_value(target.as_ref())?;
2888+
2889+
// Get the LLVM type for the cast target
2890+
let target_llvm_type = self.llvm_index.get_associated_type(base_type_name)
2891+
.map(|t| t.ptr_type(AddressSpace::from(0)))
2892+
.unwrap_or_else(|_| self.llvm.context.i8_type().ptr_type(AddressSpace::from(0)));
2893+
2894+
// Perform the bitcast
2895+
let cast_value = match target_value {
2896+
ExpressionValue::LValue(ptr) => {
2897+
// Load the pointer value and cast it
2898+
let loaded = self.llvm.load_pointer(&ptr, "cast_load");
2899+
let cast_ptr = self.llvm.builder.build_bitcast(loaded, target_llvm_type, "cast");
2900+
ExpressionValue::RValue(cast_ptr)
2901+
}
2902+
ExpressionValue::RValue(val) => {
2903+
// Direct cast of the value
2904+
let cast_ptr = self.llvm.builder.build_bitcast(val, target_llvm_type, "cast");
2905+
ExpressionValue::RValue(cast_ptr)
2906+
}
2907+
};
2908+
2909+
Ok(cast_value)
28752910
}
28762911
}
28772912

src/resolver.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2076,6 +2076,11 @@ impl<'i> TypeAnnotator<'i> {
20762076
.iter()
20772077
.find_map(|scope| scope.resolve_name(name, qualifier, self.index, ctx, &self.scopes)),
20782078

2079+
AstStatement::ReferenceExpr(_) => {
2080+
self.visit_statement(ctx, reference);
2081+
self.annotation_map.get(reference).cloned() // XXX: This looks wrong, but for now does the job
2082+
}
2083+
20792084
AstStatement::Literal(..) => {
20802085
self.visit_statement_literals(ctx, reference);
20812086
let literal_annotation = self.annotation_map.get(reference).cloned(); // return what we just annotated //TODO not elegant, we need to clone
@@ -2105,6 +2110,7 @@ impl<'i> TypeAnnotator<'i> {
21052110
strategy.resolve_name(&name, qualifier, self.index, ctx, &self.scopes)
21062111
})
21072112
}
2113+
AstStatement::ParenExpression(expr) => self.resolve_reference_expression(expr, qualifier, ctx),
21082114
_ => None,
21092115
}
21102116
}

src/resolver/tests/function_pointer_tests.rs

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use plc_ast::{ast::AstStatement, provider::IdProvider};
1+
use plc_ast::{
2+
ast::{AstStatement, ReferenceAccess, ReferenceExpr},
3+
provider::IdProvider,
4+
};
25

36
use crate::{
47
resolver::{AnnotationMap, TypeAnnotator},
@@ -92,3 +95,153 @@ fn function_pointer_definition() {
9295
insta::assert_debug_snapshot!(annotations.get_hint(&call.operator), @"None");
9396
}
9497
}
98+
99+
#[test]
100+
fn void_pointer_casting() {
101+
let id_provider = IdProvider::default();
102+
let (unit, index) = index_with_ids(
103+
r"
104+
VAR_GLOBAL
105+
vtable_FbA_instance: vtable_FbA;
106+
END_VAR
107+
108+
TYPE vtable_FbA: STRUCT
109+
foo: POINTER TO FbA.foo := ADR(FbA.foo);
110+
END_STRUCT END_TYPE
111+
112+
FUNCTION_BLOCK FbA
113+
VAR
114+
__vtable: POINTER TO __VOID;
115+
END_VAR
116+
117+
METHOD foo
118+
END_METHOD
119+
END_FUNCTION_BLOCK
120+
121+
122+
FUNCTION main
123+
VAR
124+
instanceFbA: FbA;
125+
END_VAR
126+
127+
vtable_FbA#(instanceFbA.__vtable);
128+
vtable_FbA#(instanceFbA.__vtable).foo^(instanceFbA);
129+
END_FUNCTION
130+
",
131+
id_provider.clone(),
132+
);
133+
134+
let (annotations, ..) = TypeAnnotator::visit_unit(&index, &unit, id_provider);
135+
{
136+
let node = &unit.implementations.iter().find(|imp| imp.name == "main").unwrap().statements[0];
137+
138+
// vtable_FbA#(instanceFbA.__vtable)
139+
// ^^^^^^^^^^^^^^^^^^^^
140+
let AstStatement::ReferenceExpr(ReferenceExpr { access: ReferenceAccess::Cast(target), .. }) =
141+
node.get_stmt()
142+
else {
143+
unreachable!();
144+
};
145+
146+
insta::assert_debug_snapshot!(annotations.get(target), @r#"
147+
Some(
148+
Variable {
149+
resulting_type: "__FbA___vtable",
150+
qualified_name: "FbA.__vtable",
151+
constant: false,
152+
argument_type: ByVal(
153+
Local,
154+
),
155+
auto_deref: None,
156+
},
157+
)
158+
"#);
159+
insta::assert_debug_snapshot!(annotations.get_hint(target), @"None");
160+
161+
// vtable_FbA#(instanceFbA.__vtable)
162+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
163+
insta::assert_debug_snapshot!(annotations.get(node), @r#"
164+
Some(
165+
Value {
166+
resulting_type: "vtable_FbA",
167+
},
168+
)
169+
"#);
170+
insta::assert_debug_snapshot!(annotations.get_hint(node), @"None");
171+
}
172+
173+
{
174+
let node = &unit.implementations.iter().find(|imp| imp.name == "main").unwrap().statements[1];
175+
176+
// vtable_FbA#(instanceFbA.__vtable).foo^(instanceFbA);
177+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
178+
let AstStatement::CallStatement(call) = node.get_stmt() else {
179+
unreachable!();
180+
};
181+
182+
insta::assert_debug_snapshot!(annotations.get(&call.operator), @r#"
183+
Some(
184+
Value {
185+
resulting_type: "__vtable_FbA_foo",
186+
},
187+
)
188+
"#);
189+
insta::assert_debug_snapshot!(annotations.get_hint(&call.operator), @"None");
190+
}
191+
}
192+
193+
#[test]
194+
fn demo() {
195+
let id_provider = IdProvider::default();
196+
let (unit, index) = index_with_ids(
197+
r"
198+
VAR_GLOBAL
199+
vtable_FbA_instance: vtable_FbA;
200+
END_VAR
201+
202+
TYPE vtable_FbA: STRUCT
203+
foo: POINTER TO FbA.foo := ADR(FbA.foo);
204+
END_STRUCT END_TYPE
205+
206+
FUNCTION_BLOCK FbA
207+
VAR
208+
__vtable: POINTER TO vtable_FbA;
209+
END_VAR
210+
211+
METHOD foo
212+
END_METHOD
213+
END_FUNCTION_BLOCK
214+
215+
216+
FUNCTION main
217+
VAR
218+
instanceFbA: FbA;
219+
END_VAR
220+
221+
instanceFbA.__vtable^.foo^(instanceFbA);
222+
END_FUNCTION
223+
",
224+
id_provider.clone(),
225+
);
226+
227+
let (annotations, ..) = TypeAnnotator::visit_unit(&index, &unit, id_provider);
228+
229+
{
230+
let node = &unit.implementations.iter().find(|imp| imp.name == "main").unwrap().statements[0];
231+
232+
// instanceFbA.__vtable.foo^(instanceFbA);
233+
// ^^^^^^^^^^^^^^^^^^^^^^^^^
234+
let AstStatement::CallStatement(call) = node.get_stmt() else {
235+
unreachable!();
236+
};
237+
238+
insta::assert_debug_snapshot!(annotations.get(&call.operator), @r#"
239+
Some(
240+
Value {
241+
resulting_type: "__vtable_FbA_foo",
242+
},
243+
)
244+
"#);
245+
insta::assert_debug_snapshot!(annotations.get_hint(&call.operator), @"None");
246+
}
247+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: (%COMPILE %s && %RUN) | %CHECK %s
2+
3+
VAR_GLOBAL
4+
vtable_FbA_instance: vtable_FbA;
5+
END_VAR
6+
7+
TYPE vtable_FbA: STRUCT
8+
foo: POINTER TO FbA.foo := ADR(FbA.foo);
9+
END_STRUCT END_TYPE
10+
11+
FUNCTION_BLOCK FbA
12+
VAR
13+
__vtable: POINTER TO __VOID := ADR(vtable_FbA_instance);
14+
END_VAR
15+
16+
METHOD foo
17+
printf('Hello from FbA::foo$N');
18+
END_METHOD
19+
END_FUNCTION_BLOCK
20+
21+
22+
FUNCTION main
23+
VAR
24+
instanceFbA: FbA;
25+
END_VAR
26+
27+
vtable_FbA#(instanceFbA.__vtable).foo^(instanceFbA); // CHECK: Hello from FbA::foo
28+
END_FUNCTION

0 commit comments

Comments
 (0)