Skip to content

Commit

Permalink
Use vec instead of map, add generics to index
Browse files Browse the repository at this point in the history
  • Loading branch information
ghaith committed Nov 18, 2021
1 parent e3fbdc1 commit 935691c
Show file tree
Hide file tree
Showing 13 changed files with 113 additions and 184 deletions.
20 changes: 10 additions & 10 deletions src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
use crate::typesystem::DataTypeInformation;
use std::{
collections::HashMap,
fmt::{Debug, Display, Formatter, Result},
iter,
ops::Range,
Expand All @@ -11,6 +10,12 @@ mod pre_processor;

pub type AstId = usize;

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

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

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -345,7 +350,6 @@ pub enum DataType {
StructType {
name: Option<String>, //maybe None for inline structs
variables: Vec<Variable>,
generics: HashMap<String, String>,
},
EnumType {
name: Option<String>, //maybe empty for inline enums
Expand Down Expand Up @@ -381,14 +385,10 @@ impl Debug for DataType {
DataType::StructType {
name,
variables,
generics,
} => {
let mut str = f.debug_struct("StructType");
str.field("name", name).field("variables", variables);
if !generics.is_empty() {
str.field("generics", generics);
}
str.finish()
f.debug_struct("StructType")
.field("name", name).field("variables", variables)
.finish()
}
DataType::EnumType { name, elements } => f
.debug_struct("EnumType")
Expand Down
142 changes: 55 additions & 87 deletions src/codegen/generators/expression_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,99 +401,67 @@ impl<'a, 'b> ExpressionCodeGenerator<'a, 'b> {
}

let function_context = self.get_function_context(operator)?;
let instance_and_index_entry = match operator {
AstStatement::Reference { name, .. } => {
//Get associated Variable or generate a variable for the type with the same name
let variable = self.index.find_callable_instance_variable(
Some(function_context.linking_context.get_type_name()),
&[name],
);

let (implementation, callable_reference) = if let Some(variable_instance) = variable
{
let implementation = try_find_implementation(
self.index,
variable_instance.get_type_name(),
operator,
)?;
(
implementation,
self.llvm_index
.find_loaded_associated_variable_value(
variable_instance.get_qualified_name(),
)
.ok_or_else(|| CompileError::CodeGenError {
message: format!("cannot find callable type for {:?}", operator),
location: operator.get_location(),
})?,
)
//find call name
let implementation = self
.annotations
.get_call_name(operator)
//find implementationIndexEntry for the name
.and_then(|it| self.index.find_implementation(it))
//If that fails, try to find an implementation from the reference name
.or_else(|| {
if let AstStatement::Reference { name, .. } = operator {
try_find_implementation(self.index, name, operator).ok()
} else {
let implementation = self.index.find_implementation(name);
if let Some(implementation) = implementation {
(
implementation,
self.allocate_function_struct_instance(
implementation.get_call_name(),
operator,
)?,
)
} else {
//Look for a possible action
let qualified_name = format!(
"{}.{}",
function_context.linking_context.get_type_name(),
name
);
let function = function_context.function;
let ptr = function.get_first_param().unwrap();
(
try_find_implementation(self.index, qualified_name.as_str(), operator)?,
ptr.into_pointer_value(),
)
}
};
None
}
})
.ok_or_else(|| CompileError::CodeGenError {
message: format!("cannot generate call statement for {:?}", operator),
location: operator.get_location(),
})?;

Ok((None, callable_reference, implementation))
let (class_ptr, call_ptr) = match implementation {
ImplementationIndexEntry {
implementation_type: ImplementationType::Function,
..
} => {
let call_ptr = self
.allocate_function_struct_instance(implementation.get_call_name(), operator)?;
(None, call_ptr)
}
AstStatement::QualifiedReference { .. } => {
let loaded_value = self.generate_element_pointer(operator);
loaded_value.map(|ptr_value| {
//find call name
self.annotations
.get_call_name(operator)
//find implementationIndexEntry for the name
.and_then(|it| self.index.find_implementation(it))
.map(|implementation| {
let (class_struct, method_struct) = if matches!(
implementation.get_implementation_type(),
&ImplementationType::Method
) {
(
Some(ptr_value),
self.allocate_function_struct_instance(
implementation.get_call_name(),
operator,
)
.unwrap(),
)
} else {
(None, ptr_value)
};
(class_struct, method_struct, implementation)
})
.ok_or_else(|| CompileError::CodeGenError {
message: format!("cannot generate call statement for {:?}", operator),
location: operator.get_location(),
})
})?
ImplementationIndexEntry {
implementation_type: ImplementationType::Method,
..
} => {
let class_ptr = self.generate_element_pointer(operator)?;
let call_ptr = self
.allocate_function_struct_instance(implementation.get_call_name(), operator)?;
(Some(class_ptr), call_ptr)
}
ImplementationIndexEntry {
implementation_type: ImplementationType::Action,
..
} if matches!(operator, AstStatement::Reference { .. }) => {
//Special handling for local actions, get the parameter from the function context
if let Some(call_ptr) = function_context.function.get_first_param() {
(None, call_ptr.into_pointer_value())
} else {
return Err(CompileError::CodeGenError {
message: format!(
"cannot find parameter for {}",
implementation.get_call_name()
),
location: operator.get_location(),
});
}
}
_ => {
let class_ptr = self.generate_element_pointer(operator)?;
(None, class_ptr)
}
_ => Err(CompileError::CodeGenError {
message: format!("cannot generate call statement for {:?}", operator),
location: operator.get_location(),
}),
};

let (class_struct, instance, index_entry) = instance_and_index_entry?;
let (class_struct, instance, index_entry) = (class_ptr, call_ptr, implementation);
let function_name = index_entry.get_call_name();
//Create parameters for input and output blocks
let current_f = function_context.function;
Expand Down
1 change: 1 addition & 0 deletions src/index/tests.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
// Copyright (c) 2020 Ghaith Hachem and Mathias Rieder
mod index_tests;
mod generic_tests;
19 changes: 19 additions & 0 deletions src/index/tests/generic_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use pretty_assertions::assert_eq;

use crate::{ast::GenericBinding, test_utils::tests::index, typesystem::DataTypeInformation};

#[test]
fn generics_saved_in_index() {
let (_,index) = index(r"
FUNCTION foo<T: ANY> : T; END_FUNCTION
");

let foo_info = index.find_effective_type_info("foo").unwrap();
assert!(foo_info.is_generic());
if let DataTypeInformation::Struct{ generics, .. } = foo_info {
let t = &generics[0];
assert_eq!(&GenericBinding{ name: "T".into(), nature: "ANY".into()}, t);
} else {
panic!("{:#?} not a struct", foo_info);
}
}
4 changes: 0 additions & 4 deletions src/index/tests/index_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::parser::tests::literal_int;
use crate::test_utils::tests::{index, parse};
use crate::typesystem::TypeSize;
use crate::{ast::*, index::VariableType, typesystem::DataTypeInformation};
use std::collections::HashMap;

#[test]
fn index_not_case_sensitive() {
Expand Down Expand Up @@ -707,7 +706,6 @@ fn pre_processing_generates_inline_structs_global() {
location: (54..55).into(),
initializer: None,
},],
generics: HashMap::new()
},
new_struct_type
);
Expand Down Expand Up @@ -797,7 +795,6 @@ fn pre_processing_generates_inline_structs() {
location: (67..68).into(),
initializer: None,
}],
generics: HashMap::new(),
},
new_struct_type
);
Expand Down Expand Up @@ -1199,7 +1196,6 @@ fn pre_processing_nested_array_in_struct() {
location: SourceRange::undefined(),
initializer: None,
}],
generics: HashMap::new(),
},
initializer: None,
location: (14..97).into(),
Expand Down
3 changes: 2 additions & 1 deletion src/index/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ pub fn visit_pou(index: &mut Index, pou: &Pou) {
member_names,
varargs,
source: StructSource::Pou(pou.pou_type.clone()),
generics: pou.generics.clone(),
},
);
}
Expand Down Expand Up @@ -222,7 +223,6 @@ fn visit_data_type(
DataType::StructType {
name: Some(name),
variables,
generics: _,
} => {
let struct_name = name.as_str();

Expand All @@ -235,6 +235,7 @@ fn visit_data_type(
member_names,
varargs: None,
source: StructSource::OriginalDeclaration,
generics: vec![],
};

let init = index
Expand Down
13 changes: 5 additions & 8 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::{
lexer::{ParseSession, Token, Token::*},
Diagnostic,
};
use std::collections::HashMap;

use self::{control_parser::parse_control_statement, expressions_parser::parse_expression};

Expand Down Expand Up @@ -238,16 +237,16 @@ fn parse_pou(
pou
}

fn parse_generics(lexer: &mut ParseSession) -> HashMap<String, String> {
fn parse_generics(lexer: &mut ParseSession) -> Vec<GenericBinding> {
if lexer.allow(&Token::OperatorLess) {
parse_any_in_region(lexer, vec![Token::OperatorGreater], |lexer| {
let mut generics = HashMap::new();
let mut generics = vec![];
loop {
//identifier
if let Some(identifier) = parse_identifier(lexer) {
if let Some(name) = parse_identifier(lexer) {
lexer.consume_or_report(Token::KeywordColon);
if let Some(nature) = parse_identifier(lexer) {
generics.insert(identifier, nature);
generics.push(GenericBinding{ name, nature });
}
}

Expand All @@ -259,7 +258,7 @@ fn parse_generics(lexer: &mut ParseSession) -> HashMap<String, String> {
generics
})
} else {
HashMap::new()
vec![]
}
}

Expand Down Expand Up @@ -567,15 +566,13 @@ fn parse_data_type_definition(
) -> Option<DataTypeWithInitializer> {
let start = lexer.location().get_start();
if lexer.allow(&KeywordStruct) {
let generics = parse_generics(lexer);
// Parse struct
let variables = parse_variable_list(lexer);
Some((
DataTypeDeclaration::DataTypeDefinition {
data_type: DataType::StructType {
name,
variables,
generics,
},
location: (start..lexer.range().end).into(),
scope: lexer.scope.clone(),
Expand Down
5 changes: 2 additions & 3 deletions src/parser/tests/expressions_parser_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::ast::{
use crate::parser::tests::{literal_int, ref_to};
use crate::test_utils::tests::parse;
use pretty_assertions::*;
use std::collections::HashMap;

#[test]
fn single_statement_parsed() {
Expand Down Expand Up @@ -2556,7 +2555,7 @@ fn sized_string_as_function_return() {
}),
variable_blocks: vec![],
location: SourceRange::undefined(),
generics: HashMap::new(),
generics: vec![],
};

assert_eq!(format!("{:?}", ast.units[0]), format!("{:?}", expected));
Expand Down Expand Up @@ -2602,7 +2601,7 @@ fn array_type_as_function_return() {
}),
variable_blocks: vec![],
location: SourceRange::undefined(),
generics: HashMap::new(),
generics: vec![],
};

assert_eq!(format!("{:?}", ast.units[0]), format!("{:?}", expected));
Expand Down
4 changes: 1 addition & 3 deletions src/parser/tests/function_parser_tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::{ast::*, test_utils::tests::parse, Diagnostic};
use pretty_assertions::*;
use std::collections::HashMap;

#[test]
fn simple_foo_function_can_be_parsed() {
Expand Down Expand Up @@ -159,7 +158,7 @@ fn varargs_parameters_can_be_parsed() {
}],
location: SourceRange::undefined(),
poly_mode: None,
generics: HashMap::new(),
generics: vec![],
};
assert_eq!(format!("{:#?}", expected), format!("{:#?}", x).as_str());
}
Expand Down Expand Up @@ -337,7 +336,6 @@ fn function_inline_struct_return_unsupported() {
initializer: None
}
],
generics: HashMap::new(),
},
location: (15..50).into(),
scope: Some("foo".into()),
Expand Down
Loading

0 comments on commit 935691c

Please sign in to comment.