Skip to content

Commit

Permalink
Merge pull request #6 from mrLSD/feat/extend-tests-v0.2.3
Browse files Browse the repository at this point in the history
Feat: extend tests for `func-call` and `let-binding`
  • Loading branch information
mrLSD committed Oct 9, 2023
2 parents 0490a1b + ea5d075 commit 2992080
Show file tree
Hide file tree
Showing 6 changed files with 466 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
- name: Run grcov
run: |
mkdir ./target/debug/coverage/
grcov . -s . -b ./target/debug/ -o ./target/debug/coverage/
grcov . -s . -b ./target/debug/ -o ./target/debug/coverage/ --ignore-not-existing --excl-line="grcov-excl-line|#\\[derive\\(|//!|///" --ignore="*.cargo/*" --ignore="src/lib.rs"
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "semantic-analyzer"
version = "0.2.2"
version = "0.2.3"
authors = ["Evgeny Ukhanov <mrlsd@ya.ru>"]
description = "Semantic analyzer library for compilers written in Rust for semantic analysis of programming languages AST"
keywords = ["compiler", "semantic-analisis", "semantic-alalyzer", "compiler-design", "semantic"]
Expand Down
119 changes: 119 additions & 0 deletions tests/function_call_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use crate::utils::SemanticTest;
use semantic_analyzer::ast;
use semantic_analyzer::ast::{CodeLocation, GetLocation, Ident};
use semantic_analyzer::types::block_state::BlockState;
use semantic_analyzer::types::error::StateErrorKind;
use semantic_analyzer::types::types::{PrimitiveTypes, Type};
use semantic_analyzer::types::FunctionCall;
use std::cell::RefCell;
use std::rc::Rc;

mod utils;

#[test]
fn func_call_transform() {
let fn_name = ast::FunctionName::new(Ident::new("fn1"));
let fn_call = ast::FunctionCall {
name: fn_name.clone(),
parameters: vec![],
};
let fn_call_into: FunctionCall = fn_call.clone().into();
assert_eq!(fn_call.location(), CodeLocation::new(1, 0));
assert_eq!(fn_call.name.to_string(), "fn1");
assert_eq!(fn_call_into.to_string(), "fn1");
assert!(fn_call_into.parameters.is_empty());

let param1 = ast::Expression {
expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Ptr),
operation: None,
};
let fn_call2 = ast::FunctionCall {
name: fn_name.clone(),
parameters: vec![param1.clone()],
};
let fn_call_into2: FunctionCall = fn_call2.clone().into();
assert_eq!(fn_call_into2.parameters.len(), 1);
assert_eq!(fn_call_into2.parameters[0], param1.into());
}

#[test]
fn func_call_not_declared_func() {
let block_state = Rc::new(RefCell::new(BlockState::new(None)));
let mut t = SemanticTest::new();
let fn_name = ast::FunctionName::new(Ident::new("fn1"));
let param1 = ast::Expression {
expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Ptr),
operation: None,
};
let fn_call = ast::FunctionCall {
name: fn_name.clone(),
parameters: vec![param1.clone()],
};
let res = t.state.function_call(&fn_call, &block_state);
assert!(res.is_none());
assert!(t.check_errors_len(1));
assert!(t.check_error(StateErrorKind::FunctionNotFound));
}

#[test]
fn func_call_wrong_type() {
let block_state = Rc::new(RefCell::new(BlockState::new(None)));
let mut t = SemanticTest::new();
let fn_name = ast::FunctionName::new(Ident::new("fn1"));
let fn_decl_param1 = ast::FunctionParameter {
name: ast::ParameterName::new(Ident::new("x")),
parameter_type: ast::Type::Primitive(ast::PrimitiveTypes::Bool),
};
let fn_statement = ast::FunctionStatement {
name: fn_name.clone(),
parameters: vec![fn_decl_param1],
result_type: ast::Type::Primitive(ast::PrimitiveTypes::I16),
body: vec![],
};
t.state.function_declaration(&fn_statement);
assert!(t.is_empty_error());

let param1 = ast::Expression {
expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::F64(1.2)),
operation: None,
};
let fn_call = ast::FunctionCall {
name: fn_name.clone(),
parameters: vec![param1.clone()],
};
let res = t.state.function_call(&fn_call, &block_state).unwrap();
assert_eq!(res, Type::Primitive(PrimitiveTypes::I16));
assert!(t.check_errors_len(1));
assert!(t.check_error(StateErrorKind::FunctionParameterTypeWrong));
}

#[test]
fn func_call_declared_func() {
let block_state = Rc::new(RefCell::new(BlockState::new(None)));
let mut t = SemanticTest::new();
let fn_name = ast::FunctionName::new(Ident::new("fn1"));
let fn_decl_param1 = ast::FunctionParameter {
name: ast::ParameterName::new(Ident::new("x")),
parameter_type: ast::Type::Primitive(ast::PrimitiveTypes::Bool),
};
let fn_statement = ast::FunctionStatement {
name: fn_name.clone(),
parameters: vec![fn_decl_param1],
result_type: ast::Type::Primitive(ast::PrimitiveTypes::I32),
body: vec![],
};
t.state.function_declaration(&fn_statement);
assert!(t.is_empty_error());

let param1 = ast::Expression {
expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)),
operation: None,
};
let fn_call = ast::FunctionCall {
name: fn_name.clone(),
parameters: vec![param1.clone()],
};
let res = t.state.function_call(&fn_call, &block_state).unwrap();
assert_eq!(res, Type::Primitive(PrimitiveTypes::I32));
assert!(t.is_empty_error());
}
2 changes: 1 addition & 1 deletion tests/function_declaration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn function_declaration_without_body() {
}

