Skip to content

Support case insesitive keywords #255

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

Merged
merged 2 commits into from
Aug 23, 2021
Merged
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions src/codegen/generators/data_type_generator.rs
Original file line number Diff line number Diff line change
@@ -234,8 +234,8 @@ fn register_aliased_initial_value<'ink>(
} else {
// if there's no initializer defined for this alias, we go and check the aliased type for an initial value
index
.get_types()
.get(referenced_type)
.get_type(referenced_type)
.ok()
.and_then(|referenced_data_type| {
generate_initial_value(index, types_index, llvm, referenced_data_type)
})
32 changes: 18 additions & 14 deletions src/codegen/llvm_index.rs
Original file line number Diff line number Diff line change
@@ -60,7 +60,8 @@ impl<'ink> LlvmTypedIndex<'ink> {
type_name: &str,
target_type: BasicTypeEnum<'ink>,
) -> Result<(), CompileError> {
self.type_associations.insert(type_name.into(), target_type);
self.type_associations
.insert(type_name.to_lowercase(), target_type);
Ok(())
}

@@ -70,7 +71,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
initial_value: BasicValueEnum<'ink>,
) -> Result<(), CompileError> {
self.initial_value_associations
.insert(type_name.into(), initial_value);
.insert(type_name.to_lowercase(), initial_value);
Ok(())
}

@@ -82,16 +83,19 @@ impl<'ink> LlvmTypedIndex<'ink> {
) -> Result<(), CompileError> {
let qualified_name = format!("{}.{}", container_name, variable_name);
self.loaded_variable_associations
.insert(qualified_name, target_value);
.insert(qualified_name.to_lowercase(), target_value);
Ok(())
}

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

