Skip to content

Commit

Permalink
Issue 357 codegen fails if datatype and function have the same name (#…
Browse files Browse the repository at this point in the history
…384)

* added pou_types to TypeIndex, visitor registers POUs to pou_types (#357)

* added find_pou_type/find_effective_pou_type methodes in index, visitor registers actions in pou_types, fix index_tests (#357)

* resolver first search in types if none search in pou_types (#357)

* variable_validator data_type_is_fb_or_class_instance only search in pou_types (#357)

* added pou_type_associations to llvm_index (#357)

* index find_type() try find_pou_type() if cannot find any (#357)

* llvm_index find_associated_type() search for pou_types if cannot find type (#357)

* create and generate pou_types (#357)

* generate function with same name as return type (#357)
  • Loading branch information
99NIMI committed Nov 30, 2021
1 parent 573ce0e commit 901304e
Show file tree
Hide file tree
Showing 12 changed files with 331 additions and 24 deletions.
73 changes: 56 additions & 17 deletions src/codegen/generators/data_type_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ use std::convert::TryInto;
use crate::ast::SourceRange;
use crate::index::{Index, VariableIndexEntry, VariableType};
use crate::resolver::AnnotationMap;
use crate::typesystem::{Dimension, StringEncoding};
use crate::{ast::AstStatement, diagnostics::Diagnostic, typesystem::DataTypeInformation};
use crate::typesystem::{Dimension, StringEncoding, StructSource};
use crate::Diagnostic;
use crate::{ast::AstStatement, typesystem::DataTypeInformation};
use crate::{
codegen::{
llvm_index::LlvmTypedIndex,
llvm_typesystem::{get_llvm_float_type, get_llvm_int_type},
},
typesystem::DataType,
};
use inkwell::values::BasicValue;
use inkwell::{
types::{ArrayType, BasicType, BasicTypeEnum},
values::BasicValueEnum,
values::{BasicValue, BasicValueEnum},
AddressSpace,
};

Expand Down Expand Up @@ -55,6 +55,7 @@ pub fn generate_data_types<'ink>(
};

let types = generator.index.get_types();
let pou_types = generator.index.get_pou_types();

// first create all STUBs for struct types (empty structs)
// and associate them in the llvm index
Expand All @@ -68,11 +69,26 @@ pub fn generate_data_types<'ink>(
.associate_type(name, llvm.create_struct_stub(struct_name).into())?;
}
}
// pou_types will always be struct
for (name, user_type) in pou_types {
if let DataTypeInformation::Struct {
name: struct_name, ..
} = user_type.get_type_information()
{
generator
.types_index
.associate_pou_type(name, llvm.create_struct_stub(struct_name).into())?;
}
}
// now create all other types (enum's, arrays, etc.)
for (name, user_type) in types {
let gen_type = generator.create_type(name, user_type)?;
generator.types_index.associate_type(name, gen_type)?
}
for (name, user_type) in pou_types {
let gen_type = generator.create_type(name, user_type)?;
generator.types_index.associate_pou_type(name, gen_type)?
}

// now since all types should be available in the llvm index, we can think about constructing and associating
// initial values for the types
Expand All @@ -84,6 +100,14 @@ pub fn generate_data_types<'ink>(
.associate_initial_value(name, init_value)?;
}
}
for (name, user_type) in pou_types {
generator.expand_opaque_types(user_type)?;
if let Some(init_value) = generator.generate_initial_value(user_type)? {
generator
.types_index
.associate_initial_value(name, init_value)?;
}
}

Ok(generator.types_index)
}
Expand All @@ -92,7 +116,7 @@ impl<'ink, 'b> DataTypeGenerator<'ink, 'b> {
/// generates the members of an opaque struct and associates its initial values
fn expand_opaque_types(&mut self, data_type: &DataType) -> Result<(), Diagnostic> {
let information = data_type.get_type_information();
if let DataTypeInformation::Struct { .. } = information {
if let DataTypeInformation::Struct { source, .. } = information {
let members = self
.index
.get_container_members(data_type.get_name())
Expand All @@ -101,10 +125,15 @@ impl<'ink, 'b> DataTypeGenerator<'ink, 'b> {
.map(|m| self.types_index.get_associated_type(m.get_type_name()))
.collect::<Result<Vec<BasicTypeEnum>, Diagnostic>>()?;

let struct_type = self
.types_index
.get_associated_type(data_type.get_name())
.map(BasicTypeEnum::into_struct_type)?;
let struct_type = match source {
StructSource::Pou(..) => self
.types_index
.get_associated_pou_type(data_type.get_name()),
StructSource::OriginalDeclaration => {
self.types_index.get_associated_type(data_type.get_name())
}
}
.map(BasicTypeEnum::into_struct_type)?;

struct_type.set_body(members.as_slice(), false);
}
Expand All @@ -121,9 +150,14 @@ impl<'ink, 'b> DataTypeGenerator<'ink, 'b> {
) -> Result<BasicTypeEnum<'ink>, Diagnostic> {
let information = data_type.get_type_information();
match information {
DataTypeInformation::Struct { .. } => {
self.types_index.get_associated_type(data_type.get_name())
}
DataTypeInformation::Struct { source, .. } => match source {
StructSource::Pou(..) => self
.types_index
.get_associated_pou_type(data_type.get_name()),
StructSource::OriginalDeclaration => {
self.types_index.get_associated_type(data_type.get_name())
}
},
DataTypeInformation::Array {
inner_type_name,
dimensions,
Expand Down Expand Up @@ -184,7 +218,7 @@ impl<'ink, 'b> DataTypeGenerator<'ink, 'b> {
) -> Result<Option<BasicValueEnum<'ink>>, Diagnostic> {
let information = data_type.get_type_information();
match information {
DataTypeInformation::Struct { .. } => {
DataTypeInformation::Struct { source, .. } => {
let members = self.index.get_container_members(data_type.get_name());
let member_names_and_initializers = members
.iter()
Expand All @@ -208,10 +242,15 @@ impl<'ink, 'b> DataTypeGenerator<'ink, 'b> {
member_values.push(*v);
}

let struct_type = self
.types_index
.get_associated_type(data_type.get_name())?
.into_struct_type();
let struct_type = match source {
StructSource::Pou(..) => self
.types_index
.get_associated_pou_type(data_type.get_name()),
StructSource::OriginalDeclaration => {
self.types_index.get_associated_type(data_type.get_name())
}
}?
.into_struct_type();

Ok(Some(
struct_type
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/generators/expression_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ impl<'a, 'b> ExpressionCodeGenerator<'a, 'b> {
let instance_name = format!("{}_instance", function_name);
let function_type = self
.llvm_index
.find_associated_type(function_name) //Using find instead of get to control the compile error
.find_associated_pou_type(function_name) //Using find instead of get to control the compile error
.ok_or_else(|| {
Diagnostic::codegen_error(
&format!("No type associated with '{:}'", instance_name),
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/generators/pou_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl<'ink, 'cg> PouGenerator<'ink, 'cg> {

let instance_struct_type: StructType = self
.llvm_index
.get_associated_type(implementation.get_type_name())
.get_associated_pou_type(implementation.get_type_name())
.map(|it| it.into_struct_type())?;
parameters.push(instance_struct_type.ptr_type(AddressSpace::Generic).into());

Expand Down
35 changes: 35 additions & 0 deletions src/codegen/llvm_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use std::collections::HashMap;
pub struct LlvmTypedIndex<'ink> {
parent_index: Option<&'ink LlvmTypedIndex<'ink>>,
type_associations: HashMap<String, BasicTypeEnum<'ink>>,
pou_type_associations: HashMap<String, BasicTypeEnum<'ink>>,
initial_value_associations: HashMap<String, BasicValueEnum<'ink>>,
loaded_variable_associations: HashMap<String, PointerValue<'ink>>,
implementations: HashMap<String, FunctionValue<'ink>>,
Expand All @@ -22,6 +23,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
LlvmTypedIndex {
parent_index: Some(parent),
type_associations: HashMap::new(),
pou_type_associations: HashMap::new(),
initial_value_associations: HashMap::new(),
loaded_variable_associations: HashMap::new(),
implementations: HashMap::new(),
Expand All @@ -33,6 +35,9 @@ impl<'ink> LlvmTypedIndex<'ink> {
for (name, assocication) in other.type_associations.drain() {
self.type_associations.insert(name, assocication);
}
for (name, assocication) in other.pou_type_associations.drain() {
self.pou_type_associations.insert(name, assocication);
}
for (name, assocication) in other.initial_value_associations.drain() {
self.initial_value_associations.insert(name, assocication);
}
Expand All @@ -58,6 +63,16 @@ impl<'ink> LlvmTypedIndex<'ink> {
Ok(())
}

pub fn associate_pou_type(
&mut self,
type_name: &str,
target_type: BasicTypeEnum<'ink>,
) -> Result<(), Diagnostic> {
self.pou_type_associations
.insert(type_name.to_lowercase(), target_type);
Ok(())
}

pub fn associate_initial_value(
&mut self,
type_name: &str,
Expand Down Expand Up @@ -89,13 +104,33 @@ impl<'ink> LlvmTypedIndex<'ink> {
.map(|it| it.find_associated_type(type_name))
.flatten()
})
.or_else(|| self.find_associated_pou_type(type_name))
}

pub fn find_associated_pou_type(&self, type_name: &str) -> Option<BasicTypeEnum<'ink>> {
self.pou_type_associations
.get(&type_name.to_lowercase())
.copied()
.or_else(|| {
self.parent_index
.map(|it| it.find_associated_pou_type(type_name))
.flatten()
})
}

pub fn get_associated_type(&self, type_name: &str) -> Result<BasicTypeEnum<'ink>, Diagnostic> {
self.find_associated_type(type_name)
.ok_or_else(|| Diagnostic::unknown_type(type_name, SourceRange::undefined()))
}

pub fn get_associated_pou_type(
&self,
type_name: &str,
) -> Result<BasicTypeEnum<'ink>, Diagnostic> {
self.find_associated_pou_type(type_name)
.ok_or_else(|| Diagnostic::unknown_type(type_name, SourceRange::undefined()))
}

pub fn find_associated_initial_value(&self, type_name: &str) -> Option<BasicValueEnum<'ink>> {
self.initial_value_associations
.get(&type_name.to_lowercase())
Expand Down
51 changes: 51 additions & 0 deletions src/codegen/tests/code_gen_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5706,3 +5706,54 @@ fn program_with_casted_chars_assignment() {
);
insta::assert_snapshot!(result);
}

#[test]
fn function_call_with_same_name_as_return_type() {
let result = codegen(
"
FUNCTION TIME : TIME
END_FUNCTION
PROGRAM prg
VAR
END_VAR
TIME();
END_PROGRAM
",
);
insta::assert_snapshot!(result);
}

#[test]
fn variable_with_same_name_as_data_type() {
let result = codegen(
"
FUNCTION func : TIME
VAR
TIME : TIME;
END_VAR
END_FUNCTION
PROGRAM prog
VAR
TIME : TIME;
END_VAR
END_PROGRAM
",
);
insta::assert_snapshot!(result);
}

#[test]
fn variable_with_same_name_as_function() {
let result = codegen(
"
FUNCTION TIME : TIME
VAR
TIME : TIME;
END_VAR
END_FUNCTION
",
);
insta::assert_snapshot!(result);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
source: src/codegen/tests/code_gen_tests.rs
expression: result

---
; ModuleID = 'main'
source_filename = "main"

%prg_interface = type {}
%TIME_interface = type {}

@prg_instance = global %prg_interface zeroinitializer

define i64 @TIME(%TIME_interface* %0) {
entry:
%TIME = alloca i64, align 8
%TIME_ret = load i64, i64* %TIME, align 4
ret i64 %TIME_ret
}

define void @prg(%prg_interface* %0) {
entry:
%TIME_instance = alloca %TIME_interface, align 8
br label %input

input: ; preds = %entry
br label %call

call: ; preds = %input
%call1 = call i64 @TIME(%TIME_interface* %TIME_instance)
br label %output

output: ; preds = %call
br label %continue

continue: ; preds = %output
ret void
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
source: src/codegen/tests/code_gen_tests.rs
expression: result

---
; ModuleID = 'main'
source_filename = "main"

%prog_interface = type { i64 }
%func_interface = type { i64 }

@prog_instance = global %prog_interface zeroinitializer

define i64 @func(%func_interface* %0) {
entry:
%TIME = getelementptr inbounds %func_interface, %func_interface* %0, i32 0, i32 0
%func = alloca i64, align 8
%func_ret = load i64, i64* %func, align 4
ret i64 %func_ret
}

define void @prog(%prog_interface* %0) {
entry:
%TIME = getelementptr inbounds %prog_interface, %prog_interface* %0, i32 0, i32 0
ret void
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
source: src/codegen/tests/code_gen_tests.rs
expression: result

---
; ModuleID = 'main'
source_filename = "main"

%TIME_interface = type {}

define i64 @TIME(%TIME_interface* %0) {
entry:
%TIME = alloca i64, align 8
%TIME_ret = load i64, i64* %TIME, align 4
ret i64 %TIME_ret
}

Loading

0 comments on commit 901304e

Please sign in to comment.