#[test]
fn function_declaration_wrong_typecd() {
fn function_declaration_wrong_type() {
let mut t = SemanticTest::new();
let fn_name = ast::FunctionName::new(Ident::new("fn2"));

Expand Down
168 changes: 168 additions & 0 deletions tests/lbinding_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
use crate::utils::SemanticTest;
use semantic_analyzer::ast;
use semantic_analyzer::ast::{CodeLocation, GetLocation, GetName, Ident, ValueName};
use semantic_analyzer::types::block_state::BlockState;
use semantic_analyzer::types::error::StateErrorKind;
use semantic_analyzer::types::expression::{ExpressionResult, ExpressionResultValue};
use semantic_analyzer::types::semantic::SemanticStackContext;
use semantic_analyzer::types::types::{PrimitiveTypes, Type};
use semantic_analyzer::types::{Binding, InnerValueName, PrimitiveValue, Value};
use std::cell::RefCell;
use std::rc::Rc;

mod utils;

#[test]
fn binding_transform() {
let expr_ast = ast::Expression {
expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::U64(3)),
operation: None,
};
let binding_ast = ast::Binding {
name: ast::ValueName::new(Ident::new("x")),
value: Box::new(expr_ast.clone()),
};
assert_eq!(binding_ast.location(), CodeLocation::new(1, 0));
assert_eq!(binding_ast.clone().name(), "x");

let binding: Binding = binding_ast.clone().into();
assert_eq!(binding.clone().to_string(), "x");
assert_eq!(binding.value, Box::new(expr_ast.into()));
// For grcov
format!("{:?}", binding_ast.clone());
}

#[test]
fn binding_wrong_expression() {
let block_state = Rc::new(RefCell::new(BlockState::new(None)));
let mut t = SemanticTest::new();
let expr = ast::Expression {
expression_value: ast::ExpressionValue::ValueName(ast::ValueName::new(Ident::new("x"))),
operation: None,
};
let binding = ast::Binding {
name: ast::ValueName::new(Ident::new("x")),
value: Box::new(expr),
};
t.state.binding(&binding, &block_state);
assert!(t.check_errors_len(1));
assert!(t.check_error(StateErrorKind::ValueNotFound));
}

#[test]
fn binding_value_not_exist() {
let block_state = Rc::new(RefCell::new(BlockState::new(None)));
let mut t = SemanticTest::new();
let expr = ast::Expression {
expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::I16(23)),
operation: None,
};
let binding = ast::Binding {
name: ast::ValueName::new(Ident::new("x")),
value: Box::new(expr),
};
t.state.binding(&binding, &block_state);
assert!(t.check_errors_len(1));
assert!(t.check_error(StateErrorKind::ValueNotFound));
}

#[test]
fn binding_value_not_mutable() {
let block_state = Rc::new(RefCell::new(BlockState::new(None)));
let mut t = SemanticTest::new();
let expr = ast::Expression {
expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::U64(30)),
operation: None,
};
let let_binding = ast::LetBinding {
name: ast::ValueName::new(Ident::new("x")),
mutable: false,
value_type: Some(ast::Type::Primitive(ast::PrimitiveTypes::U64)),
value: Box::new(expr.clone()),
};
t.state.let_binding(&let_binding, &block_state);
assert!(t.is_empty_error());
let inner_name: InnerValueName = "x.0".into();
let val = Value {
inner_name: inner_name.clone(),
inner_type: Type::Primitive(PrimitiveTypes::U64),
mutable: false,
alloca: false,
malloc: false,
};

let state = block_state.borrow().context.clone().get();
assert_eq!(state.len(), 1);
assert_eq!(
state[0],
SemanticStackContext::LetBinding {
let_decl: val.clone(),
expr_result: ExpressionResult {
expr_type: Type::Primitive(PrimitiveTypes::U64),
expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::U64(30))
},
}
);
assert!(block_state.borrow().inner_values_name.contains(&inner_name));
assert_eq!(
block_state.borrow().values.get(&("x".into())).unwrap(),
&val
);
let binding = ast::Binding {
name: ValueName::new(Ident::new("x")),
value: Box::new(expr),
};
t.state.binding(&binding, &block_state);
assert!(t.check_errors_len(1));
assert!(t.check_error(StateErrorKind::ValueIsNotMutable));
}

#[test]
fn binding_value_found() {
let block_state = Rc::new(RefCell::new(BlockState::new(None)));
let mut t = SemanticTest::new();
let expr = ast::Expression {
expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::U64(30)),
operation: None,
};
let let_binding = ast::LetBinding {
name: ast::ValueName::new(Ident::new("x")),
mutable: true,
value_type: Some(ast::Type::Primitive(ast::PrimitiveTypes::U64)),
value: Box::new(expr.clone()),
};
t.state.let_binding(&let_binding, &block_state);
assert!(t.is_empty_error());
let inner_name: InnerValueName = "x.0".into();
let val = Value {
inner_name: inner_name.clone(),
inner_type: Type::Primitive(PrimitiveTypes::U64),
mutable: true,
alloca: false,
malloc: false,
};

let state = block_state.borrow().context.clone().get();
assert_eq!(state.len(), 1);
assert_eq!(
state[0],
SemanticStackContext::LetBinding {
let_decl: val.clone(),
expr_result: ExpressionResult {
expr_type: Type::Primitive(PrimitiveTypes::U64),
expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::U64(30))
},
}
);
assert!(block_state.borrow().inner_values_name.contains(&inner_name));
assert_eq!(
block_state.borrow().values.get(&("x".into())).unwrap(),
&val
);
let binding = ast::Binding {
name: ValueName::new(Ident::new("x")),
value: Box::new(expr),
};
t.state.binding(&binding, &block_state);
assert!(t.is_empty_error());
}
Loading

0 comments on commit 2992080

Please sign in to comment.