pub fn get_associated_type(
@@ -104,7 +108,7 @@ impl<'ink> LlvmTypedIndex<'ink> {

pub fn find_associated_initial_value(&self, type_name: &str) -> Option<BasicValueEnum<'ink>> {
self.initial_value_associations
.get(type_name)
.get(&type_name.to_lowercase())
.copied()
.or_else(|| {
self.parent_index
@@ -119,7 +123,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
global_variable: GlobalValue<'ink>,
) -> Result<(), CompileError> {
self.initial_value_associations.insert(
variable_name.into(),
variable_name.to_lowercase(),
global_variable.as_pointer_value().into(),
);
Ok(())
@@ -131,7 +135,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
function_value: FunctionValue<'ink>,
) -> Result<(), CompileError> {
self.implementations
.insert(callable_name.into(), function_value);
.insert(callable_name.to_lowercase(), function_value);
Ok(())
}

@@ -140,7 +144,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
callable_name: &str,
) -> Option<FunctionValue<'ink>> {
self.implementations
.get(callable_name)
.get(&callable_name.to_lowercase())
.copied()
.or_else(|| {
self.parent_index
@@ -154,7 +158,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
qualified_name: &str,
) -> Option<BasicValueEnum<'ink>> {
self.initial_value_associations
.get(qualified_name)
.get(&qualified_name.to_lowercase())
.copied()
.or_else(|| {
self.parent_index
@@ -169,7 +173,7 @@ impl<'ink> LlvmTypedIndex<'ink> {
) -> Option<PointerValue<'ink>> {
let result = self
.loaded_variable_associations
.get(qualified_name)
.get(&qualified_name.to_lowercase())
.copied()
.or_else(|| {
self.parent_index
37 changes: 37 additions & 0 deletions src/codegen/tests/code_gen_tests.rs
Original file line number Diff line number Diff line change
@@ -163,6 +163,7 @@ entry:

assert_eq!(result, expected);
}

#[test]
fn program_with_variables_generates_void_function_and_struct() {
let result = codegen!(
@@ -580,6 +581,42 @@ entry:
assert_eq!(result, expected);
}

#[test]
fn different_case_references() {
let result = codegen!(
r#"
TYPE MyInt: INT := 1; END_TYPE
TYPE MyDInt: DINT := 2; END_TYPE

PROGRAM prg
VAR
y : int;
z : MyInt;
zz : Mydint;
END_VAR
END_PROGRAM
"#
);

let expected = r#"; ModuleID = 'main'
source_filename = "main"

%prg_interface = type { i16, i16, i32 }

@prg_instance = global %prg_interface { i16 0, i32 1, i32 2 }

define void @prg(%prg_interface* %0) {
entry:
%y = getelementptr inbounds %prg_interface, %prg_interface* %0, i32 0, i32 0
%z = getelementptr inbounds %prg_interface, %prg_interface* %0, i32 0, i32 1
%zz = getelementptr inbounds %prg_interface, %prg_interface* %0, i32 0, i32 2
ret void
}
"#;

assert_eq!(result, expected);
}

#[test]
fn program_with_string_type_assignment() {
let result = codegen!(
42 changes: 23 additions & 19 deletions src/index.rs
Original file line number Diff line number Diff line change
@@ -193,26 +193,26 @@ impl Index {
}

pub fn find_global_variable(&self, name: &str) -> Option<&VariableIndexEntry> {
self.global_variables.get(name)
self.global_variables.get(&name.to_lowercase())
}

pub fn find_member(&self, pou_name: &str, variable_name: &str) -> Option<&VariableIndexEntry> {
self.member_variables
.get(pou_name)
.and_then(|map| map.get(variable_name))
.get(&pou_name.to_lowercase())
.and_then(|map| map.get(&variable_name.to_lowercase()))
}

pub fn find_local_members(&self, container_name: &str) -> Vec<&VariableIndexEntry> {
self.member_variables
.get(container_name)
.get(&container_name.to_lowercase())
.map(|it| it.values().collect())
.unwrap_or_else(Vec::new)
}

/// Returns true if the current index is a VAR_INPUT, VAR_IN_OUT or VAR_OUTPUT that is not a variadic argument
pub fn is_declared_parameter(&self, pou_name: &str, index: u32) -> bool {
self.member_variables
.get(pou_name)
.get(&pou_name.to_lowercase())
.and_then(|map| {
map.values()
.filter(|item| {
@@ -226,11 +226,13 @@ impl Index {
}

pub fn find_input_parameter(&self, pou_name: &str, index: u32) -> Option<&VariableIndexEntry> {
self.member_variables.get(pou_name).and_then(|map| {
map.values()
.filter(|item| item.information.variable_type == VariableType::Input)
.find(|item| item.information.location == index)
})
self.member_variables
.get(&pou_name.to_lowercase())
.and_then(|map| {
map.values()
.filter(|item| item.information.variable_type == VariableType::Input)
.find(|item| item.information.location == index)
})
}

pub fn find_variable(
@@ -260,7 +262,7 @@ impl Index {
}

pub fn find_type(&self, type_name: &str) -> Option<&DataType> {
self.types.get(type_name)
self.types.get(&type_name.to_lowercase())
}

pub fn find_effective_type_by_name(&self, type_name: &str) -> Option<&DataType> {
@@ -322,7 +324,7 @@ impl Index {
}

pub fn find_return_variable(&self, pou_name: &str) -> Option<&VariableIndexEntry> {
let members = self.member_variables.get(pou_name); //.ok_or_else(||CompileError::unknown_type(pou_name, 0..0))?;
let members = self.member_variables.get(&pou_name.to_lowercase()); //.ok_or_else(||CompileError::unknown_type(pou_name, 0..0))?;
if let Some(members) = members {
for (_, variable) in members {
if variable.information.variable_type == VariableType::Return {
@@ -351,7 +353,8 @@ impl Index {
.ok_or_else(|| CompileError::unknown_type(type_name, SourceRange::undefined()))
}

pub fn get_types(&self) -> &IndexMap<String, DataType> {
/// Returns a list of types, should not be used to search for types, just to react on them
pub(crate) fn get_types(&self) -> &IndexMap<String, DataType> {
&self.types
}

@@ -370,7 +373,7 @@ impl Index {
impl_type: ImplementationType,
) {
self.implementations.insert(
call_name.into(),
call_name.to_lowercase(),
ImplementationIndexEntry {
call_name: call_name.into(),
type_name: type_name.into(),
@@ -380,7 +383,7 @@ impl Index {
}

pub fn find_implementation(&self, call_name: &str) -> Option<&ImplementationIndexEntry> {
self.implementations.get(call_name)
self.implementations.get(&call_name.to_lowercase())
}

/// registers a member-variable of a container to be accessed in a qualified name.
@@ -407,7 +410,7 @@ impl Index {

let members = self
.member_variables
.entry(container_name.into())
.entry(container_name.to_lowercase())
.or_insert_with(IndexMap::new);

let qualified_name = format!("{}.{}", container_name, variable_name);
@@ -424,7 +427,7 @@ impl Index {
location,
},
};
members.insert(variable_name.into(), entry);
members.insert(variable_name.to_lowercase(), entry);
}

pub fn register_global_variable(
@@ -466,7 +469,8 @@ impl Index {
location: 0,
},
};
self.global_variables.insert(association_name.into(), entry);
self.global_variables
.insert(association_name.to_lowercase(), entry);
}

pub fn print_global_variables(&self) {
@@ -484,7 +488,7 @@ impl Index {
initial_value,
information,
};
self.types.insert(type_name.into(), index_entry);
self.types.insert(type_name.to_lowercase(), index_entry);
}

pub fn find_callable_instance_variable(
45 changes: 43 additions & 2 deletions src/index/tests/index_tests.rs
Original file line number Diff line number Diff line change
@@ -19,6 +19,47 @@ fn lex(source: &str) -> lexer::ParseSession {
lexer::lex(source)
}

#[test]
fn index_not_case_sensitive() {
let index = index!(
r#"
TYPE st : STRUCT
x : INT;
y : DINT;
END_STRUCT
END_TYPE

VAR_GLOBAL
a: INT;
x : ST;
END_VAR
FUNCTION foo : INT
END_FUNCTION

PROGRAM aProgram
VAR
c,d : INT;
END_VAR
END_PROGRAM
"#
);

let entry = index.find_global_variable("A").unwrap();
assert_eq!("a", entry.name);
assert_eq!("INT", entry.information.data_type_name);
let entry = index.find_global_variable("X").unwrap();
assert_eq!("x", entry.name);
assert_eq!("ST", entry.information.data_type_name);
let entry = index.find_member("ST", "X").unwrap();
assert_eq!("x", entry.name);
assert_eq!("INT", entry.information.data_type_name);
let entry = index.find_type("APROGRAM").unwrap();
assert_eq!("aProgram", entry.name);
let entry = index.find_implementation("Foo").unwrap();
assert_eq!("foo", entry.call_name);
assert_eq!("foo", entry.type_name);
}

#[test]
fn global_variables_are_indexed() {
let index = index!(
@@ -1152,7 +1193,7 @@ fn sub_range_boundaries_are_registered_at_the_index() {
let index = index!(src);

// THEN I expect the index to contain the defined range-information for the given type
let my_int = &index.get_types().get("MyInt").unwrap().information;
let my_int = &index.get_type("MyInt").unwrap().information;
let expected = &DataTypeInformation::SubRange {
name: "MyInt".to_string(),
referenced_type: "INT".to_string(),
@@ -1170,7 +1211,7 @@ fn sub_range_boundaries_are_registered_at_the_index() {
assert_eq!(format!("{:?}", expected), format!("{:?}", my_int));

// THEN I expect the index to contain the defined range-information for the given type
let my_int = &index.get_types().get("MyAliasInt").unwrap().information;
let my_int = &index.get_type("MyAliasInt").unwrap().information;
let expected = &DataTypeInformation::Alias {
name: "MyAliasInt".to_string(),
referenced_type: "MyInt".to_string(),
4 changes: 3 additions & 1 deletion src/index/visitor.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,9 @@ pub fn visit(unit: &CompilationUnit) -> Index {
//Create the typesystem
let builtins = get_builtin_types();
for data_type in builtins {
index.types.insert(data_type.get_name().into(), data_type);
index
.types
.insert(data_type.get_name().to_lowercase(), data_type);
}

//Create user defined datatypes
2 changes: 2 additions & 0 deletions src/lexer.rs
Original file line number Diff line number Diff line change
@@ -118,6 +118,8 @@ impl<'a> ParseSession<'a> {
| Token::KeywordVarOutput
| Token::KeywordVarGlobal
| Token::KeywordVarInOut
| Token::KeywordVarTemp
| Token::KeywordNonRetain
| Token::KeywordEndVar
| Token::KeywordEndProgram
| Token::KeywordEndFunction
Loading