Skip to content

Commit

Permalink
Introduce RefAssignment node, adjust codegen
Browse files Browse the repository at this point in the history
  • Loading branch information
volsa committed Jun 25, 2024
1 parent 9486255 commit 4d61e7e
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 32 deletions.
14 changes: 14 additions & 0 deletions compiler/plc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,7 @@ pub enum AstStatement {
// Assignments
Assignment(Assignment),
OutputAssignment(Assignment),
RefAssignment(Assignment),

CallStatement(CallStatement),

Expand Down Expand Up @@ -664,6 +665,9 @@ impl Debug for AstNode {
AstStatement::OutputAssignment(Assignment { left, right }) => {
f.debug_struct("OutputAssignment").field("left", left).field("right", right).finish()
}
AstStatement::RefAssignment(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 @@ -1322,6 +1326,16 @@ impl AstFactory {
)
}

// TODO: Merge this with create(_output)_assignment
pub fn create_ref_assignment(left: AstNode, right: AstNode, id: AstId) -> AstNode {
let location = left.location.span(&right.location);
AstNode::new(
AstStatement::RefAssignment(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
10 changes: 10 additions & 0 deletions compiler/plc_ast/src/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,15 @@ pub trait AstVisitor: Sized {
stmt.walk(self)
}

/// Visits an `RefAssignment` node.
/// Make sure to call `walk` on the `Assignment` node to visit its children.
/// # Arguments
/// * `stmt` - The unwraped, typed `Assignment` node to visit.
/// * `node` - The wrapped `AstNode` node to visit. Offers access to location information and AstId
fn visit_ref_assignment(&mut self, stmt: &Assignment, _node: &AstNode) {
stmt.walk(self)
}

/// Visits a `CallStatement` node.
/// Make sure to call `walk` on the `CallStatement` node to visit its children.
/// # Arguments
Expand Down Expand Up @@ -556,6 +565,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::RefAssignment(stmt) => visitor.visit_ref_assignment(stmt, node),
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
3 changes: 1 addition & 2 deletions src/codegen/generators/expression_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2507,14 +2507,13 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
/// - `access` the ReferenceAccess of the reference to generate
/// - `base` the "previous" segment of an optional qualified reference-access
/// - `original_expression` the original ast-statement used to report Diagnostics
fn generate_reference_expression(
pub(crate) fn generate_reference_expression(
&self,
access: &ReferenceAccess,
base: Option<&AstNode>,
original_expression: &AstNode,
) -> Result<ExpressionValue<'ink>, Diagnostic> {
match (access, base) {

// expressions like `base.member`, or just `member`
(ReferenceAccess::Member(member), base) => {
let base_value = base.map(|it| self.generate_expression_value(it)).transpose()?;
Expand Down
20 changes: 20 additions & 0 deletions src/codegen/generators/statement_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> {
AstStatement::Assignment(data, ..) => {
self.generate_assignment_statement(&data.left, &data.right)?;
}
AstStatement::RefAssignment(data, ..) => {
self.generate_ref_assignment(&data.left, &data.right)?;
}
AstStatement::ControlStatement(ctl_statement, ..) => {
self.generate_control_statement(ctl_statement)?
}
Expand Down Expand Up @@ -230,6 +233,23 @@ impl<'a, 'b> StatementCodeGenerator<'a, 'b> {
}
}

pub fn generate_ref_assignment(&self, left: &AstNode, right: &AstNode) -> Result<(), Diagnostic> {
let exp = self.create_expr_generator();
let AstStatement::ReferenceExpr(data) = &left.stmt else {
panic!("this needs a validation, but the lhs must always be a reference?")
};

let ref_builtin = self.index.get_builtin_function("REF").unwrap();
let left_pointer = {
let expr = exp.generate_reference_expression(&data.access, data.base.as_deref(), left)?;
expr.get_basic_value_enum().into_pointer_value()
};
let right_expr_value = ref_builtin.codegen(&exp, &[&right], SourceLocation::undefined()).unwrap();

self.llvm.builder.build_store(left_pointer, right_expr_value.get_basic_value_enum());
Ok(())
}

/// generates an assignment statement _left_ := _right_
///
/// `left_statement` the left side of the assignment
Expand Down
16 changes: 1 addition & 15 deletions src/parser/expressions_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,23 +223,9 @@ fn parse_leaf_expression(lexer: &mut ParseSession) -> AstNode {
lexer.advance();
AstFactory::create_output_assignment(statement, parse_range_statement(lexer), lexer.next_id())
}
// TODO: This is a good candidate for lowering (if we ever implement it)
KeywordReferenceAssignment => {
debug_assert!(
get_builtin("REF").is_some(),
"The REF builtin must exist for the REF= syntactic sugar"
);

lexer.advance();
let fn_arg = parse_range_statement(lexer);
let fn_loc = fn_arg.location.clone();
let fn_name = AstFactory::create_identifier("REF", &fn_loc, lexer.next_id());

AstFactory::create_assignment(
statement,
AstFactory::create_call_statement(fn_name, Some(fn_arg), lexer.next_id(), fn_loc),
lexer.next_id(),
)
AstFactory::create_ref_assignment(statement, parse_range_statement(lexer), lexer.next_id())
}
_ => statement,
},
Expand Down
19 changes: 6 additions & 13 deletions src/parser/tests/statement_parser_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ 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###"
[
Assignment {
ReferenceAssignment {
left: ReferenceExpr {
kind: Member(
Identifier {
Expand All @@ -277,20 +277,13 @@ fn reference_assignment_is_parsed() {
),
base: None,
},
right: CallStatement {
operator: Identifier {
name: "REF",
},
parameters: Some(
ReferenceExpr {
kind: Member(
Identifier {
name: "y",
},
),
base: None,
right: ReferenceExpr {
kind: Member(
Identifier {
name: "y",
},
),
base: None,
},
},
]
Expand Down
9 changes: 7 additions & 2 deletions src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1419,7 +1419,7 @@ impl<'i> TypeAnnotator<'i> {
AstStatement::RangeStatement(data, ..) => {
visit_all_statements!(self, ctx, &data.start, &data.end);
}
AstStatement::Assignment(data, ..) => {
AstStatement::Assignment(data, ..) | AstStatement::RefAssignment(data, ..) => {
self.visit_statement(&ctx.enter_control(), &data.right);
if let Some(lhs) = ctx.lhs {
//special context for left hand side
Expand Down Expand Up @@ -1749,7 +1749,12 @@ impl<'i> TypeAnnotator<'i> {
}

pub(crate) fn annotate_parameters(&mut self, p: &AstNode, type_name: &str) {
if !matches!(p.get_stmt(), AstStatement::Assignment(..) | AstStatement::OutputAssignment(..)) {
if !matches!(
p.get_stmt(),
AstStatement::Assignment(..)
| AstStatement::OutputAssignment(..)
| AstStatement::RefAssignment(..)
) {
if let Some(effective_member_type) = self.index.find_effective_type_by_name(type_name) {
//update the type hint
self.annotation_map
Expand Down

0 comments on commit 4d61e7e

Please sign in to comment.