Skip to content

Commit

Permalink
Initial commit w/ segfault 😎
Browse files Browse the repository at this point in the history
  • Loading branch information
volsa committed Jun 19, 2024
1 parent 45f487f commit 91f485f
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 10 deletions.
21 changes: 21 additions & 0 deletions compiler/plc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,11 @@ pub enum AstStatement {
Assignment(Assignment),
// OutputAssignment
OutputAssignment(Assignment),

// x REF= y
// XXX: Not a big fan of how Assignment, OutputAssignment and ReferenceAssignment are three different
// enums instead of one with a type / kind field distinguishing them
ReferenceAssignment(Assignment),
//Call Statement
CallStatement(CallStatement),
// Control Statements
Expand Down Expand Up @@ -661,6 +666,9 @@ impl Debug for AstNode {
AstStatement::OutputAssignment(Assignment { left, right }) => {
f.debug_struct("OutputAssignment").field("left", left).field("right", right).finish()
}
AstStatement::ReferenceAssignment(Assignment { left, right }) => {
f.debug_struct("ReferenceAssignment").field("left", left).field("right", right).finish()
}
AstStatement::CallStatement(CallStatement { operator, parameters }) => f
.debug_struct("CallStatement")
.field("operator", operator)
Expand Down Expand Up @@ -1311,6 +1319,19 @@ impl AstFactory {
)
}

// XXX: Deduplicate code here?
pub fn create_reference_assignment(left: AstNode, right: AstNode, id: AstId) -> AstNode {
let location = left.location.span(&right.location);
AstNode {
stmt: AstStatement::ReferenceAssignment(Assignment {
left: Box::new(left),
right: Box::new(right),
}),
id,
location,
}
}

pub fn create_member_reference(member: AstNode, base: Option<AstNode>, id: AstId) -> AstNode {
let location = base
.as_ref()
Expand Down
1 change: 1 addition & 0 deletions compiler/plc_ast/src/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ impl Walker for AstNode {
AstStatement::VlaRangeStatement => visitor.visit_vla_range_statement(node),
AstStatement::Assignment(stmt) => visitor.visit_assignment(stmt, node),
AstStatement::OutputAssignment(stmt) => visitor.visit_output_assignment(stmt, node),
AstStatement::ReferenceAssignment(stmt) => todo!(),
AstStatement::CallStatement(stmt) => visitor.visit_call_statement(stmt, node),
AstStatement::ControlStatement(stmt) => visitor.visit_control_statement(stmt, node),
AstStatement::CaseCondition(stmt) => visitor.visit_case_condition(stmt, node),
Expand Down
24 changes: 23 additions & 1 deletion src/codegen/generators/statement_generator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
use super::{
expression_generator::{to_i1, ExpressionCodeGenerator},
expression_generator::{to_i1, ExpressionCodeGenerator, ExpressionValue},
llvm::Llvm,
};
use crate::{
Expand Down Expand Up @@ -122,6 +122,9 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> {
AstStatement::Assignment(data, ..) => {
self.generate_assignment_statement(&data.left, &data.right)?;
}
AstStatement::ReferenceAssignment(data, ..) => {
self.generate_reference_assignment_statement(&data.left, &data.right)?;
}

AstStatement::ControlStatement(ctl_statement, ..) => {
self.generate_control_statement(ctl_statement)?
Expand Down Expand Up @@ -231,6 +234,25 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> {
}
}

// XXX: Replace Result with CodegenResult<T>?
pub fn generate_reference_assignment_statement(
&self,
left: &AstNode,
right: &AstNode,
) -> Result<(), Diagnostic> {
let exp_gen = self.create_expr_generator();

let left_type = exp_gen.get_type_hint_info_for(left)?;
let left_pvalue: PointerValue = exp_gen.generate_expression_value(left).and_then(|it| {
it.get_basic_value_enum()
.try_into()
.map_err(|err| Diagnostic::codegen_error(format!("{err:?}").as_str(), left.get_location()))
})?;

exp_gen.generate_store(left_pvalue, left_type, right)?;
Ok(())
}

/// generates an assignment statement _left_ := _right_
///
/// `left_statement` the left side of the assignment
Expand Down
32 changes: 32 additions & 0 deletions src/codegen/tests/statement_codegen_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,35 @@ fn floating_point_type_casting() {

insta::assert_snapshot!(result);
}

#[test]
fn reference_assignment() {
let result = codegen(
r#"
FUNCTION main
VAR
a : REF_TO DINT;
b : DINT;
END_VAR
a REF= b;
END_PROGRAM
"#,
);

insta::assert_snapshot!(result, @r###"
; ModuleID = 'main'
source_filename = "main"
define void @main() section "fn-$RUSTY$main:v" {
entry:
%a = alloca i32*, align 8
%b = alloca i32, align 4
store i32* null, i32** %a, align 8
store i32 0, i32* %b, align 4
%load_b = load i32, i32* %b, align 4
%0 = inttoptr i32 %load_b to i32*
store i32* %0, i32** %a, align 8
ret void
}
"###);
}
3 changes: 3 additions & 0 deletions src/lexer/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ pub enum Token {
#[token("=>")]
KeywordOutputAssignment,

#[token("REF=")]
KeywordReferenceAssignment,

#[token("(")]
KeywordParensOpen,

Expand Down
20 changes: 14 additions & 6 deletions src/parser/expressions_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,17 +213,25 @@ fn parse_leaf_expression(lexer: &mut ParseSession) -> AstNode {
};

match literal_parse_result {
Some(statement) => {
if lexer.token == KeywordAssignment {
Some(statement) => match lexer.token {
KeywordAssignment => {
lexer.advance();
AstFactory::create_assignment(statement, parse_range_statement(lexer), lexer.next_id())
} else if lexer.token == KeywordOutputAssignment {
}
KeywordOutputAssignment => {
lexer.advance();
AstFactory::create_output_assignment(statement, parse_range_statement(lexer), lexer.next_id())
} else {
statement
}
}
KeywordReferenceAssignment => {
lexer.advance();
AstFactory::create_reference_assignment(
statement,
parse_range_statement(lexer),
lexer.next_id(),
)
}
_ => statement,
},
None => {
let statement = AstFactory::create_empty_statement(
lexer.diagnostics.last().map_or(SourceLocation::undefined(), |d| d.get_location()),
Expand Down
29 changes: 28 additions & 1 deletion src/parser/tests/statement_parser_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
parser::tests::{empty_stmt, ref_to},
test_utils::tests::parse,
test_utils::tests::{parse, parse_and_preprocess},
typesystem::DINT_TYPE,
};
use insta::assert_snapshot;
Expand Down Expand Up @@ -262,3 +262,30 @@ fn empty_parameter_assignments_in_call_statement() {
let ast_string = format!("{:#?}", &result);
insta::assert_snapshot!(ast_string);
}

#[test]
fn reference_assignment_is_parsed() {
let result = &parse("PROGRAM main x REF= y END_PROGRAM").0.implementations[0];
insta::assert_debug_snapshot!(result.statements, @r###"
[
ReferenceAssignment {
left: ReferenceExpr {
kind: Member(
Identifier {
name: "x",
},
),
base: None,
},
right: ReferenceExpr {
kind: Member(
Identifier {
name: "y",
},
),
base: None,
},
},
]
"###)
}
5 changes: 3 additions & 2 deletions src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,8 @@ impl<'i> TypeAnnotator<'i> {
}
}
}
AstStatement::Assignment(Assignment { left, right }, ..) => {
AstStatement::ReferenceAssignment(Assignment { left, right }, ..)
| AstStatement::Assignment(Assignment { left, right }, ..) => {
// struct initialization (left := right)
// find out left's type and update a type hint for right
if let (
Expand Down Expand Up @@ -1416,7 +1417,7 @@ impl<'i> TypeAnnotator<'i> {
AstStatement::RangeStatement(data, ..) => {
visit_all_statements!(self, ctx, &data.start, &data.end);
}
AstStatement::Assignment(data, ..) => {
AstStatement::ReferenceAssignment(data, ..) | AstStatement::Assignment(data, ..) => {
self.visit_statement(&ctx.enter_control(), &data.right);
if let Some(lhs) = ctx.lhs {
//special context for left hand side
Expand Down
18 changes: 18 additions & 0 deletions tests/correctness/pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,21 @@ fn value_behind_function_block_pointer_is_assigned_to_correctly() {
assert!(!maintype.a);
assert!(maintype.b);
}

#[test]
fn reference_assignment() {
let function = r"
FUNCTION main : DINT
VAR
a : REF_TO DINT;
b : DINT := 5;
END_VAR
a REF= b;
main := a^;
END_FUNCTION
";

let res: i32 = compile_and_run(function.to_string(), &mut MainType::default());
assert_eq!(5, res);
}

0 comments on commit 91f485f

Please sign in to comment.