Skip to content

Commit 599da5a

Browse files
committed
feat: type casting on pointers
1 parent 15331ae commit 599da5a

13 files changed

+424
-26
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: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2866,12 +2866,33 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
28662866

28672867
// `INT#target` (INT = base)
28682868
(ReferenceAccess::Cast(target), Some(_base)) => {
2869+
// Check if this is a simple identifier cast or literal cast (use original logic)
28692870
if target.as_ref().is_identifier() {
28702871
let mr =
28712872
AstFactory::create_member_reference(target.as_ref().clone(), None, target.get_id());
28722873
self.generate_expression_value(&mr)
2873-
} else {
2874+
} else if target.as_ref().is_literal() {
2875+
// Handle literal casts with original logic
28742876
self.generate_expression_value(target.as_ref())
2877+
} else {
2878+
// Otherwise just bitcast the target to the given type
2879+
let base_type = self.annotations.get_type_or_void(_base, self.index);
2880+
let base_type_name = base_type.get_name();
2881+
2882+
// Generate the value we're casting
2883+
let target_value = self.generate_expression_value(target.as_ref())?;
2884+
2885+
// Get the LLVM type for the cast target
2886+
let target_llvm_type = self.llvm_index.get_associated_type(base_type_name)
2887+
.map(|t| t.ptr_type(AddressSpace::from(0)))
2888+
.unwrap_or_else(|_| self.llvm.context.i8_type().ptr_type(AddressSpace::from(0)));
2889+
2890+
// Perform the bitcast
2891+
let basic_value = target_value.get_basic_value_enum();
2892+
let cast_ptr = self.llvm.builder.build_bitcast(basic_value, target_llvm_type, "cast");
2893+
let cast_value = ExpressionValue::RValue(cast_ptr);
2894+
2895+
Ok(cast_value)
28752896
}
28762897
}
28772898

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: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// RUN: (%COMPILE %s && %RUN) | %CHECK %s
2+
3+
TYPE UserDefinedVT_FbA: STRUCT
4+
increaseStateByOne: POINTER TO FbA.increaseStateByOne := ADR(FbA.increaseStateByOne);
5+
increaseStateByArg: POINTER TO FbA.increaseStateByArg := ADR(FbA.increaseStateByArg);
6+
END_STRUCT
7+
END_TYPE
8+
9+
VAR_GLOBAL
10+
UserDefinedVT_FbA_instance: UserDefinedVT_FbA;
11+
END_VAR
12+
13+
FUNCTION_BLOCK FbA
14+
VAR
15+
vt: POINTER TO __VOID := ADR(UserDefinedVT_FbA_instance);
16+
localState: DINT := 5;
17+
END_VAR
18+
19+
METHOD increaseStateByOne: DINT
20+
localState := localState + 1;
21+
printf('FbA::increaseStateByOne: localState = %d$N', localState);
22+
END_METHOD
23+
24+
METHOD increaseStateByArg: DINT
25+
VAR_INPUT
26+
in: DINT;
27+
END_VAR
28+
29+
localState := localState + in;
30+
printf('FbA::increaseStateByArg: localState = %d$N', localState);
31+
END_METHOD
32+
END_FUNCTION_BLOCK
33+
34+
FUNCTION main
35+
VAR
36+
instanceFbA: FbA;
37+
refInstanceFbA: POINTER TO FbA := ADR(instanceFbA);
38+
END_VAR
39+
40+
UserDefinedVT_FbA#(refInstanceFbA^.vt^).increaseStateByOne^(refInstanceFbA^); // CHECK: FbA::increaseStateByOne: localState = 6
41+
UserDefinedVT_FbA#(refInstanceFbA^.vt^).increaseStateByArg^(refInstanceFbA^, 4); // CHECK: FbA::increaseStateByArg: localState = 10
42+
END_FUNCTION

0 commit comments

Comments
 (0)