Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 375 add support for any type #380

Merged
merged 23 commits into from
Dec 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7750771
Add generics type to the AST
ghaith Nov 15, 2021
e3fbdc1
Add support for parsing generic types
ghaith Nov 15, 2021
8f03a6b
Use vec instead of map, add generics to index
ghaith Nov 18, 2021
265abfd
Merge remote-tracking branch 'origin/master' into issue-375-Add_suppo…
ghaith Nov 18, 2021
ccdb789
Codegen tests
ghaith Nov 18, 2021
560eb00
Add indexing support for generics
ghaith Nov 20, 2021
9098079
Merge remote-tracking branch 'origin/master' into issue-375-Add_suppo…
ghaith Nov 20, 2021
8037f58
Add resolver support for generics
ghaith Nov 27, 2021
43a53a6
Merge remote-tracking branch 'origin/master' into issue-375-Add_suppo…
ghaith Nov 27, 2021
276da9d
Clippy fixes
ghaith Nov 27, 2021
8b7bca3
Code generation for generics
ghaith Nov 27, 2021
fe7fdc4
Add natures as keywords, add initial validation scaffold
ghaith Nov 29, 2021
9a54f4c
Merge remote-tracking branch 'origin/master' into issue-375-Add_suppo…
ghaith Nov 29, 2021
71e8a41
Validation wip
ghaith Nov 29, 2021
aafb8e8
Add validation for generics
ghaith Nov 30, 2021
fd7bb31
Deleted some demo files
ghaith Nov 30, 2021
d2b77fe
Add intermdiate index
ghaith Nov 30, 2021
807a3b9
Merge remote-tracking branch 'origin/master' into issue-375-Add_suppo…
ghaith Nov 30, 2021
a598e23
Create implementation entries for resolved generics - wip
ghaith Nov 30, 2021
c51bfa3
Make sure types are generated, add correctness tests
ghaith Dec 1, 2021
4b8b977
additional tests for generic-parameter annotation
riederm Dec 1, 2021
96ee719
Fix some review comments, missing : Tokens
ghaith Dec 2, 2021
a7946cc
Remove the keywords from the lexer and treat type natures as Identifiers
ghaith Dec 2, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "rusty"
version = "0.2.0"
authors = ["Ghaith Hachem <ghaith.hachem@gmail.com>", "Mathias Rieder <mathias.rieder@gmail.com>"]
edition = "2018"
edition = "2021"
readme = "README.md"
repository = "https://github.com/ghaith/rusty/"
license = "LGPL-3.0-or-later"
Expand Down
201 changes: 124 additions & 77 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ mod pre_processor;

pub type AstId = usize;

#[derive(Clone, Debug, PartialEq)]
pub struct GenericBinding {
pub name: String,
pub nature: TypeNature,
}

#[derive(PartialEq)]
pub struct Pou {
pub name: String,
Expand All @@ -18,6 +24,7 @@ pub struct Pou {
pub return_type: Option<DataTypeDeclaration>,
pub location: SourceRange,
pub poly_mode: Option<PolymorphismMode>,
pub generics: Vec<GenericBinding>,
}

#[derive(Debug, PartialEq)]
Expand All @@ -35,6 +42,95 @@ pub enum DirectAccessType {
DWord,
}

#[derive(Debug, PartialEq, Clone, Copy)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i find it a bit surprising, that typeNatures are note defined in typesystem.rs

I guess you want to avoid the dependency from AST -> typesystem?

pub enum TypeNature {
Any,
Derived,
Elementary,
Magnitude,
Num,
Real,
Int,
Signed,
Unsigned,
Duration,
Bit,
Chars,
String,
Char,
Date,
}

impl TypeNature {
pub fn derives(self, other: TypeNature) -> bool {
if other == self {
true
} else {
match self {
TypeNature::Any => true,
TypeNature::Derived => matches!(other, TypeNature::Any),
TypeNature::Elementary => matches!(other, TypeNature::Any),
TypeNature::Magnitude => matches!(other, TypeNature::Elementary | TypeNature::Any),
TypeNature::Num => matches!(
other,
TypeNature::Magnitude | TypeNature::Elementary | TypeNature::Any
),
TypeNature::Real => matches!(
other,
TypeNature::Num
| TypeNature::Magnitude
| TypeNature::Elementary
| TypeNature::Any
),
TypeNature::Int => matches!(
other,
TypeNature::Num
| TypeNature::Magnitude
| TypeNature::Elementary
| TypeNature::Any
),
TypeNature::Signed => matches!(
other,
TypeNature::Int
| TypeNature::Num
| TypeNature::Magnitude
| TypeNature::Elementary
| TypeNature::Any
),
TypeNature::Unsigned => matches!(
other,
TypeNature::Int
| TypeNature::Num
| TypeNature::Magnitude
| TypeNature::Elementary
| TypeNature::Any
),
TypeNature::Duration => matches!(
other,
TypeNature::Num
| TypeNature::Magnitude
| TypeNature::Elementary
| TypeNature::Any
),
TypeNature::Bit => matches!(
other,
TypeNature::Magnitude | TypeNature::Elementary | TypeNature::Any
),
TypeNature::Chars => matches!(other, TypeNature::Elementary | TypeNature::Any),
TypeNature::String => matches!(
other,
TypeNature::Chars | TypeNature::Elementary | TypeNature::Any
),
TypeNature::Char => matches!(
other,
TypeNature::Chars | TypeNature::Elementary | TypeNature::Any
),
TypeNature::Date => matches!(other, TypeNature::Elementary | TypeNature::Any),
}
}
}
}

impl DirectAccessType {
/// Returns true if the current index is in the range for the given type
pub fn is_in_range(&self, index: u64, data_type: &DataTypeInformation) -> bool {
Expand Down Expand Up @@ -64,12 +160,15 @@ impl DirectAccessType {

impl Debug for Pou {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("POU")
.field("name", &self.name)
let mut str = f.debug_struct("POU");
str.field("name", &self.name)
.field("variable_blocks", &self.variable_blocks)
.field("pou_type", &self.pou_type)
.field("return_type", &self.return_type)
.finish()
.field("return_type", &self.return_type);
if !self.generics.is_empty() {
str.field("generics", &self.generics);
}
str.finish()
}
}

Expand Down Expand Up @@ -335,7 +434,7 @@ impl Debug for UserTypeDeclaration {
}
}

#[derive(Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
pub enum DataType {
StructType {
name: Option<String>, //maybe None for inline structs
Expand Down Expand Up @@ -367,88 +466,36 @@ pub enum DataType {
VarArgs {
referenced_type: Option<Box<DataTypeDeclaration>>,
},
}

impl Debug for DataType {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self {
DataType::StructType { name, variables } => f
.debug_struct("StructType")
.field("name", name)
.field("variables", variables)
.finish(),
DataType::EnumType { name, elements } => f
.debug_struct("EnumType")
.field("name", name)
.field("elements", elements)
.finish(),
DataType::SubRangeType {
name,
referenced_type,
bounds,
} => f
.debug_struct("SubRangeType")
.field("name", name)
.field("referenced_type", referenced_type)
.field("bounds", bounds)
.finish(),
DataType::ArrayType {
name,
bounds,
referenced_type,
} => f
.debug_struct("ArrayType")
.field("name", name)
.field("bounds", bounds)
.field("referenced_type", referenced_type)
.finish(),
DataType::PointerType {
name,
referenced_type,
} => f
.debug_struct("PointerType")
.field("name", name)
.field("referenced_type", referenced_type)
.finish(),
DataType::StringType {
name,
is_wide,
size,
} => f
.debug_struct("StringType")
.field("name", name)
.field("is_wide", is_wide)
.field("size", size)
.finish(),
DataType::VarArgs { referenced_type } => f
.debug_struct("VarArgs")
.field("referenced_type", referenced_type)
.finish(),
}
}
GenericType {
name: String,
generic_symbol: String,
nature: TypeNature,
},
}

impl DataType {
pub fn set_name(&mut self, new_name: String) {
match self {
DataType::StructType { name, variables: _ } => *name = Some(new_name),
DataType::EnumType { name, elements: _ } => *name = Some(new_name),
DataType::SubRangeType { name, .. } => *name = Some(new_name),
DataType::ArrayType { name, .. } => *name = Some(new_name),
DataType::PointerType { name, .. } => *name = Some(new_name),
DataType::StringType { name, .. } => *name = Some(new_name),
DataType::StructType { name, .. }
| DataType::EnumType { name, .. }
| DataType::SubRangeType { name, .. }
| DataType::ArrayType { name, .. }
| DataType::PointerType { name, .. }
| DataType::StringType { name, .. } => *name = Some(new_name),
DataType::GenericType { name, .. } => *name = new_name,
DataType::VarArgs { .. } => {} //No names on varargs
}
}

pub fn get_name(&self) -> Option<&str> {
match self {
DataType::StructType { name, variables: _ } => name.as_ref().map(|x| x.as_str()),
DataType::EnumType { name, elements: _ } => name.as_ref().map(|x| x.as_str()),
DataType::ArrayType { name, .. } => name.as_ref().map(|x| x.as_str()),
DataType::PointerType { name, .. } => name.as_ref().map(|x| x.as_str()),
DataType::StringType { name, .. } => name.as_ref().map(|x| x.as_str()),
DataType::SubRangeType { name, .. } => name.as_ref().map(|x| x.as_str()),
match &self {
DataType::StructType { name, .. }
| DataType::EnumType { name, .. }
| DataType::ArrayType { name, .. }
| DataType::PointerType { name, .. }
| DataType::StringType { name, .. }
| DataType::SubRangeType { name, .. } => name.as_ref().map(|x| x.as_str()),
DataType::GenericType { name, .. } => Some(name.as_str()),
DataType::VarArgs { .. } => None,
}
}
Expand Down
67 changes: 64 additions & 3 deletions src/ast/pre_processor.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder

use crate::ast::DataTypeDeclaration;

use super::{
super::ast::{CompilationUnit, DataType, DataTypeDeclaration, UserTypeDeclaration, Variable},
super::ast::{CompilationUnit, DataType, UserTypeDeclaration, Variable},
Pou, SourceRange,
};
use std::vec;
use std::{collections::HashMap, vec};

pub fn pre_process(unit: &mut CompilationUnit) {
//process all local variables from POUs
for mut pou in unit.units.iter_mut() {
//Find all generic types in that pou
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we put this into it's own function?. It kindo'f disturbs the level of detail of the rest of this function

let generic_types = preprocess_generic_structs(&mut pou);
unit.types.extend(generic_types);

let all_variables = pou
.variable_blocks
.iter_mut()
Expand Down Expand Up @@ -39,7 +45,9 @@ pub fn pre_process(unit: &mut CompilationUnit) {
for dt in unit.types.iter_mut() {
{
match &mut dt.data_type {
DataType::StructType { name, variables } => {
DataType::StructType {
name, variables, ..
} => {
let name: &str = name.as_ref().map(|it| it.as_str()).unwrap_or("undefined");
variables
.iter_mut()
Expand Down Expand Up @@ -88,6 +96,38 @@ pub fn pre_process(unit: &mut CompilationUnit) {
unit.types.append(&mut new_types);
}

fn preprocess_generic_structs(pou: &mut Pou) -> Vec<UserTypeDeclaration> {
let mut generic_types = HashMap::new();
let mut types = vec![];
for binding in &pou.generics {
let new_name = format!("__{}__{}", pou.name, binding.name);
//Generate a type for the generic
let data_type = UserTypeDeclaration {
data_type: DataType::GenericType {
name: new_name.clone(),
generic_symbol: binding.name.clone(),
nature: binding.nature,
},
initializer: None,
scope: Some(pou.name.clone()),
location: pou.location.clone(),
};
types.push(data_type);
generic_types.insert(binding.name.clone(), new_name);
}
for var in pou
.variable_blocks
.iter_mut()
.flat_map(|it| it.variables.iter_mut())
{
replace_generic_type_name(&mut var.data_type, &generic_types);
}
if let Some(datatype) = pou.return_type.as_mut() {
replace_generic_type_name(datatype, &generic_types);
};
types
}

fn preprocess_return_type(pou: &mut Pou, types: &mut Vec<UserTypeDeclaration>) {
if let Some(return_type) = &pou.return_type {
if should_generate_implicit(return_type) {
Expand Down Expand Up @@ -185,3 +225,24 @@ fn add_nested_datatypes(
});
}
}

fn replace_generic_type_name(dt: &mut DataTypeDeclaration, generics: &HashMap<String, String>) {
match dt {
DataTypeDeclaration::DataTypeDefinition { data_type, .. } => match data_type {
DataType::ArrayType {
referenced_type, ..
}
| DataType::PointerType {
referenced_type, ..
} => replace_generic_type_name(referenced_type.as_mut(), generics),
_ => {}
},
DataTypeDeclaration::DataTypeReference {
referenced_type, ..
} => {
if let Some(type_name) = generics.get(referenced_type) {
*referenced_type = type_name.clone();
}
}
}
}
8 changes: 6 additions & 2 deletions src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,12 @@ impl<'ink> CodeGen<'ink> {

//Generate the POU stubs in the first go to make sure they can be referenced.
for implementation in &unit.implementations {
//Don't generate external functions
if implementation.linkage != LinkageType::External {
//Don't generate external or generic functions
if implementation.linkage != LinkageType::External
&& !global_index
.get_type_information_or_void(&implementation.type_name)
.is_generic()
{
pou_generator.generate_implementation(implementation)?;
}
}
Expand Down
Loading