├── .gitignore ├── .github ├── actions-rs │ └── grcov.yml └── workflows │ ├── lints.yml │ └── tests.yml ├── tests ├── import_tests.rs ├── errors_tests.rs ├── utils │ └── mod.rs ├── function_declaration_tests.rs ├── function_call_tests.rs ├── let_binding_tests.rs ├── const_tests.rs ├── binding_tests.rs ├── state_tests.rs ├── types_tests.rs ├── codec_tests.rs ├── loop_tests.rs └── main_tests.rs ├── Cargo.toml ├── LICENSE ├── src ├── lib.rs └── types │ ├── error.rs │ ├── expression.rs │ ├── types.rs │ ├── condition.rs │ ├── mod.rs │ ├── block_state.rs │ └── semantic.rs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea/ 3 | Makefile 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /.github/actions-rs/grcov.yml: -------------------------------------------------------------------------------- 1 | output-type: lcov 2 | output-path: /root/lcov.info 3 | -------------------------------------------------------------------------------- /tests/import_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::SemanticTest; 2 | use semantic_analyzer::ast::{self, GetName}; 3 | 4 | mod utils; 5 | 6 | #[test] 7 | fn import_ast_transform() { 8 | let import_name_ast = ast::ImportName::new(ast::Ident::new("import1")); 9 | let imports = [import_name_ast.clone()]; 10 | assert_eq!(imports.len(), 1); 11 | assert_eq!(import_name_ast.name(), "import1"); 12 | let x: ast::ImportPath = vec![import_name_ast]; 13 | assert_eq!(x.len(), 1); 14 | let t = SemanticTest::new(); 15 | t.state.import(&x); 16 | } 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "semantic-analyzer" 3 | version = "0.4.6" 4 | authors = ["Evgeny Ukhanov "] 5 | description = "Semantic analyzer library for compilers written in Rust for semantic analysis of programming languages AST" 6 | keywords = ["compiler", "semantic-analisis", "semantic-alalyzer", "compiler-design", "semantic"] 7 | categories = ["compilers", "development-tools", "development-tools::build-utils"] 8 | license = "MIT" 9 | edition = "2021" 10 | homepage = "https://github.com/mrLSD/semantic-analyzer-rs" 11 | repository = "https://github.com/mrLSD/semantic-analyzer-rs" 12 | 13 | [lib] 14 | doctest = false 15 | 16 | [dependencies] 17 | nom_locate = "5.0" 18 | serde = { version = "1", features = ["derive"], optional = true } 19 | 20 | [dev-dependencies] 21 | serde_json = "1" 22 | 23 | [features] 24 | codec = ["serde"] 25 | -------------------------------------------------------------------------------- /tests/errors_tests.rs: -------------------------------------------------------------------------------- 1 | use semantic_analyzer::ast::CodeLocation; 2 | use semantic_analyzer::types::error::{StateErrorKind, StateErrorLocation, StateErrorResult}; 3 | 4 | #[test] 5 | fn error_trace() { 6 | let err_res = StateErrorResult::new( 7 | StateErrorKind::Common, 8 | "test".to_string(), 9 | CodeLocation::new(1, 1), 10 | ); 11 | assert_eq!(err_res.value, "test".to_string()); 12 | assert_eq!(err_res.kind, StateErrorKind::Common); 13 | assert_eq!(err_res.trace_state(), "[Common] for value \"test\" at: 1:1"); 14 | 15 | let err_res2 = StateErrorResult { 16 | kind: StateErrorKind::ReturnNotFound, 17 | value: "test2".to_string(), 18 | location: StateErrorLocation(CodeLocation::new(2, 2)), 19 | }; 20 | assert_eq!( 21 | err_res2.trace_state(), 22 | "[ReturnNotFound] for value \"test2\" at: 2:2" 23 | ); 24 | let errs = [err_res, err_res2.clone()]; 25 | assert_eq!(errs.len(), 2); 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/lints.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | - develop 6 | pull_request: 7 | 8 | name: Lints 9 | jobs: 10 | lint: 11 | name: Lint 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | os: 16 | - ubuntu-latest 17 | rust: 18 | - nightly 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 1 24 | - uses: actions-rs/toolchain@v1 25 | with: 26 | profile: minimal 27 | toolchain: ${{ matrix.rust }} 28 | override: true 29 | components: rustfmt, clippy 30 | - name: Format 31 | run: cargo fmt --all -- --check 32 | - name: Clippy no-default-features 33 | run: cargo +nightly clippy --all --all-targets --no-default-features -- -D warnings 34 | - name: Clippy 35 | run: cargo +nightly clippy --all --all-targets --all-features -- -D warnings 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Evgeny Ukhanov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(clippy::pedantic, clippy::nursery, clippy::as_conversions)] 2 | #![allow( 3 | clippy::module_name_repetitions, 4 | clippy::doc_lazy_continuation, 5 | clippy::too_long_first_doc_paragraph 6 | )] 7 | //! # Semantic Analyzer 8 | //! The semantic analyzer consists of the following basic elements: 9 | //! - AST is an abstract syntax tree that implements a predefined set of 10 | //! representations in a programming language. This is the basis for 11 | //! semantic analysis. 12 | //! - Semantic analyzer - AST based semantic analyzes generates a 13 | //! Semantic State Stack and semantic representation context for 14 | //! logical semantic blocks. Contains all the necessary results of 15 | //! semantic analysis, including: 16 | //! - constants 17 | //! - types 18 | //! - functions 19 | //! 20 | //! For the body of functions, the analysis of the semantic logic of the 21 | //! function and the generation of Block State context trees are fully implemented. 22 | //! 23 | //! Based on this Semantic context data, additional analysis in the form of linters, 24 | //! optimizers, and code generation can be implemented. 25 | 26 | /// AST representation 27 | pub mod ast; 28 | /// Semantic analyzer and State related functions 29 | pub mod semantic; 30 | /// Semantic analyzer common types 31 | pub mod types; 32 | -------------------------------------------------------------------------------- /src/types/error.rs: -------------------------------------------------------------------------------- 1 | //! # Errors types 2 | //! Errors types for Semantic analyzer result of Error state. 3 | 4 | use crate::ast::CodeLocation; 5 | #[cfg(feature = "codec")] 6 | use serde::{Deserialize, Serialize}; 7 | 8 | /// Common errors kind for the State. 9 | #[derive(Debug, Clone, Eq, PartialEq)] 10 | #[cfg_attr( 11 | feature = "codec", 12 | derive(Serialize, Deserialize), 13 | serde(tag = "type", content = "content") 14 | )] 15 | pub enum StateErrorKind { 16 | /// Common error indicate errors in the State 17 | Common, 18 | ConstantAlreadyExist, 19 | ConstantNotFound, 20 | WrongLetType, 21 | WrongExpressionType, 22 | TypeAlreadyExist, 23 | FunctionAlreadyExist, 24 | ValueNotFound, 25 | ValueNotStruct, 26 | ValueNotStructField, 27 | ValueIsNotMutable, 28 | FunctionNotFound, 29 | FunctionParameterTypeWrong, 30 | ReturnNotFound, 31 | ReturnAlreadyCalled, 32 | IfElseDuplicated, 33 | TypeNotFound, 34 | WrongReturnType, 35 | ConditionExpressionWrongType, 36 | ConditionIsEmpty, 37 | ConditionExpressionNotSupported, 38 | ForbiddenCodeAfterReturnDeprecated, 39 | ForbiddenCodeAfterContinueDeprecated, 40 | ForbiddenCodeAfterBreakDeprecated, 41 | FunctionArgumentNameDuplicated, 42 | } 43 | 44 | /// State error location. Useful to determine location of error 45 | #[derive(Debug, Clone, Eq, PartialEq)] 46 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 47 | pub struct StateErrorLocation(pub CodeLocation); 48 | 49 | /// State error result data representation 50 | #[derive(Debug, Clone, Eq, PartialEq)] 51 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 52 | pub struct StateErrorResult { 53 | /// Kind of error 54 | pub kind: StateErrorKind, 55 | /// Error value 56 | pub value: String, 57 | /// Error location 58 | pub location: StateErrorLocation, 59 | } 60 | 61 | impl StateErrorResult { 62 | #[must_use] 63 | pub const fn new(kind: StateErrorKind, value: String, location: CodeLocation) -> Self { 64 | Self { 65 | kind, 66 | value, 67 | location: StateErrorLocation(location), 68 | } 69 | } 70 | } 71 | 72 | impl StateErrorResult { 73 | /// Get state trace data from error result as string 74 | #[must_use] 75 | pub fn trace_state(&self) -> String { 76 | format!( 77 | "[{:?}] for value {:?} at: {:?}:{:?}", 78 | self.kind, 79 | self.value, 80 | self.location.0.line(), 81 | self.location.0.offset() 82 | ) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - master 5 | - develop 6 | pull_request: 7 | 8 | name: Tests 9 | jobs: 10 | test: 11 | name: Tests 12 | runs-on: ${{ matrix.os }} 13 | strategy: 14 | matrix: 15 | os: 16 | - ubuntu-latest 17 | rust: 18 | - nightly 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 1 24 | - uses: actions-rs/toolchain@v1 25 | with: 26 | profile: minimal 27 | toolchain: ${{ matrix.rust }} 28 | override: true 29 | components: rustfmt, clippy 30 | - name: Restore cache 31 | uses: actions/cache/restore@v3 32 | with: 33 | path: | 34 | ~/.cargo/bin/ 35 | ~/.cargo/registry/index/ 36 | ~/.cargo/registry/cache/ 37 | ~/.cargo/git/db/ 38 | key: ${{ runner.os }}-cargo 39 | - name: Build 40 | run: cargo build --all-features 41 | - name: Test 42 | run: cargo test --all-targets --all-features 43 | # env: 44 | # CARGO_INCREMENTAL: '0' 45 | # RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Cllvm-args=--inline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort' 46 | # RUSTDOCFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Cllvm-args=--inline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort' 47 | # - name: Install grcov 48 | # run: | 49 | # if [[ ! -f ~/.cargo/bin/grcov ]]; then 50 | # cargo install grcov 51 | # fi 52 | - name: Save cache 53 | uses: actions/cache/save@v3 54 | with: 55 | path: | 56 | ~/.cargo/bin/ 57 | ~/.cargo/registry/index/ 58 | ~/.cargo/registry/cache/ 59 | ~/.cargo/git/db/ 60 | key: ${{ runner.os }}-cargo 61 | # - name: Run grcov 62 | # run: | 63 | # mkdir ./target/debug/coverage/ 64 | # grcov . -s . -b ./target/debug/ -o ./target/debug/coverage/ --ignore-not-existing --excl-line="grcov-excl-line|#\\[derive\\(|//!|///" --excl-start="grcov-excl-start" --excl-stop="grcov-excl-end" --ignore="*.cargo/*" --ignore="src/lib.rs" --ignore="tests/*" 65 | # - name: Upload coverage reports to Codecov 66 | # uses: codecov/codecov-action@v3 67 | # env: 68 | # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 69 | # with: 70 | # directory: ./target/debug/coverage/ 71 | # files: ./target/debug/coverage/lcov 72 | # verbose: true 73 | # fail_ci_if_error: true 74 | -------------------------------------------------------------------------------- /tests/utils/mod.rs: -------------------------------------------------------------------------------- 1 | use semantic_analyzer::semantic::State; 2 | use semantic_analyzer::types::block_state::BlockState; 3 | use semantic_analyzer::types::error::StateErrorKind; 4 | use semantic_analyzer::types::expression::{ExpressionResult, ExpressionResultValue}; 5 | use semantic_analyzer::types::semantic::{ExtendedExpression, SemanticContextInstruction}; 6 | use semantic_analyzer::types::types::{PrimitiveTypes, Type}; 7 | use semantic_analyzer::types::PrimitiveValue; 8 | #[cfg(feature = "codec")] 9 | use serde::{Deserialize, Serialize}; 10 | use std::cell::RefCell; 11 | use std::marker::PhantomData; 12 | use std::rc::Rc; 13 | 14 | #[derive(Clone, Debug, PartialEq)] 15 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 16 | pub struct CustomExpression { 17 | _marker: PhantomData, 18 | } 19 | 20 | impl ExtendedExpression for CustomExpression { 21 | fn expression( 22 | &self, 23 | _state: &mut State, 24 | _block_state: &Rc>>, 25 | ) -> ExpressionResult { 26 | ExpressionResult { 27 | expr_type: Type::Primitive(PrimitiveTypes::Ptr), 28 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Ptr), 29 | } 30 | } 31 | } 32 | 33 | #[derive(Debug, Clone, PartialEq)] 34 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 35 | pub struct CustomExpressionInstruction; 36 | 37 | impl SemanticContextInstruction for CustomExpressionInstruction {} 38 | 39 | pub struct SemanticTest { 40 | pub state: State, I>, 41 | } 42 | 43 | impl Default for SemanticTest { 44 | fn default() -> Self { 45 | Self::new() 46 | } 47 | } 48 | 49 | impl SemanticTest { 50 | pub fn new() -> Self { 51 | Self { 52 | state: State::new(), 53 | } 54 | } 55 | 56 | #[allow(dead_code)] 57 | pub fn is_empty_error(&self) -> bool { 58 | self.state.errors.is_empty() 59 | } 60 | 61 | #[allow(dead_code)] 62 | pub fn clean_errors(&mut self) { 63 | self.state.errors = vec![] 64 | } 65 | 66 | #[allow(dead_code)] 67 | pub fn check_errors_len(&self, len: usize) -> bool { 68 | self.state.errors.len() == len 69 | } 70 | 71 | #[allow(dead_code)] 72 | pub fn check_error(&self, err_kind: StateErrorKind) -> bool { 73 | self.state.errors.first().unwrap().kind == err_kind 74 | } 75 | 76 | #[allow(dead_code)] 77 | pub fn check_error_index(&self, index: usize, err_kind: StateErrorKind) -> bool { 78 | self.state.errors.get(index).unwrap().kind == err_kind 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tests/function_declaration_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::SemanticTest; 2 | use semantic_analyzer::ast::{self, CodeLocation, GetLocation, Ident}; 3 | use semantic_analyzer::types::error::StateErrorKind; 4 | use semantic_analyzer::types::semantic::SemanticStackContext; 5 | 6 | mod utils; 7 | 8 | #[test] 9 | fn function_transform_ast() { 10 | let fn_name = ast::FunctionName::new(Ident::new("fn1")); 11 | assert_eq!(fn_name.location(), CodeLocation::new(1, 0)); 12 | assert_eq!(fn_name.to_string(), "fn1"); 13 | } 14 | 15 | #[test] 16 | fn function_declaration_without_body() { 17 | let mut t = SemanticTest::new(); 18 | let fn_name = ast::FunctionName::new(Ident::new("fn1")); 19 | let fn_statement = ast::FunctionStatement::new( 20 | fn_name.clone(), 21 | vec![], 22 | ast::Type::Primitive(ast::PrimitiveTypes::I8), 23 | vec![], 24 | ); 25 | t.state.function_declaration(&fn_statement); 26 | assert!(t.is_empty_error()); 27 | assert!(t.state.global.functions.contains_key(&fn_name.into())); 28 | let state = t.state.global.context.clone().get(); 29 | assert_eq!(state.len(), 1); 30 | assert_eq!( 31 | state[0], 32 | SemanticStackContext::FunctionDeclaration { 33 | fn_decl: fn_statement.clone().into() 34 | } 35 | ); 36 | 37 | t.state.function_declaration(&fn_statement); 38 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 39 | assert!( 40 | t.check_error(StateErrorKind::FunctionAlreadyExist), 41 | "Errors: {:?}", 42 | t.state.errors[0] 43 | ); 44 | } 45 | 46 | #[test] 47 | fn function_declaration_wrong_type() { 48 | let mut t = SemanticTest::new(); 49 | let fn_name = ast::FunctionName::new(Ident::new("fn2")); 50 | 51 | let type_decl = ast::StructTypes { 52 | name: Ident::new("type1"), 53 | attributes: vec![], 54 | }; 55 | 56 | let fn_statement = ast::FunctionStatement::new( 57 | fn_name.clone(), 58 | vec![ast::FunctionParameter { 59 | name: ast::ParameterName::new(Ident::new("x")), 60 | parameter_type: ast::Type::Primitive(ast::PrimitiveTypes::I64), 61 | }], 62 | ast::Type::Struct(type_decl.clone()), 63 | vec![], 64 | ); 65 | t.state.function_declaration(&fn_statement); 66 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 67 | assert!( 68 | t.check_error(StateErrorKind::TypeNotFound), 69 | "Errors: {:?}", 70 | t.state.errors[0] 71 | ); 72 | 73 | assert!(!t 74 | .state 75 | .global 76 | .functions 77 | .contains_key(&fn_name.clone().into())); 78 | let state = t.state.global.context.clone().get(); 79 | assert_eq!(state.len(), 0); 80 | 81 | let fn_statement2 = ast::FunctionStatement::new( 82 | fn_statement.name, 83 | vec![ast::FunctionParameter { 84 | name: ast::ParameterName::new(Ident::new("x")), 85 | parameter_type: ast::Type::Struct(type_decl.clone()), 86 | }], 87 | ast::Type::Primitive(ast::PrimitiveTypes::I64), 88 | fn_statement.body, 89 | ); 90 | t.state.function_declaration(&fn_statement2); 91 | assert!(t.check_errors_len(2), "Errors: {:?}", t.state.errors.len()); 92 | assert!(t.check_error_index(1, StateErrorKind::TypeNotFound)); 93 | t.clean_errors(); 94 | 95 | t.state.types(&type_decl); 96 | assert!(t.is_empty_error()); 97 | t.state.function_declaration(&fn_statement2); 98 | assert!(t.is_empty_error()); 99 | assert!(t.state.global.functions.contains_key(&fn_name.into())); 100 | let state = t.state.global.context.clone().get(); 101 | assert_eq!(state.len(), 2); 102 | assert_eq!( 103 | state[1], 104 | SemanticStackContext::FunctionDeclaration { 105 | fn_decl: fn_statement2.into() 106 | } 107 | ); 108 | } 109 | -------------------------------------------------------------------------------- /tests/function_call_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{CustomExpression, CustomExpressionInstruction, SemanticTest}; 2 | use semantic_analyzer::ast; 3 | use semantic_analyzer::ast::{CodeLocation, GetLocation, GetName, Ident}; 4 | use semantic_analyzer::types::block_state::BlockState; 5 | use semantic_analyzer::types::error::StateErrorKind; 6 | use semantic_analyzer::types::types::{PrimitiveTypes, Type}; 7 | use semantic_analyzer::types::FunctionCall; 8 | use std::cell::RefCell; 9 | use std::rc::Rc; 10 | 11 | mod utils; 12 | 13 | #[test] 14 | fn func_call_transform() { 15 | let fn_name = ast::FunctionName::new(Ident::new("fn1")); 16 | let fn_call = ast::FunctionCall::< 17 | CustomExpressionInstruction, 18 | CustomExpression, 19 | > { 20 | name: fn_name.clone(), 21 | parameters: vec![], 22 | }; 23 | let fn_call_into: FunctionCall = fn_call.clone().into(); 24 | assert_eq!(fn_call.location(), CodeLocation::new(1, 0)); 25 | assert_eq!(fn_call.name(), "fn1"); 26 | assert_eq!(fn_call.name.to_string(), "fn1"); 27 | assert_eq!(fn_call_into.to_string(), "fn1"); 28 | assert!(fn_call_into.parameters.is_empty()); 29 | 30 | let param1 = ast::Expression { 31 | expression_value: ast::ExpressionValue::< 32 | CustomExpressionInstruction, 33 | CustomExpression, 34 | >::PrimitiveValue(ast::PrimitiveValue::Ptr), 35 | operation: None, 36 | }; 37 | let fn_call2 = ast::FunctionCall { 38 | name: fn_name.clone(), 39 | parameters: vec![param1.clone()], 40 | }; 41 | let fn_call_into2: FunctionCall = fn_call2.clone().into(); 42 | assert_eq!(fn_call_into2.parameters.len(), 1); 43 | assert_eq!(fn_call_into2.parameters[0], param1.into()); 44 | } 45 | 46 | #[test] 47 | fn func_call_not_declared_func() { 48 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 49 | let mut t = SemanticTest::new(); 50 | let fn_name = ast::FunctionName::new(Ident::new("fn1")); 51 | let param1 = ast::Expression { 52 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Ptr), 53 | operation: None, 54 | }; 55 | let fn_call = ast::FunctionCall { 56 | name: fn_name.clone(), 57 | parameters: vec![param1.clone()], 58 | }; 59 | let res = t.state.function_call(&fn_call, &block_state); 60 | assert!(res.is_none()); 61 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 62 | assert!( 63 | t.check_error(StateErrorKind::FunctionNotFound), 64 | "Errors: {:?}", 65 | t.state.errors[0] 66 | ); 67 | } 68 | 69 | #[test] 70 | fn func_call_wrong_type() { 71 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 72 | let mut t = SemanticTest::new(); 73 | let fn_name = ast::FunctionName::new(Ident::new("fn1")); 74 | let fn_decl_param1 = ast::FunctionParameter { 75 | name: ast::ParameterName::new(Ident::new("x")), 76 | parameter_type: ast::Type::Primitive(ast::PrimitiveTypes::Bool), 77 | }; 78 | let fn_statement = ast::FunctionStatement::new( 79 | fn_name.clone(), 80 | vec![fn_decl_param1], 81 | ast::Type::Primitive(ast::PrimitiveTypes::I16), 82 | vec![], 83 | ); 84 | t.state.function_declaration(&fn_statement); 85 | assert!(t.is_empty_error()); 86 | 87 | let param1 = ast::Expression { 88 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::F64(1.2)), 89 | operation: None, 90 | }; 91 | let fn_call = ast::FunctionCall { 92 | name: fn_name.clone(), 93 | parameters: vec![param1.clone()], 94 | }; 95 | let res = t.state.function_call(&fn_call, &block_state).unwrap(); 96 | assert_eq!(res, Type::Primitive(PrimitiveTypes::I16)); 97 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 98 | assert!( 99 | t.check_error(StateErrorKind::FunctionParameterTypeWrong), 100 | "Errors: {:?}", 101 | t.state.errors[0] 102 | ); 103 | } 104 | 105 | #[test] 106 | fn func_call_declared_func() { 107 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 108 | let mut t = SemanticTest::new(); 109 | let fn_name = ast::FunctionName::new(Ident::new("fn1")); 110 | let fn_decl_param1 = ast::FunctionParameter { 111 | name: ast::ParameterName::new(Ident::new("x")), 112 | parameter_type: ast::Type::Primitive(ast::PrimitiveTypes::Bool), 113 | }; 114 | let fn_statement = ast::FunctionStatement::new( 115 | fn_name.clone(), 116 | vec![fn_decl_param1], 117 | ast::Type::Primitive(ast::PrimitiveTypes::I32), 118 | vec![], 119 | ); 120 | t.state.function_declaration(&fn_statement); 121 | assert!(t.is_empty_error()); 122 | 123 | let param1 = ast::Expression { 124 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 125 | operation: None, 126 | }; 127 | let fn_call = ast::FunctionCall { 128 | name: fn_name.clone(), 129 | parameters: vec![param1.clone()], 130 | }; 131 | let res = t.state.function_call(&fn_call, &block_state).unwrap(); 132 | assert_eq!(res, Type::Primitive(PrimitiveTypes::I32)); 133 | assert!(t.is_empty_error()); 134 | } 135 | -------------------------------------------------------------------------------- /tests/let_binding_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{CustomExpression, CustomExpressionInstruction, SemanticTest}; 2 | use semantic_analyzer::ast; 3 | use semantic_analyzer::ast::{CodeLocation, GetLocation, GetName, Ident}; 4 | use semantic_analyzer::types::block_state::BlockState; 5 | use semantic_analyzer::types::error::StateErrorKind; 6 | use semantic_analyzer::types::expression::{ExpressionResult, ExpressionResultValue}; 7 | use semantic_analyzer::types::semantic::SemanticStackContext; 8 | use semantic_analyzer::types::types::{PrimitiveTypes, Type}; 9 | use semantic_analyzer::types::{InnerValueName, LetBinding, PrimitiveValue, Value}; 10 | use std::cell::RefCell; 11 | use std::rc::Rc; 12 | 13 | mod utils; 14 | 15 | #[test] 16 | fn let_binding_transform() { 17 | let expr_ast = ast::Expression { 18 | expression_value: ast::ExpressionValue::< 19 | CustomExpressionInstruction, 20 | CustomExpression, 21 | >::PrimitiveValue(ast::PrimitiveValue::U64(3)), 22 | operation: None, 23 | }; 24 | let let_binding_ast = ast::LetBinding { 25 | name: ast::ValueName::new(Ident::new("x")), 26 | mutable: true, 27 | value_type: Some(ast::Type::Primitive(ast::PrimitiveTypes::U64)), 28 | value: Box::new(expr_ast.clone()), 29 | }; 30 | assert_eq!(let_binding_ast.location(), CodeLocation::new(1, 0)); 31 | assert_eq!(let_binding_ast.clone().name(), "x"); 32 | 33 | let let_binding: LetBinding = let_binding_ast.clone().into(); 34 | assert_eq!(let_binding.clone().to_string(), "x"); 35 | assert!(let_binding.mutable); 36 | assert_eq!( 37 | let_binding.value_type, 38 | Some(Type::Primitive(PrimitiveTypes::U64)) 39 | ); 40 | assert_eq!(let_binding.value, Box::new(expr_ast.into())); 41 | // For grcov 42 | let _ = format!("{:?}", let_binding_ast.clone()); 43 | } 44 | 45 | #[test] 46 | fn let_binding_wrong_expression() { 47 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 48 | let mut t = SemanticTest::new(); 49 | let expr = ast::Expression { 50 | expression_value: ast::ExpressionValue::ValueName(ast::ValueName::new(Ident::new("x"))), 51 | operation: None, 52 | }; 53 | let let_binding = ast::LetBinding { 54 | name: ast::ValueName::new(Ident::new("x")), 55 | mutable: true, 56 | value_type: Some(ast::Type::Primitive(ast::PrimitiveTypes::U64)), 57 | value: Box::new(expr), 58 | }; 59 | t.state.let_binding(&let_binding, &block_state); 60 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 61 | assert!( 62 | t.check_error(StateErrorKind::ValueNotFound), 63 | "Errors: {:?}", 64 | t.state.errors[0] 65 | ); 66 | } 67 | 68 | #[test] 69 | fn let_binding_wrong_type() { 70 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 71 | let mut t = SemanticTest::new(); 72 | let expr = ast::Expression { 73 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 74 | operation: None, 75 | }; 76 | let let_binding = ast::LetBinding { 77 | name: ast::ValueName::new(Ident::new("x")), 78 | mutable: true, 79 | value_type: Some(ast::Type::Primitive(ast::PrimitiveTypes::U64)), 80 | value: Box::new(expr), 81 | }; 82 | t.state.let_binding(&let_binding, &block_state); 83 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 84 | assert!( 85 | t.check_error(StateErrorKind::WrongLetType), 86 | "Errors: {:?}", 87 | t.state.errors[0] 88 | ); 89 | } 90 | 91 | #[test] 92 | fn let_binding_value_not_found() { 93 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 94 | let mut t = SemanticTest::new(); 95 | let expr = ast::Expression { 96 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::U64(30)), 97 | operation: None, 98 | }; 99 | let let_binding = ast::LetBinding { 100 | name: ast::ValueName::new(Ident::new("x")), 101 | mutable: true, 102 | value_type: Some(ast::Type::Primitive(ast::PrimitiveTypes::U64)), 103 | value: Box::new(expr), 104 | }; 105 | t.state.let_binding(&let_binding, &block_state); 106 | assert!(t.is_empty_error()); 107 | let state = block_state.borrow().get_context().clone().get(); 108 | assert_eq!(state.len(), 1); 109 | let inner_name: InnerValueName = "x.0".into(); 110 | let val = Value { 111 | inner_name: inner_name.clone(), 112 | inner_type: Type::Primitive(PrimitiveTypes::U64), 113 | mutable: true, 114 | alloca: false, 115 | malloc: false, 116 | }; 117 | assert_eq!( 118 | state[0], 119 | SemanticStackContext::LetBinding { 120 | let_decl: val.clone(), 121 | expr_result: ExpressionResult { 122 | expr_type: Type::Primitive(PrimitiveTypes::U64), 123 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::U64(30)), 124 | }, 125 | } 126 | ); 127 | assert!(block_state.borrow().inner_values_name.contains(&inner_name)); 128 | assert_eq!( 129 | block_state.borrow().values.get(&("x".into())).unwrap(), 130 | &val 131 | ); 132 | } 133 | 134 | #[test] 135 | fn let_binding_value_found() { 136 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 137 | let mut t = SemanticTest::new(); 138 | let expr = ast::Expression { 139 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::U64(30)), 140 | operation: None, 141 | }; 142 | let inner_name: InnerValueName = "x.0".into(); 143 | let val = Value { 144 | inner_name: inner_name.clone(), 145 | inner_type: Type::Primitive(PrimitiveTypes::U64), 146 | mutable: true, 147 | alloca: false, 148 | malloc: false, 149 | }; 150 | block_state 151 | .borrow_mut() 152 | .values 153 | .insert("x".into(), val.clone()); 154 | let let_binding = ast::LetBinding { 155 | name: ast::ValueName::new(Ident::new("x")), 156 | mutable: true, 157 | value_type: Some(ast::Type::Primitive(ast::PrimitiveTypes::U64)), 158 | value: Box::new(expr), 159 | }; 160 | t.state.let_binding(&let_binding, &block_state); 161 | assert!(t.is_empty_error()); 162 | let state = block_state.borrow().get_context().clone().get(); 163 | assert_eq!(state.len(), 1); 164 | 165 | let val2 = Value { 166 | inner_name: "x.1".into(), 167 | ..val.clone() 168 | }; 169 | assert_eq!( 170 | state[0], 171 | SemanticStackContext::LetBinding { 172 | let_decl: val2.clone(), 173 | expr_result: ExpressionResult { 174 | expr_type: Type::Primitive(PrimitiveTypes::U64), 175 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::U64(30)), 176 | }, 177 | } 178 | ); 179 | assert!(block_state 180 | .borrow() 181 | .inner_values_name 182 | .contains(&val2.inner_name)); 183 | assert_eq!( 184 | block_state.borrow().values.get(&("x".into())).unwrap(), 185 | &val2 186 | ); 187 | } 188 | -------------------------------------------------------------------------------- /src/types/expression.rs: -------------------------------------------------------------------------------- 1 | //! # Expression types 2 | //! Expression types for Semantic analyzer result state. 3 | 4 | use super::types::Type; 5 | use super::{FunctionCall, PrimitiveValue, ValueName}; 6 | use crate::ast; 7 | use crate::types::semantic::{ExtendedExpression, SemanticContextInstruction}; 8 | #[cfg(feature = "codec")] 9 | use serde::{Deserialize, Serialize}; 10 | use std::fmt::Display; 11 | 12 | /// # Expression result 13 | /// Contains analyzing results of expression: 14 | /// - `expr_type` - result type of expression 15 | /// - `expr_value` - result value of expression 16 | #[derive(Debug, Clone, PartialEq)] 17 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 18 | pub struct ExpressionResult { 19 | /// Result type of expression 20 | pub expr_type: Type, 21 | /// Result value of expression 22 | pub expr_value: ExpressionResultValue, 23 | } 24 | 25 | /// # Expression Result Value 26 | /// Result value of expression analyze has to kind: 27 | /// - Primitive value 28 | /// - Register that contain result of expression 29 | /// evaluation or call. 30 | #[derive(Debug, Clone, PartialEq)] 31 | #[cfg_attr( 32 | feature = "codec", 33 | derive(Serialize, Deserialize), 34 | serde(tag = "type", content = "content") 35 | )] 36 | pub enum ExpressionResultValue { 37 | PrimitiveValue(PrimitiveValue), 38 | Register(u64), 39 | } 40 | 41 | /// `ExtendedExpressionValue` represent simplified string 42 | /// data of custom extended `ExpressionValue`. For now 43 | /// used only for display errors. 44 | #[derive(Debug, Clone, Eq, PartialEq)] 45 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 46 | pub struct ExtendedExpressionValue(String); 47 | 48 | /// Expression value kinds: 49 | /// - value name - initialized through let-binding 50 | /// - primitive value - most primitive value, like integers etc. 51 | /// - struct value - value of struct type 52 | /// - function call - call of function with params 53 | /// - expression - contains other expression 54 | #[derive(Debug, Clone, PartialEq)] 55 | #[cfg_attr( 56 | feature = "codec", 57 | derive(Serialize, Deserialize), 58 | serde(tag = "type", content = "content") 59 | )] 60 | pub enum ExpressionValue { 61 | ValueName(ValueName), 62 | PrimitiveValue(PrimitiveValue), 63 | StructValue(ExpressionStructValue), 64 | FunctionCall(FunctionCall), 65 | Expression(Box), 66 | ExtendedExpression(ExtendedExpressionValue), 67 | } 68 | 69 | impl Display for ExpressionValue { 70 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 71 | let str = match self { 72 | Self::ValueName(val) => val.clone().to_string(), 73 | Self::PrimitiveValue(val) => val.clone().to_string(), 74 | Self::StructValue(st_val) => st_val.clone().to_string(), 75 | Self::FunctionCall(fn_call) => fn_call.clone().to_string(), 76 | Self::Expression(val) => val.to_string(), 77 | Self::ExtendedExpression(val) => val.clone().0, 78 | }; 79 | write!(f, "{str}") 80 | } 81 | } 82 | 83 | impl> From> 84 | for ExpressionValue 85 | { 86 | fn from(value: ast::ExpressionValue<'_, I, E>) -> Self { 87 | match value { 88 | #[allow(unreachable_patterns)] 89 | ast::ExpressionValue::_marker(..) => unreachable!(), 90 | ast::ExpressionValue::ValueName(v) => Self::ValueName(v.into()), 91 | ast::ExpressionValue::PrimitiveValue(v) => Self::PrimitiveValue(v.into()), 92 | ast::ExpressionValue::StructValue(v) => Self::StructValue(v.into()), 93 | ast::ExpressionValue::FunctionCall(v) => Self::FunctionCall(v.into()), 94 | ast::ExpressionValue::Expression(v) => { 95 | Self::Expression(Box::new(v.as_ref().clone().into())) 96 | } 97 | ast::ExpressionValue::ExtendedExpression(expr) => { 98 | Self::ExtendedExpression(ExtendedExpressionValue(format!("{expr:?}"))) 99 | } 100 | } 101 | } 102 | } 103 | 104 | /// Expression value of struct type. It's represent access to 105 | /// struct attributes of values with struct type 106 | #[derive(Debug, Clone, PartialEq, Eq)] 107 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 108 | pub struct ExpressionStructValue { 109 | /// Value name for structure value 110 | pub name: ValueName, 111 | /// Value attribute for structure value 112 | pub attribute: ValueName, 113 | } 114 | 115 | impl Display for ExpressionStructValue { 116 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 117 | write!(f, "{}", self.name) 118 | } 119 | } 120 | 121 | impl From> for ExpressionStructValue { 122 | fn from(value: ast::ExpressionStructValue<'_>) -> Self { 123 | Self { 124 | name: value.name.into(), 125 | attribute: value.attribute.into(), 126 | } 127 | } 128 | } 129 | 130 | /// Basic expression operations - calculations and 131 | /// logic operations 132 | #[derive(Debug, Clone, PartialEq, Eq)] 133 | #[cfg_attr( 134 | feature = "codec", 135 | derive(Serialize, Deserialize), 136 | serde(tag = "type", content = "content") 137 | )] 138 | pub enum ExpressionOperations { 139 | Plus, 140 | Minus, 141 | Multiply, 142 | Divide, 143 | ShiftLeft, 144 | ShiftRight, 145 | And, 146 | Or, 147 | Xor, 148 | Eq, 149 | NotEq, 150 | Great, 151 | Less, 152 | GreatEq, 153 | LessEq, 154 | } 155 | 156 | impl From for ExpressionOperations { 157 | fn from(value: ast::ExpressionOperations) -> Self { 158 | match value { 159 | ast::ExpressionOperations::Plus => Self::Plus, 160 | ast::ExpressionOperations::Minus => Self::Minus, 161 | ast::ExpressionOperations::Multiply => Self::Multiply, 162 | ast::ExpressionOperations::Divide => Self::Divide, 163 | ast::ExpressionOperations::ShiftLeft => Self::ShiftLeft, 164 | ast::ExpressionOperations::ShiftRight => Self::ShiftRight, 165 | ast::ExpressionOperations::And => Self::And, 166 | ast::ExpressionOperations::Or => Self::Or, 167 | ast::ExpressionOperations::Xor => Self::Xor, 168 | ast::ExpressionOperations::Eq => Self::Eq, 169 | ast::ExpressionOperations::NotEq => Self::NotEq, 170 | ast::ExpressionOperations::Great => Self::Great, 171 | ast::ExpressionOperations::Less => Self::Less, 172 | ast::ExpressionOperations::GreatEq => Self::GreatEq, 173 | ast::ExpressionOperations::LessEq => Self::LessEq, 174 | } 175 | } 176 | } 177 | 178 | /// # Expression 179 | /// Basic expression entity representation. It contains 180 | /// `ExpressionValue` and optional operations with other 181 | /// expressions. So it's represent flat tree. 182 | #[derive(Debug, Clone, PartialEq)] 183 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 184 | pub struct Expression { 185 | /// Expression value 186 | pub expression_value: ExpressionValue, 187 | /// Optional expression operation under other `Expression` 188 | pub operation: Option<(ExpressionOperations, Box)>, 189 | } 190 | 191 | impl Display for Expression { 192 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 193 | write!(f, "{}", self.expression_value) 194 | } 195 | } 196 | 197 | impl> From> 198 | for Expression 199 | { 200 | fn from(value: ast::Expression<'_, I, E>) -> Self { 201 | Self { 202 | expression_value: value.expression_value.into(), 203 | operation: value 204 | .operation 205 | .map(|(op, expr)| (op.into(), Box::new(expr.as_ref().clone().into()))), 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /tests/const_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::SemanticTest; 2 | use semantic_analyzer::ast::{self, CodeLocation, GetLocation, GetName, Ident}; 3 | use semantic_analyzer::types::error::StateErrorKind; 4 | use semantic_analyzer::types::expression::ExpressionOperations; 5 | use semantic_analyzer::types::{ 6 | semantic::SemanticStackContext, Constant, ConstantExpression, ConstantName, ConstantValue, 7 | PrimitiveValue, 8 | }; 9 | 10 | mod utils; 11 | 12 | #[test] 13 | fn const_name_ast_transform() { 14 | let const_name_ast = ast::ConstantName::new(ast::Ident::new("cnt1")); 15 | let const_name_into1: ConstantName = const_name_ast.clone().into(); 16 | assert_eq!(const_name_ast.name(), const_name_into1.to_string()); 17 | assert_eq!(const_name_ast.name(), "cnt1".to_string()); 18 | let const_name_into2: ConstantName = String::from("cnt1").into(); 19 | assert_eq!(const_name_into1, const_name_into2); 20 | } 21 | 22 | #[test] 23 | fn const_ast_transform() { 24 | let const_name = ast::ConstantName::new(ast::Ident::new("cnt1")); 25 | let const_statement = ast::Constant { 26 | name: const_name.clone(), 27 | constant_type: ast::Type::Primitive(ast::PrimitiveTypes::I8), 28 | constant_value: ast::ConstantExpression { 29 | value: ast::ConstantValue::Value(ast::PrimitiveValue::I8(10)), 30 | operation: None, 31 | }, 32 | }; 33 | let const_semantic: Constant = const_statement.into(); 34 | assert_eq!(const_semantic.name, const_name.into()); 35 | assert_eq!( 36 | const_semantic.constant_type, 37 | ast::Type::Primitive(ast::PrimitiveTypes::I8).into() 38 | ); 39 | let cnt_val: ConstantValue = ast::ConstantValue::Value(ast::PrimitiveValue::I8(10)).into(); 40 | assert_eq!(const_semantic.constant_value.value, cnt_val); 41 | assert_eq!( 42 | const_semantic.constant_value.value, 43 | ConstantValue::Value(PrimitiveValue::I8(10)) 44 | ); 45 | assert_eq!(const_semantic.constant_value.operation, None); 46 | } 47 | 48 | #[test] 49 | fn const_value_ast_transform() { 50 | let cnt_val1: ConstantValue = ast::ConstantValue::Value(ast::PrimitiveValue::I8(10)).into(); 51 | assert_eq!(cnt_val1, ConstantValue::Value(PrimitiveValue::I8(10))); 52 | 53 | let const_name2 = ast::ConstantName::new(ast::Ident::new("cnt2")); 54 | let cnt_val2: ConstantValue = ast::ConstantValue::Constant(const_name2.clone()).into(); 55 | assert_eq!(cnt_val2, ConstantValue::Constant(const_name2.into())); 56 | } 57 | 58 | #[test] 59 | fn const_expr_ast_transform() { 60 | let cnt_expr_prev2 = ast::ConstantExpression { 61 | value: ast::ConstantValue::Constant(ast::ConstantName::new(Ident::new("cnt3"))), 62 | operation: None, 63 | }; 64 | let cnt_expr_prev = ast::ConstantExpression { 65 | value: ast::ConstantValue::Value(ast::PrimitiveValue::I16(20)), 66 | operation: Some(( 67 | ast::ExpressionOperations::Eq, 68 | Box::new(cnt_expr_prev2.clone()), 69 | )), 70 | }; 71 | let cnt_expr_ast = ast::ConstantExpression { 72 | value: ast::ConstantValue::Value(ast::PrimitiveValue::I8(10)), 73 | operation: Some(( 74 | ast::ExpressionOperations::Eq, 75 | Box::new(cnt_expr_prev.clone()), 76 | )), 77 | }; 78 | let cnt_expr: ConstantExpression = cnt_expr_ast.clone().into(); 79 | let c_val: ConstantValue = cnt_expr_ast.value.clone().into(); 80 | assert_eq!(cnt_expr.value, c_val); 81 | 82 | let expr_op: ExpressionOperations = ast::ExpressionOperations::Eq.into(); 83 | let c_val2: ConstantValue = cnt_expr_prev.value.into(); 84 | let cnt_expr_op = cnt_expr.operation.clone().unwrap(); 85 | assert_eq!(cnt_expr_op.0, expr_op); 86 | assert_eq!(cnt_expr_op.1.value, c_val2); 87 | 88 | let cnt_expr_op2 = cnt_expr_op.clone().1.operation.unwrap(); 89 | let c_val3: ConstantValue = cnt_expr_prev2.value.into(); 90 | assert_eq!(cnt_expr_op2.0, expr_op); 91 | assert_eq!(cnt_expr_op2.1.value, c_val3); 92 | let mut t = SemanticTest::new(); 93 | t.state 94 | .check_constant_value_expression(&cnt_expr_ast.operation); 95 | } 96 | 97 | #[test] 98 | fn const_declaration() { 99 | let mut t = SemanticTest::new(); 100 | let const_name = ast::ConstantName::new(ast::Ident::new("cnt1")); 101 | let const_statement = ast::Constant { 102 | name: const_name.clone(), 103 | constant_type: ast::Type::Primitive(ast::PrimitiveTypes::I8), 104 | constant_value: ast::ConstantExpression { 105 | value: ast::ConstantValue::Value(ast::PrimitiveValue::I8(10)), 106 | operation: None, 107 | }, 108 | }; 109 | t.state.constant(&const_statement); 110 | assert!(t.state.global.constants.contains_key(&const_name.into())); 111 | assert!(t.is_empty_error()); 112 | 113 | let state = t.state.global.context.clone().get(); 114 | assert_eq!(state.len(), 1); 115 | assert_eq!( 116 | state[0], 117 | SemanticStackContext::Constant { 118 | const_decl: const_statement.clone().into() 119 | } 120 | ); 121 | 122 | t.state.constant(&const_statement); 123 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 124 | assert!( 125 | t.check_error(StateErrorKind::ConstantAlreadyExist), 126 | "Errors: {:?}", 127 | t.state.errors[0] 128 | ); 129 | let state = t.state.global.context.clone().get(); 130 | assert_eq!(state.len(), 1); 131 | } 132 | 133 | #[test] 134 | fn const_declaration_with_operations() { 135 | let mut t = SemanticTest::new(); 136 | let const_name2 = ast::ConstantName::new(ast::Ident::new("cnt2")); 137 | 138 | let cnt_expr_prev2 = ast::ConstantExpression { 139 | value: ast::ConstantValue::Value(ast::PrimitiveValue::F32(1.1)), 140 | operation: None, 141 | }; 142 | 143 | let cnt_expr_prev = ast::ConstantExpression { 144 | value: ast::ConstantValue::Constant(const_name2.clone()), 145 | operation: Some((ast::ExpressionOperations::Plus, Box::new(cnt_expr_prev2))), 146 | }; 147 | 148 | // constant1 149 | let const_name1 = ast::ConstantName::new(ast::Ident::new("cnt1")); 150 | let const_statement = ast::Constant { 151 | name: const_name1.clone(), 152 | constant_type: ast::Type::Primitive(ast::PrimitiveTypes::I8), 153 | constant_value: ast::ConstantExpression { 154 | value: ast::ConstantValue::Value(ast::PrimitiveValue::I8(10)), 155 | operation: Some((ast::ExpressionOperations::Plus, Box::new(cnt_expr_prev))), 156 | }, 157 | }; 158 | assert_eq!(const_statement.location(), CodeLocation::new(1, 0)); 159 | t.state.constant(&const_statement); 160 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 161 | assert!( 162 | t.check_error(StateErrorKind::ConstantNotFound), 163 | "Errors: {:?}", 164 | t.state.errors[0] 165 | ); 166 | assert!(!t 167 | .state 168 | .global 169 | .constants 170 | .contains_key(&const_name1.clone().into())); 171 | t.clean_errors(); 172 | 173 | // constant2 174 | let const_statement2 = ast::Constant { 175 | name: const_name2.clone(), 176 | constant_type: ast::Type::Primitive(ast::PrimitiveTypes::I32), 177 | constant_value: ast::ConstantExpression { 178 | value: ast::ConstantValue::Value(ast::PrimitiveValue::I8(10)), 179 | operation: None, 180 | }, 181 | }; 182 | t.state.constant(&const_statement2); 183 | assert!(t.state.global.constants.contains_key(&const_name2.into())); 184 | 185 | t.state.constant(&const_statement); 186 | assert!(t.state.global.constants.contains_key(&const_name1.into())); 187 | assert!(t.is_empty_error()); 188 | 189 | let state = t.state.global.context.clone().get(); 190 | assert_eq!(state.len(), 2); 191 | assert_eq!( 192 | state[0], 193 | SemanticStackContext::Constant { 194 | const_decl: const_statement2.into() 195 | } 196 | ); 197 | assert_eq!( 198 | state[1], 199 | SemanticStackContext::Constant { 200 | const_decl: const_statement.into() 201 | } 202 | ); 203 | } 204 | -------------------------------------------------------------------------------- /tests/binding_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{CustomExpression, CustomExpressionInstruction, SemanticTest}; 2 | use semantic_analyzer::ast; 3 | use semantic_analyzer::ast::{CodeLocation, GetLocation, GetName, Ident, ValueName}; 4 | use semantic_analyzer::types::block_state::BlockState; 5 | use semantic_analyzer::types::error::StateErrorKind; 6 | use semantic_analyzer::types::expression::{ExpressionResult, ExpressionResultValue}; 7 | use semantic_analyzer::types::semantic::SemanticStackContext; 8 | use semantic_analyzer::types::types::{PrimitiveTypes, Type}; 9 | use semantic_analyzer::types::{Binding, InnerValueName, PrimitiveValue, Value}; 10 | use std::cell::RefCell; 11 | use std::rc::Rc; 12 | 13 | mod utils; 14 | 15 | #[test] 16 | fn binding_transform() { 17 | let expr_ast = ast::Expression { 18 | expression_value: ast::ExpressionValue::< 19 | CustomExpressionInstruction, 20 | CustomExpression, 21 | >::PrimitiveValue(ast::PrimitiveValue::U64(3)), 22 | operation: None, 23 | }; 24 | let binding_ast = ast::Binding { 25 | name: ast::ValueName::new(Ident::new("x")), 26 | value: Box::new(expr_ast.clone()), 27 | }; 28 | assert_eq!(binding_ast.location(), CodeLocation::new(1, 0)); 29 | assert_eq!(binding_ast.clone().name(), "x"); 30 | 31 | let binding: Binding = binding_ast.clone().into(); 32 | assert_eq!(binding.clone().to_string(), "x"); 33 | assert_eq!(binding.value, Box::new(expr_ast.into())); 34 | // For grcov 35 | let _ = format!("{:?}", binding_ast.clone()); 36 | } 37 | 38 | #[test] 39 | fn binding_wrong_expression() { 40 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 41 | let mut t = SemanticTest::new(); 42 | let expr = ast::Expression { 43 | expression_value: ast::ExpressionValue::< 44 | CustomExpressionInstruction, 45 | CustomExpression, 46 | >::ValueName(ast::ValueName::new(Ident::new("x"))), 47 | operation: None, 48 | }; 49 | let binding = ast::Binding { 50 | name: ast::ValueName::new(Ident::new("x")), 51 | value: Box::new(expr), 52 | }; 53 | t.state.binding(&binding, &block_state); 54 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 55 | assert!( 56 | t.check_error(StateErrorKind::ValueNotFound), 57 | "Errors: {:?}", 58 | t.state.errors[0] 59 | ); 60 | } 61 | 62 | #[test] 63 | fn binding_value_not_exist() { 64 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 65 | let mut t = SemanticTest::new(); 66 | let expr = ast::Expression { 67 | expression_value: ast::ExpressionValue::< 68 | CustomExpressionInstruction, 69 | CustomExpression, 70 | >::PrimitiveValue(ast::PrimitiveValue::I16(23)), 71 | operation: None, 72 | }; 73 | let binding = ast::Binding { 74 | name: ast::ValueName::new(Ident::new("x")), 75 | value: Box::new(expr), 76 | }; 77 | t.state.binding(&binding, &block_state); 78 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 79 | assert!( 80 | t.check_error(StateErrorKind::ValueNotFound), 81 | "Errors: {:?}", 82 | t.state.errors[0] 83 | ); 84 | } 85 | 86 | #[test] 87 | fn binding_value_not_mutable() { 88 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 89 | let mut t = SemanticTest::new(); 90 | let expr = ast::Expression { 91 | expression_value: ast::ExpressionValue::< 92 | CustomExpressionInstruction, 93 | CustomExpression, 94 | >::PrimitiveValue(ast::PrimitiveValue::U64(30)), 95 | operation: None, 96 | }; 97 | let let_binding = ast::LetBinding { 98 | name: ast::ValueName::new(Ident::new("x")), 99 | mutable: false, 100 | value_type: Some(ast::Type::Primitive(ast::PrimitiveTypes::U64)), 101 | value: Box::new(expr.clone()), 102 | }; 103 | t.state.let_binding(&let_binding, &block_state); 104 | assert!(t.is_empty_error()); 105 | let inner_name: InnerValueName = "x.0".into(); 106 | let val = Value { 107 | inner_name: inner_name.clone(), 108 | inner_type: Type::Primitive(PrimitiveTypes::U64), 109 | mutable: false, 110 | alloca: false, 111 | malloc: false, 112 | }; 113 | 114 | let state = block_state.borrow().get_context().get(); 115 | assert_eq!(state.len(), 1); 116 | assert_eq!( 117 | state[0], 118 | SemanticStackContext::LetBinding { 119 | let_decl: val.clone(), 120 | expr_result: ExpressionResult { 121 | expr_type: Type::Primitive(PrimitiveTypes::U64), 122 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::U64(30)), 123 | }, 124 | } 125 | ); 126 | assert!(block_state.borrow().inner_values_name.contains(&inner_name)); 127 | assert_eq!( 128 | block_state.borrow().values.get(&("x".into())).unwrap(), 129 | &val 130 | ); 131 | let binding = ast::Binding { 132 | name: ValueName::new(Ident::new("x")), 133 | value: Box::new(expr), 134 | }; 135 | t.state.binding(&binding, &block_state); 136 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 137 | assert!( 138 | t.check_error(StateErrorKind::ValueIsNotMutable), 139 | "Errors: {:?}", 140 | t.state.errors[0] 141 | ); 142 | } 143 | 144 | #[test] 145 | fn binding_value_found() { 146 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 147 | let mut t = SemanticTest::new(); 148 | let expr = ast::Expression { 149 | expression_value: ast::ExpressionValue::< 150 | CustomExpressionInstruction, 151 | CustomExpression, 152 | >::PrimitiveValue(ast::PrimitiveValue::U64(30)), 153 | operation: None, 154 | }; 155 | let let_binding = ast::LetBinding { 156 | name: ast::ValueName::new(Ident::new("x")), 157 | mutable: true, 158 | value_type: Some(ast::Type::Primitive(ast::PrimitiveTypes::U64)), 159 | value: Box::new(expr.clone()), 160 | }; 161 | t.state.let_binding(&let_binding, &block_state); 162 | assert!(t.is_empty_error()); 163 | let inner_name: InnerValueName = "x.0".into(); 164 | let val = Value { 165 | inner_name: inner_name.clone(), 166 | inner_type: Type::Primitive(PrimitiveTypes::U64), 167 | mutable: true, 168 | alloca: false, 169 | malloc: false, 170 | }; 171 | 172 | let state = block_state.borrow().get_context().clone().get(); 173 | assert_eq!(state.len(), 1); 174 | assert_eq!( 175 | state[0], 176 | SemanticStackContext::LetBinding { 177 | let_decl: val.clone(), 178 | expr_result: ExpressionResult { 179 | expr_type: Type::Primitive(PrimitiveTypes::U64), 180 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::U64(30)), 181 | }, 182 | } 183 | ); 184 | assert!(block_state.borrow().inner_values_name.contains(&inner_name)); 185 | assert_eq!( 186 | block_state.borrow().values.get(&("x".into())).unwrap(), 187 | &val 188 | ); 189 | let new_expr = ast::Expression { 190 | expression_value: ast::ExpressionValue::< 191 | CustomExpressionInstruction, 192 | CustomExpression, 193 | >::PrimitiveValue(ast::PrimitiveValue::U64(100)), 194 | operation: None, 195 | }; 196 | let binding = ast::Binding { 197 | name: ValueName::new(Ident::new("x")), 198 | value: Box::new(new_expr), 199 | }; 200 | t.state.binding(&binding, &block_state); 201 | assert!(t.is_empty_error()); 202 | let state = block_state.borrow().get_context().clone().get(); 203 | assert_eq!(state.len(), 2); 204 | assert_eq!( 205 | state[0], 206 | SemanticStackContext::LetBinding { 207 | let_decl: val.clone(), 208 | expr_result: ExpressionResult { 209 | expr_type: Type::Primitive(PrimitiveTypes::U64), 210 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::U64(30)), 211 | }, 212 | } 213 | ); 214 | assert_eq!( 215 | state[1], 216 | SemanticStackContext::Binding { 217 | val: val.clone(), 218 | expr_result: ExpressionResult { 219 | expr_type: Type::Primitive(PrimitiveTypes::U64), 220 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::U64(100)), 221 | }, 222 | } 223 | ); 224 | } 225 | -------------------------------------------------------------------------------- /src/types/types.rs: -------------------------------------------------------------------------------- 1 | //! # Semantic types 2 | //! Type-system types for Semantic analyzer State results. 3 | 4 | use super::{FunctionName, ValueName}; 5 | use crate::ast::{self, GetName}; 6 | #[cfg(feature = "codec")] 7 | use serde::{Deserialize, Serialize}; 8 | use std::collections::HashMap; 9 | use std::fmt::Display; 10 | 11 | /// `TypeAttributes` type attributes trait. 12 | /// Used for types declarations. 13 | pub trait TypeAttributes { 14 | /// Get attribute index by value name for the parent type 15 | fn get_attribute_index(&self, attr_name: &ValueName) -> Option; 16 | /// Get attribute type by value name for the parent type 17 | fn get_attribute_type(&self, attr_name: &ValueName) -> Option; 18 | /// Get function name for the parent type by method name 19 | fn get_method(&self, method_name: String) -> Option; 20 | /// Check is value attribute 21 | fn is_attribute(&self, name: &ValueName) -> bool; 22 | /// Check is name is method 23 | fn is_method(&self, name: String) -> bool; 24 | } 25 | 26 | /// Type name representation 27 | #[derive(Debug, Clone, Eq, Hash, PartialEq)] 28 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 29 | pub struct TypeName(String); 30 | 31 | impl GetName for TypeName { 32 | fn name(&self) -> String { 33 | self.0.clone() 34 | } 35 | } 36 | 37 | impl From for TypeName { 38 | fn from(value: String) -> Self { 39 | Self(value) 40 | } 41 | } 42 | 43 | impl Display for TypeName { 44 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 45 | write!(f, "{}", self.0.clone()) 46 | } 47 | } 48 | 49 | /// # Type 50 | /// Basic representation of Type. Basic entities: 51 | /// - primitive type 52 | /// - struct type 53 | /// - array type 54 | #[derive(Debug, Clone, Eq, PartialEq)] 55 | #[cfg_attr( 56 | feature = "codec", 57 | derive(Serialize, Deserialize), 58 | serde(tag = "type", content = "content") 59 | )] 60 | pub enum Type { 61 | Primitive(PrimitiveTypes), 62 | Struct(StructTypes), 63 | Array(Box, u32), 64 | } 65 | 66 | impl Type { 67 | /// Get type name 68 | #[must_use] 69 | pub fn name(&self) -> TypeName { 70 | self.to_string().into() 71 | } 72 | 73 | /// Get structure type if it is 74 | #[must_use] 75 | pub fn get_struct(&self) -> Option { 76 | match self { 77 | Self::Struct(ty) => Some(ty.clone()), 78 | _ => None, 79 | } 80 | } 81 | } 82 | 83 | impl Display for Type { 84 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 85 | let str = match self { 86 | Self::Primitive(primitive) => primitive.to_string(), 87 | Self::Struct(struct_type) => struct_type.name.clone(), 88 | Self::Array(array_type, size) => { 89 | format!("[{:?};{:?}]", array_type.to_string(), size) 90 | } 91 | }; 92 | write!(f, "{str}") 93 | } 94 | } 95 | 96 | impl TypeAttributes for Type { 97 | fn get_attribute_index(&self, attr_name: &ValueName) -> Option { 98 | match self { 99 | Self::Struct(st) => st.get_attribute_index(attr_name), 100 | _ => None, 101 | } 102 | } 103 | fn get_attribute_type(&self, attr_name: &ValueName) -> Option { 104 | match self { 105 | Self::Struct(st) => st.get_attribute_type(attr_name), 106 | _ => None, 107 | } 108 | } 109 | fn get_method(&self, method_name: String) -> Option { 110 | match self { 111 | Self::Struct(st) => st.get_method(method_name), 112 | _ => None, 113 | } 114 | } 115 | fn is_attribute(&self, attr_name: &ValueName) -> bool { 116 | match self { 117 | Self::Struct(st) => st.is_attribute(attr_name), 118 | _ => false, 119 | } 120 | } 121 | fn is_method(&self, method_name: String) -> bool { 122 | match self { 123 | Self::Struct(st) => st.is_method(method_name), 124 | _ => false, 125 | } 126 | } 127 | } 128 | 129 | impl From> for Type { 130 | fn from(value: ast::Type<'_>) -> Self { 131 | match value { 132 | ast::Type::Primitive(v) => Self::Primitive(v.into()), 133 | ast::Type::Struct(v) => Self::Struct(v.into()), 134 | ast::Type::Array(v, s) => Self::Array(Box::new(v.as_ref().clone().into()), s), 135 | } 136 | } 137 | } 138 | 139 | /// # Primitive types 140 | /// Most primitive type. It's basic elements for other types. 141 | #[derive(Debug, Clone, PartialEq, Eq)] 142 | #[cfg_attr( 143 | feature = "codec", 144 | derive(Serialize, Deserialize), 145 | serde(tag = "type", content = "content") 146 | )] 147 | pub enum PrimitiveTypes { 148 | U8, 149 | U16, 150 | U32, 151 | U64, 152 | I8, 153 | I16, 154 | I32, 155 | I64, 156 | F32, 157 | F64, 158 | Bool, 159 | Char, 160 | Ptr, 161 | None, 162 | } 163 | 164 | impl Display for PrimitiveTypes { 165 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 166 | let s = match self { 167 | Self::U8 => "u8", 168 | Self::U16 => "u16", 169 | Self::U32 => "u32", 170 | Self::U64 => "u64", 171 | Self::I8 => "i8", 172 | Self::I16 => "i16", 173 | Self::I32 => "i32", 174 | Self::I64 => "i64", 175 | Self::F32 => "f32", 176 | Self::F64 => "f64", 177 | Self::Bool => "bool", 178 | Self::Char => "char", 179 | Self::Ptr => "ptr", 180 | Self::None => "()", 181 | }; 182 | write!(f, "{s}") 183 | } 184 | } 185 | 186 | impl From for PrimitiveTypes { 187 | fn from(value: ast::PrimitiveTypes) -> Self { 188 | match value { 189 | ast::PrimitiveTypes::U8 => Self::U8, 190 | ast::PrimitiveTypes::U16 => Self::U16, 191 | ast::PrimitiveTypes::U32 => Self::U32, 192 | ast::PrimitiveTypes::U64 => Self::U64, 193 | ast::PrimitiveTypes::I8 => Self::I8, 194 | ast::PrimitiveTypes::I16 => Self::I16, 195 | ast::PrimitiveTypes::I32 => Self::I32, 196 | ast::PrimitiveTypes::I64 => Self::I64, 197 | ast::PrimitiveTypes::F32 => Self::F32, 198 | ast::PrimitiveTypes::F64 => Self::F64, 199 | ast::PrimitiveTypes::Bool => Self::Bool, 200 | ast::PrimitiveTypes::Char => Self::Char, 201 | ast::PrimitiveTypes::Ptr => Self::Ptr, 202 | ast::PrimitiveTypes::None => Self::None, 203 | } 204 | } 205 | } 206 | 207 | /// # Struct types 208 | /// Basic entity for struct type itself. 209 | #[derive(Debug, Clone, Eq, PartialEq)] 210 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 211 | pub struct StructTypes { 212 | /// Type name 213 | pub name: String, 214 | /// Struct attributes 215 | pub attributes: HashMap, 216 | /// Struct methods 217 | pub methods: HashMap, 218 | } 219 | 220 | impl TypeAttributes for StructTypes { 221 | fn get_attribute_index(&self, attr_name: &ValueName) -> Option { 222 | self.attributes.get(attr_name).map(|attr| attr.attr_index) 223 | } 224 | fn get_attribute_type(&self, attr_name: &ValueName) -> Option { 225 | self.attributes 226 | .get(attr_name) 227 | .map(|attr| attr.attr_type.clone()) 228 | } 229 | fn get_method(&self, method_name: String) -> Option { 230 | self.methods.get(&method_name).cloned() 231 | } 232 | fn is_attribute(&self, attr_name: &ValueName) -> bool { 233 | self.attributes.contains_key(attr_name) 234 | } 235 | fn is_method(&self, method_name: String) -> bool { 236 | self.methods.contains_key(&method_name) 237 | } 238 | } 239 | 240 | impl From> for StructTypes { 241 | fn from(value: ast::StructTypes<'_>) -> Self { 242 | Self { 243 | name: value.name(), 244 | attributes: { 245 | let mut res = HashMap::new(); 246 | for (index, val) in value.attributes.iter().enumerate() { 247 | let name = (*val.attr_name.fragment()).to_string(); 248 | let mut v: StructAttributeType = val.clone().into(); 249 | v.attr_index = u32::try_from(index).unwrap_or_default(); 250 | res.insert(name.into(), v); 251 | } 252 | res 253 | }, 254 | methods: HashMap::new(), 255 | } 256 | } 257 | } 258 | 259 | /// `StructAttributeType` is type for Struct attributes fields. 260 | #[derive(Debug, Clone, Eq, PartialEq)] 261 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 262 | pub struct StructAttributeType { 263 | /// Attribute name for struct type 264 | pub attr_name: ValueName, 265 | /// Attribute index representation for struct type 266 | pub attr_index: u32, 267 | /// Attribute type for struct type 268 | pub attr_type: Type, 269 | } 270 | 271 | impl From> for StructAttributeType { 272 | fn from(value: ast::StructType<'_>) -> Self { 273 | Self { 274 | attr_name: value.name().into(), 275 | attr_type: value.attr_type.into(), 276 | attr_index: 0, 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 2 | [![Lints](https://github.com/mrLSD/z-rose/actions/workflows/lints.yml/badge.svg)](https://github.com/mrLSD/z-rose/actions/workflows/lints.yml) 3 | [![Tests](https://github.com/mrLSD/z-rose/actions/workflows/tests.yml/badge.svg)](https://github.com/mrLSD/z-rose/actions/workflows/tests.yml) 4 | [![Crates.io version](https://img.shields.io/crates/v/semantic-analyzer.svg?style=flat-square)](https://crates.io/crates/semantic-analyzer) 5 | [![codecov](https://codecov.io/gh/mrLSD/semantic-analyzer-rs/graph/badge.svg?token=ZQ8FCYSSZX)](https://codecov.io/gh/mrLSD/semantic-analyzer-rs) 6 | 7 |
8 |

mrLSD/semantic-analyzer-rs

9 |
10 | 11 | Semantic analyzer is an open source semantic analyzer for programming languages 12 | that makes it easy to build your own efficient compilers with extensibility in mind. 13 | 14 | ## 🌀 What the library is for and what tasks it solves 15 | 16 | Creating a compilers for a programming language is process that involves several key 17 | stages. Most commonly they are: 18 | 19 | ▶️ **Lexical Analysis (Lexer)**: This stage involves breaking down the input stream 20 | of characters into a series of tokens. Tokens are the atomic elements of the programming language, such as identifiers, keywords, operators, etc. 21 | 22 | ▶️ **Syntax Analysis (Parsing)**: At this stage, the tokens obtained in the previous 23 | stage are grouped according to the grammar rules of the programming language. The result 24 | of this process is an **Abstract Syntax Tree (AST)**, which represents a hierarchical structure of the code. 25 | 26 | ⏩ **Semantic Analysis**: This stage involves checking the semantic correctness of the code. This can include 27 | type checking, scope verification of variables, etc. 28 | 29 | ▶️ **Intermediate Code Optimization**: At this stage, the compiler tries to improve the intermediate representation of the code to make it more efficient. 30 | This can include dead code elimination, expression simplification, etc. 31 | 32 | ▶️ **Code Generation**: This is the final stage where the compiler transforms the optimized intermediate representation (IR) into 33 | machine code specific to the target architecture. 34 | 35 | This library represents **Semantic Analysis** stage. 36 | 37 | ### 🌻 Features 38 | 39 | ✅ **Name Binding and Scope Checking**: The analyzer verifies that all variables, constants, functions are declared before they're used, 40 | and that they're used within their scope. It also checks for name collisions, where variables, constants, functions, types in the same scope have the same name. 41 | 42 | ✅ **Checking Function Calls**: The analyzer verifies that functions are called with the number of parameters and that the type of 43 | arguments matches the type expected by the function. 44 | 45 | ✅ **Scope Rules**: Checks that variables, functions, constants, types are used within their scope, and available in the visibility scope. 46 | 47 | ✅ **Type Checking**: The analyzer checks that operations are performed on compatible types for expressions, functions, constant, bindings. 48 | For operations in expressions. It is the process of verifying that the types of expressions are consistent with their usage in the context. 49 | 50 | ✅ **Flow Control Checking**: The analyzer checks that the control flow statements (if-else, loop, return, break, continue) are used correctly. 51 | Supported condition expressions and condition expression correctness check. 52 | 53 | ✅ **Building the Symbol Table**: For analyzing used the symbol table as data structure used by the semantic analyzer to keep track of 54 | symbols (variables, functions, constants) in the source code. Each entry in the symbol table contains the symbol's name, type, and scope related for block state, and other relevant information. 55 | 56 | ✅ **Generic expression value**: The ability to expand custom expressions for AST, 57 | according to compiler requirements. And the ability to implement custom instructions 58 | for these custom expressions in the **Semantic Stack Context**. 59 | 60 | ### 🌳 Semantic State Tree 61 | 62 | The result of executing and passing stages of the semantic analyzer is: **Semantic State Tree**. 63 | 64 | This can be used for Intermediate Code Generation, for further passes 65 | semantic tree optimizations, linting, backend codegen (like LLVM) to target machine. 66 | 67 | #### 🌲 Structure of Semantic State Tree 68 | 69 | - **blocks state** and related block state child branches. It's a basic 70 | entity for scopes: variables, blocks (function, if, loop). 71 | Especially it makes sense for expressions. This allows you to granularly separate the visibility scope 72 | and its visibility limits. In particular - all child elements can access parent elements. 73 | However, parent elements cannot access child elements, which effectively limits the visibility scope and entity usage. 74 | 75 | - **variables state**: block state entity, contains properties of variable in current 76 | state like: name, type, mutability, allocation, mallocation. 77 | 78 | - **inner variables state**: block state entity, contains inner variables names. 79 | It's useful for Intermediate Representation for codegen backends like LLVM. 80 | Where shadowed name variables should have different inner names. It means inner variables 81 | always unique. 82 | 83 | - labels state: block state entity, that contains all information about control flow labels. 84 | 85 | - **Global state**: contains global state of constants, declared functions and types. 86 | 87 | - **State entity**: contains: 88 | - Global State 89 | - Errors results 90 | - Semantic tree results 91 | 92 | All of that source data, that can be used for Intermediate Representation for next optimizations and compilers codegen. 93 | 94 | ### 🧺 Subset of programming languages 95 | 96 | The input parameter for the analyzer is a predefined 97 | AST (abstract syntax tree). As a library for building AST and the only dependency 98 | used [nom_locate](https://github.com/fflorent/nom_locate) - which allows getting 99 | all the necessary information about the source code, for further semantic analysis 100 | and generating relevant and informative error messages. Currently 101 | decided that the AST is a fixed structure because it is a fundamental 102 | element that defines the lexical representation of a programming language. 103 | 104 | On the other hand, it allows you to implement any subset of the programming language that matches 105 | syntax tree. It also implies a subset of lexical representations from which an AST can be generated 106 | that meets the initial requirements of the semantic analyzer. As a library for lexical 107 | analysis and source code parsing, it is recommended to use: [nom is a parser combinators library](https://github.com/rust-bakery/nom). 108 | 109 | AST displays the **Turing complete** programming language and contains all the necessary elements for this. 110 | 111 | ## 🔋 🔌 Extensibility 112 | 113 | Since `AST` is predefined, but in real conditions it may be necessary to expand the 114 | functionality for the specific needs of the `compiler`, has been added the functionality 115 | of the `AST` extensibility and the additional generated set of `Instructions` for 116 | the **Semantic Stack Context**. 117 | 118 | - [x] 🚨 **Genetic expression value**: The ability to expand custom expressions for z, according to compiler requirements. 119 | The ability to implement custom instructions for these custom expressions in the 120 | **Semantic Stack Context**. 121 | 122 | ## 🛋️ Examples 123 | 124 | - 🔎 There is the example implementation separate project [💾 Toy Codegen](https://github.com/mrLSD/toy-codegen). 125 | The project uses the `SemanticStack` results and converts them into **Code Generation** logic which clearly shows the 126 | possibilities of using the results of the `semantic-analyzer-rs` `SemanticStackContext` results. LLVM is used as a 127 | backend, [inkwell](https://github.com/TheDan64/inkwell) as a library for LLVM codegen, and compiled into an executable 128 | program. The source of data is the AST structure itself. 129 | 130 | ## 📶 Features 131 | 132 | Available library rust features: 133 | - `codec` - 💮 enable serialization and deserialization with `Serde`. 134 | This is especially convenient in the process of forming AST, Codegen, 135 | a serialized representation of the `SemanticState`. Another important 136 | nuance is that any library that implements `Serde` can act as a 137 | serializer `codec`. For example formats: `json`, `toml`, `yaml`, 138 | `binary`, and many others that can use `serde` library. 139 | The main entities, which apply the `codec` feature are: 140 | - [x] `AST` ↪️ AST data source can be presented with serialized source. 141 | This is especially useful for designing and testing `Codegen`, AST data 142 | transfer pipeline, and also for use as a data generation source for 143 | AST - any programming language that can generate serialized AST data. 144 | - [x] `State` ↪️ `SematniсState` can be obtained in the form of 145 | serialized data. This is especially convenient for storing state 146 | before code generation with different parameters, post-analysis, 147 | optimizations - which will allow to work with already analyzed 148 | data. 149 | - [x] `SemanticStack` ↪️ contains a set of instructions for `Codegen`. 150 | Representation in serialized form may be convenient for cases: code 151 | generation without repeated semantic analysis, only based on 152 | instructions for the code generator generated by the `semantic analyzer`. 153 | Serialized data represented `SemanticStack` - opens up wide 154 | possibilities for using any third-party code generators and compilers 155 | implemented in any programming language. 156 | 157 | ## MIT [LICENSE](LICENSE) 158 | -------------------------------------------------------------------------------- /src/types/condition.rs: -------------------------------------------------------------------------------- 1 | //! # Condition types 2 | //! Condition types for Semantic analyzer result state. 3 | 4 | use super::expression::Expression; 5 | use super::{Binding, FunctionCall, LetBinding}; 6 | use crate::ast; 7 | use crate::types::semantic::{ExtendedExpression, SemanticContextInstruction}; 8 | #[cfg(feature = "codec")] 9 | use serde::{Deserialize, Serialize}; 10 | 11 | /// Basic logical conditions mostly for compare expressions 12 | #[derive(Debug, Clone, PartialEq, Eq)] 13 | #[cfg_attr( 14 | feature = "codec", 15 | derive(Serialize, Deserialize), 16 | serde(tag = "type", content = "content") 17 | )] 18 | pub enum Condition { 19 | Great, 20 | Less, 21 | Eq, 22 | GreatEq, 23 | LessEq, 24 | NotEq, 25 | } 26 | 27 | impl From for Condition { 28 | fn from(value: ast::Condition) -> Self { 29 | match value { 30 | ast::Condition::Great => Self::Great, 31 | ast::Condition::Less => Self::Less, 32 | ast::Condition::Eq => Self::Eq, 33 | ast::Condition::GreatEq => Self::GreatEq, 34 | ast::Condition::LessEq => Self::LessEq, 35 | ast::Condition::NotEq => Self::NotEq, 36 | } 37 | } 38 | } 39 | 40 | /// Logical conditions type representation. 41 | /// Usefulf for logical expressions. 42 | #[derive(Debug, Clone, PartialEq, Eq)] 43 | #[cfg_attr( 44 | feature = "codec", 45 | derive(Serialize, Deserialize), 46 | serde(tag = "type", content = "content") 47 | )] 48 | pub enum LogicCondition { 49 | And, 50 | Or, 51 | } 52 | 53 | impl From for LogicCondition { 54 | fn from(value: ast::LogicCondition) -> Self { 55 | match value { 56 | ast::LogicCondition::And => Self::And, 57 | ast::LogicCondition::Or => Self::Or, 58 | } 59 | } 60 | } 61 | 62 | /// Expression condition for two expressions 63 | #[derive(Debug, Clone, PartialEq)] 64 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 65 | pub struct ExpressionCondition { 66 | /// Left expression 67 | pub left: Expression, 68 | /// Condition for expressions 69 | pub condition: Condition, 70 | /// Right expression 71 | pub right: Expression, 72 | } 73 | 74 | impl> 75 | From> for ExpressionCondition 76 | { 77 | fn from(value: ast::ExpressionCondition<'_, I, E>) -> Self { 78 | Self { 79 | left: value.left.into(), 80 | condition: value.condition.into(), 81 | right: value.right.into(), 82 | } 83 | } 84 | } 85 | 86 | /// Expression logic condition for expression conditions. 87 | /// It's build chain of expression conditions and 88 | /// expression logic conditions as flat tree. 89 | #[derive(Debug, Clone, PartialEq)] 90 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 91 | pub struct ExpressionLogicCondition { 92 | /// Left expression condition 93 | pub left: ExpressionCondition, 94 | /// Optional right expression condition with logic condition 95 | pub right: Option<(LogicCondition, Box)>, 96 | } 97 | 98 | impl> 99 | From> for ExpressionLogicCondition 100 | { 101 | fn from(value: ast::ExpressionLogicCondition<'_, I, E>) -> Self { 102 | Self { 103 | left: value.left.into(), 104 | right: value 105 | .right 106 | .map(|(v, expr)| (v.into(), Box::new(expr.as_ref().clone().into()))), 107 | } 108 | } 109 | } 110 | 111 | /// If-condition representation. It can be: 112 | /// - simple - just expression 113 | /// - logic - represented through `ExpressionLogicCondition` 114 | #[derive(Debug, Clone, PartialEq)] 115 | #[cfg_attr( 116 | feature = "codec", 117 | derive(Serialize, Deserialize), 118 | serde(tag = "type", content = "content") 119 | )] 120 | pub enum IfCondition { 121 | Single(Expression), 122 | Logic(ExpressionLogicCondition), 123 | } 124 | 125 | impl> From> 126 | for IfCondition 127 | { 128 | fn from(value: ast::IfCondition<'_, I, E>) -> Self { 129 | match value { 130 | ast::IfCondition::Single(v) => Self::Single(v.into()), 131 | ast::IfCondition::Logic(v) => Self::Logic(v.into()), 132 | } 133 | } 134 | } 135 | 136 | /// # If statement 137 | /// Basic entity that represent if-statement. 138 | #[derive(Debug, Clone, PartialEq)] 139 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 140 | pub struct IfStatement { 141 | /// If-condition 142 | pub condition: IfCondition, 143 | /// Basic if-body, if if-condition is true 144 | pub body: IfBodyStatements, 145 | /// Basic else-body, if if-condition is false 146 | pub else_statement: Option, 147 | /// Basic else-if-body 148 | pub else_if_statement: Option>, 149 | } 150 | 151 | impl> From> 152 | for IfStatement 153 | { 154 | fn from(value: ast::IfStatement<'_, I, E>) -> Self { 155 | Self { 156 | condition: value.condition.into(), 157 | body: value.body.into(), 158 | else_statement: value.else_statement.map(Into::into), 159 | else_if_statement: value 160 | .else_if_statement 161 | .map(|v| Box::new(v.as_ref().clone().into())), 162 | } 163 | } 164 | } 165 | 166 | /// If-body statement can be: 167 | /// - if-body-statement related only 168 | /// - loop-body-statement related - special case for the loops 169 | #[derive(Debug, Clone, PartialEq)] 170 | #[cfg_attr( 171 | feature = "codec", 172 | derive(Serialize, Deserialize), 173 | serde(tag = "type", content = "content") 174 | )] 175 | pub enum IfBodyStatements { 176 | If(Vec), 177 | Loop(Vec), 178 | } 179 | 180 | impl> From> 181 | for IfBodyStatements 182 | { 183 | fn from(value: ast::IfBodyStatements<'_, I, E>) -> Self { 184 | match value { 185 | ast::IfBodyStatements::If(v) => Self::If(v.iter().map(|v| v.clone().into()).collect()), 186 | ast::IfBodyStatements::Loop(v) => { 187 | Self::Loop(v.iter().map(|v| v.clone().into()).collect()) 188 | } 189 | } 190 | } 191 | } 192 | 193 | /// Loop body statement represents body for the loop 194 | #[derive(Debug, Clone, PartialEq)] 195 | #[cfg_attr( 196 | feature = "codec", 197 | derive(Serialize, Deserialize), 198 | serde(tag = "type", content = "content") 199 | )] 200 | pub enum LoopBodyStatement { 201 | LetBinding(LetBinding), 202 | Binding(Binding), 203 | FunctionCall(FunctionCall), 204 | If(IfStatement), 205 | Loop(Vec), 206 | Return(Expression), 207 | Break, 208 | Continue, 209 | } 210 | 211 | impl> From> 212 | for LoopBodyStatement 213 | { 214 | fn from(value: ast::LoopBodyStatement<'_, I, E>) -> Self { 215 | match value { 216 | ast::LoopBodyStatement::LetBinding(v) => Self::LetBinding(v.into()), 217 | ast::LoopBodyStatement::Binding(v) => Self::Binding(v.into()), 218 | ast::LoopBodyStatement::FunctionCall(v) => Self::FunctionCall(v.into()), 219 | ast::LoopBodyStatement::If(v) => Self::If(v.into()), 220 | ast::LoopBodyStatement::Loop(v) => { 221 | Self::Loop(v.iter().map(|v| v.clone().into()).collect()) 222 | } 223 | ast::LoopBodyStatement::Return(v) => Self::Return(v.into()), 224 | ast::LoopBodyStatement::Break => Self::Break, 225 | ast::LoopBodyStatement::Continue => Self::Continue, 226 | } 227 | } 228 | } 229 | 230 | /// If-body statement represents body for the if-body 231 | #[derive(Debug, Clone, PartialEq)] 232 | #[cfg_attr( 233 | feature = "codec", 234 | derive(Serialize, Deserialize), 235 | serde(tag = "type", content = "content") 236 | )] 237 | pub enum IfBodyStatement { 238 | LetBinding(LetBinding), 239 | Binding(Binding), 240 | FunctionCall(FunctionCall), 241 | If(IfStatement), 242 | Loop(Vec), 243 | Return(Expression), 244 | } 245 | 246 | impl> From> 247 | for IfBodyStatement 248 | { 249 | fn from(value: ast::IfBodyStatement<'_, I, E>) -> Self { 250 | match value { 251 | ast::IfBodyStatement::LetBinding(v) => Self::LetBinding(v.into()), 252 | ast::IfBodyStatement::Binding(v) => Self::Binding(v.into()), 253 | ast::IfBodyStatement::FunctionCall(v) => Self::FunctionCall(v.into()), 254 | ast::IfBodyStatement::If(v) => Self::If(v.into()), 255 | ast::IfBodyStatement::Loop(v) => { 256 | Self::Loop(v.iter().map(|v| v.clone().into()).collect()) 257 | } 258 | ast::IfBodyStatement::Return(v) => Self::Return(v.into()), 259 | } 260 | } 261 | } 262 | 263 | /// If-loop body statements represent body of if-body 264 | /// in the loops 265 | #[derive(Debug, Clone, PartialEq)] 266 | #[cfg_attr( 267 | feature = "codec", 268 | derive(Serialize, Deserialize), 269 | serde(tag = "type", content = "content") 270 | )] 271 | pub enum IfLoopBodyStatement { 272 | LetBinding(LetBinding), 273 | Binding(Binding), 274 | FunctionCall(FunctionCall), 275 | If(IfStatement), 276 | Loop(Vec), 277 | Return(Expression), 278 | Break, 279 | Continue, 280 | } 281 | 282 | impl> 283 | From> for IfLoopBodyStatement 284 | { 285 | fn from(value: ast::IfLoopBodyStatement<'_, I, E>) -> Self { 286 | match value { 287 | ast::IfLoopBodyStatement::LetBinding(v) => Self::LetBinding(v.into()), 288 | ast::IfLoopBodyStatement::Binding(v) => Self::Binding(v.into()), 289 | ast::IfLoopBodyStatement::FunctionCall(v) => Self::FunctionCall(v.into()), 290 | ast::IfLoopBodyStatement::If(v) => Self::If(v.into()), 291 | ast::IfLoopBodyStatement::Loop(v) => { 292 | Self::Loop(v.iter().map(|v| v.clone().into()).collect()) 293 | } 294 | ast::IfLoopBodyStatement::Return(v) => Self::Return(v.into()), 295 | ast::IfLoopBodyStatement::Break => Self::Break, 296 | ast::IfLoopBodyStatement::Continue => Self::Continue, 297 | } 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /tests/state_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{CustomExpression, CustomExpressionInstruction}; 2 | use semantic_analyzer::ast::{self, Ident}; 3 | use semantic_analyzer::semantic::State; 4 | use semantic_analyzer::types::condition::{Condition, LogicCondition}; 5 | use semantic_analyzer::types::expression::{ 6 | ExpressionOperations, ExpressionResult, ExpressionResultValue, 7 | }; 8 | use semantic_analyzer::types::semantic::{ExtendedSemanticContext, SemanticContext}; 9 | use semantic_analyzer::types::{ 10 | block_state::BlockState, 11 | semantic::SemanticStack, 12 | types::{PrimitiveTypes, Type}, 13 | Constant, ConstantExpression, ConstantValue, Function, FunctionParameter, InnerValueName, 14 | LabelName, Value, ValueName, 15 | }; 16 | use std::cell::RefCell; 17 | use std::rc::Rc; 18 | 19 | mod utils; 20 | 21 | #[test] 22 | fn state_init() { 23 | let st = State::, CustomExpressionInstruction>::default(); 24 | // For grcov 25 | let _ = format!("{st:?}"); 26 | assert!(st.global.types.is_empty()); 27 | assert!(st.global.constants.is_empty()); 28 | assert!(st.global.functions.is_empty()); 29 | assert_eq!(st.global.context, SemanticStack::new()); 30 | assert!(st.context.is_empty()); 31 | assert!(st.errors.is_empty()); 32 | } 33 | 34 | #[test] 35 | fn state_block_state_count() { 36 | let bst1 = Rc::new(RefCell::new(BlockState::new(None))); 37 | let bst2 = Rc::new(RefCell::new(BlockState::new(Some(bst1.clone())))); 38 | let mut st1 = State::, CustomExpressionInstruction>::default(); 39 | st1.context.push(bst1); 40 | st1.context.push(bst2); 41 | assert_eq!(st1.context.len(), 2); 42 | let fs = ast::FunctionStatement::new( 43 | ast::FunctionName::new(Ident::new("fn1")), 44 | vec![], 45 | ast::Type::Primitive(ast::PrimitiveTypes::Bool), 46 | vec![], 47 | ); 48 | st1.function_body(&fs); 49 | // Should contain error 50 | assert_eq!(st1.errors.len(), 1); 51 | assert_eq!(st1.context.len(), 3); 52 | } 53 | 54 | #[test] 55 | fn block_state_fields() { 56 | let mut bst: BlockState = BlockState::new(None); 57 | assert!(bst.values.is_empty()); 58 | assert!(bst.inner_values_name.is_empty()); 59 | assert!(bst.labels.is_empty()); 60 | assert!(!bst.manual_return); 61 | assert!(bst.parent.is_none()); 62 | assert!(bst.children.is_empty()); 63 | assert_eq!(bst.get_context(), SemanticStack::new()); 64 | bst.set_child(Rc::new(RefCell::new(BlockState::new(None)))); 65 | assert_eq!(bst.children.len(), 1); 66 | 67 | let bst1 = Rc::new(RefCell::new( 68 | BlockState::::new(None), 69 | )); 70 | let bst2 = Rc::new(RefCell::new( 71 | BlockState::::new(Some(bst1.clone())), 72 | )); 73 | bst1.borrow_mut().set_child(bst1.clone()); 74 | bst2.borrow_mut().set_return(); 75 | assert!(bst1.borrow().manual_return); 76 | assert!(bst2.borrow().manual_return); 77 | } 78 | 79 | #[test] 80 | fn inner_value_name_transform() { 81 | let value_name: ValueName = "x1".into(); 82 | let inner_value_name1: InnerValueName = value_name.into(); 83 | assert_eq!(inner_value_name1.to_string(), "x1"); 84 | let inner_value_name2: InnerValueName = "x2".into(); 85 | assert_eq!(inner_value_name2.to_string(), "x2"); 86 | let inner_value_name3: InnerValueName = String::from("x3").into(); 87 | assert_eq!(inner_value_name3.to_string(), "x3"); 88 | } 89 | 90 | #[test] 91 | fn block_state_inner_value_name() { 92 | let bst1 = Rc::new(RefCell::new( 93 | BlockState::::new(None), 94 | )); 95 | let bst2 = Rc::new(RefCell::new(BlockState::new(Some(bst1.clone())))); 96 | bst1.borrow_mut().set_child(bst1.clone()); 97 | assert!(bst2.borrow().parent.is_some()); 98 | assert_eq!(bst1.borrow().children.len(), 1); 99 | 100 | let inner_value_name1: InnerValueName = "x1".into(); 101 | let inner_value_name2: InnerValueName = "x2".into(); 102 | let inner_value_name3: InnerValueName = "x3".into(); 103 | 104 | bst1.borrow_mut().set_inner_value_name(&inner_value_name1); 105 | bst2.borrow_mut().set_inner_value_name(&inner_value_name2); 106 | 107 | assert_eq!(bst1.borrow().inner_values_name.len(), 2); 108 | assert!(bst1.borrow().is_inner_value_name_exist(&inner_value_name1)); 109 | assert!(bst1.borrow().is_inner_value_name_exist(&inner_value_name2)); 110 | assert!(!bst1.borrow().is_inner_value_name_exist(&inner_value_name3)); 111 | 112 | assert_eq!(bst2.borrow().inner_values_name.len(), 1); 113 | assert!(bst2.borrow().is_inner_value_name_exist(&inner_value_name1)); 114 | assert!(bst2.borrow().is_inner_value_name_exist(&inner_value_name2)); 115 | assert!(!bst2.borrow().is_inner_value_name_exist(&inner_value_name3)); 116 | 117 | assert_eq!( 118 | bst1.borrow() 119 | .get_next_inner_name(&inner_value_name1) 120 | .to_string(), 121 | "x1.0" 122 | ); 123 | assert_eq!( 124 | bst2.borrow() 125 | .get_next_inner_name(&inner_value_name1) 126 | .to_string(), 127 | "x1.0" 128 | ); 129 | assert_eq!( 130 | bst1.borrow() 131 | .get_next_inner_name(&inner_value_name3) 132 | .to_string(), 133 | "x3.0" 134 | ); 135 | let inner_value_name3_0: InnerValueName = "x3.0".into(); 136 | assert_eq!( 137 | bst1.borrow() 138 | .get_next_inner_name(&inner_value_name3_0) 139 | .to_string(), 140 | "x3.1" 141 | ); 142 | 143 | let inner_value_name2_0 = "x2.0".into(); 144 | bst2.borrow_mut().set_inner_value_name(&inner_value_name2_0); 145 | assert!(bst2 146 | .borrow() 147 | .is_inner_value_name_exist(&inner_value_name2_0)); 148 | assert_eq!( 149 | bst1.borrow() 150 | .get_next_inner_name(&inner_value_name2) 151 | .to_string(), 152 | "x2.1" 153 | ); 154 | assert_eq!( 155 | bst2.borrow() 156 | .get_next_inner_name(&inner_value_name2) 157 | .to_string(), 158 | "x2.1" 159 | ); 160 | } 161 | 162 | #[test] 163 | fn block_state_label_name() { 164 | let bst1 = Rc::new(RefCell::new( 165 | BlockState::::new(None), 166 | )); 167 | let bst2 = Rc::new(RefCell::new(BlockState::new(Some(bst1.clone())))); 168 | bst1.borrow_mut().set_child(bst1.clone()); 169 | 170 | let lbl1: LabelName = String::from("lbl1").into(); 171 | let lbl2: LabelName = String::from("lbl2").into(); 172 | assert_eq!(lbl1.to_string(), "lbl1"); 173 | bst1.borrow_mut().set_label_name(&lbl1); 174 | bst2.borrow_mut().set_label_name(&lbl2); 175 | assert!(bst1.borrow().is_label_name_exist(&lbl1)); 176 | assert!(bst2.borrow().is_label_name_exist(&lbl1)); 177 | assert!(bst1.borrow().is_label_name_exist(&lbl2)); 178 | assert!(bst2.borrow().is_label_name_exist(&lbl2)); 179 | 180 | let lbl3 = bst1 181 | .borrow_mut() 182 | .get_and_set_next_label(&String::from("lbl3").into()); 183 | assert_eq!(lbl3.to_string(), "lbl3"); 184 | 185 | let lbl1_0 = bst1.borrow_mut().get_and_set_next_label(&lbl1); 186 | assert_eq!(lbl1_0.to_string(), "lbl1.0"); 187 | 188 | let lbl1_1 = bst2.borrow_mut().get_and_set_next_label(&lbl1); 189 | assert_eq!(lbl1_1.to_string(), "lbl1.1"); 190 | let lbl1_2 = bst2.borrow_mut().get_and_set_next_label(&lbl1_1); 191 | assert_eq!(lbl1_2.to_string(), "lbl1.2"); 192 | let lbl1_3 = bst2.borrow_mut().get_and_set_next_label(&lbl1); 193 | assert_eq!(lbl1_3.to_string(), "lbl1.3"); 194 | } 195 | 196 | #[test] 197 | fn block_state_value() { 198 | let bst1 = Rc::new(RefCell::new( 199 | BlockState::::new(None), 200 | )); 201 | let bst2 = Rc::new(RefCell::new( 202 | BlockState::::new(Some(bst1.clone())), 203 | )); 204 | let bst3 = Rc::new(RefCell::new( 205 | BlockState::::new(None), 206 | )); 207 | bst1.borrow_mut().set_child(bst1.clone()); 208 | 209 | // Insert Value 210 | let vn1: ValueName = "x5".into(); 211 | let val = Value { 212 | inner_name: "x5.0".into(), 213 | inner_type: Type::Primitive(PrimitiveTypes::Bool), 214 | mutable: false, 215 | alloca: false, 216 | malloc: false, 217 | }; 218 | bst1.borrow_mut().values.insert(vn1.clone(), val.clone()); 219 | assert_eq!(bst1.borrow().get_value_name(&vn1).unwrap(), val.clone()); 220 | assert_eq!(bst2.borrow().get_value_name(&vn1).unwrap(), val); 221 | assert!(bst3.borrow().get_value_name(&vn1).is_none()); 222 | 223 | assert_eq!(bst1.borrow().last_register_number, 0); 224 | assert_eq!(bst2.borrow().last_register_number, 0); 225 | bst2.borrow_mut().inc_register(); 226 | assert_eq!(bst1.borrow().last_register_number, 1); 227 | assert_eq!(bst2.borrow().last_register_number, 1); 228 | } 229 | 230 | #[test] 231 | fn block_state_last_register_inc() { 232 | let bst1 = Rc::new(RefCell::new( 233 | BlockState::::new(None), 234 | )); 235 | let bst2 = Rc::new(RefCell::new( 236 | BlockState::::new(Some(bst1.clone())), 237 | )); 238 | let mut bst3: BlockState = BlockState::new(None); 239 | 240 | assert_eq!(bst1.borrow().last_register_number, 0); 241 | assert_eq!(bst2.borrow().last_register_number, 0); 242 | bst2.borrow_mut().inc_register(); 243 | assert_eq!(bst1.borrow().last_register_number, 1); 244 | assert_eq!(bst2.borrow().last_register_number, 1); 245 | 246 | assert_eq!(bst3.last_register_number, 0); 247 | bst3.inc_register(); 248 | assert_eq!(bst3.last_register_number, 1); 249 | // For grcov 250 | let _ = format!("{bst3:?}"); 251 | } 252 | 253 | #[test] 254 | fn block_state_instructions_with_parent() { 255 | let parent_bst = Rc::new(RefCell::new( 256 | BlockState::::new(None), 257 | )); 258 | let mut bst = BlockState::new(Some(parent_bst.clone())); 259 | let val = Value { 260 | inner_name: String::from("x").into(), 261 | inner_type: Type::Primitive(PrimitiveTypes::Ptr), 262 | mutable: false, 263 | alloca: false, 264 | malloc: false, 265 | }; 266 | bst.expression_value(val.clone(), 1); 267 | let expr_const: Constant = Constant { 268 | name: String::from("cnt1").into(), 269 | constant_type: Type::Primitive(PrimitiveTypes::Ptr), 270 | constant_value: ConstantExpression { 271 | value: ConstantValue::Constant(String::from("cnt2").into()), 272 | operation: None, 273 | }, 274 | }; 275 | bst.expression_const(expr_const, 1); 276 | bst.expression_struct_value(val.clone(), 1, 1); 277 | let expr_op = ExpressionOperations::Plus; 278 | let expr_res = ExpressionResult { 279 | expr_type: Type::Primitive(PrimitiveTypes::Ptr), 280 | expr_value: ExpressionResultValue::Register(1), 281 | }; 282 | bst.expression_operation(expr_op, expr_res.clone(), expr_res.clone(), 1); 283 | let call_fn = Function { 284 | inner_name: String::from("fn1").into(), 285 | inner_type: Type::Primitive(PrimitiveTypes::Ptr), 286 | parameters: vec![], 287 | }; 288 | bst.call(call_fn, vec![], 1); 289 | bst.let_binding(val.clone(), expr_res.clone()); 290 | bst.binding(val.clone(), expr_res.clone()); 291 | bst.expression_function_return(expr_res.clone()); 292 | bst.expression_function_return_with_label(expr_res.clone()); 293 | let label: LabelName = String::from("label").into(); 294 | bst.set_label(label.clone()); 295 | bst.jump_to(label.clone()); 296 | bst.if_condition_expression(expr_res.clone(), label.clone(), label.clone()); 297 | let condition = Condition::Great; 298 | bst.condition_expression(expr_res.clone(), expr_res.clone(), condition, 1); 299 | bst.jump_function_return(expr_res); 300 | let logic_condition = LogicCondition::And; 301 | bst.logic_condition(logic_condition, 1, 2, 3); 302 | bst.if_condition_logic(label.clone(), label, 1); 303 | let func_arg = FunctionParameter { 304 | name: ast::ParameterName::new(Ident::new("x")).into(), 305 | parameter_type: Type::Primitive(PrimitiveTypes::Ptr), 306 | }; 307 | bst.function_arg(val, func_arg); 308 | 309 | let custom_instr = CustomExpressionInstruction; 310 | bst.extended_expression(&custom_instr); 311 | 312 | let parent_ctx = parent_bst.borrow().get_context().get(); 313 | assert_eq!(parent_ctx.len(), 18); 314 | } 315 | -------------------------------------------------------------------------------- /tests/types_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::SemanticTest; 2 | use semantic_analyzer::ast::{self, GetLocation, GetName, Ident}; 3 | use semantic_analyzer::types::error::StateErrorKind; 4 | use semantic_analyzer::types::semantic::SemanticStackContext; 5 | use semantic_analyzer::types::types::{ 6 | PrimitiveTypes, StructAttributeType, StructTypes, Type, TypeAttributes, 7 | }; 8 | use semantic_analyzer::types::ValueName; 9 | 10 | mod utils; 11 | 12 | #[test] 13 | fn types_ast_transform() { 14 | let type_ast = ast::StructTypes { 15 | name: Ident::new("type1"), 16 | attributes: vec![], 17 | }; 18 | assert_eq!(type_ast.name(), "type1"); 19 | assert_eq!(type_ast.location(), ast::CodeLocation::new(1, 0)); 20 | let main_ast_type = ast::Type::Struct(type_ast.clone()); 21 | assert_eq!(main_ast_type.name(), "type1"); 22 | 23 | let type_into1: StructTypes = type_ast.clone().into(); 24 | assert_eq!(type_into1.name, "type1"); 25 | assert!(type_into1.attributes.is_empty()); 26 | assert!(type_into1.methods.is_empty()); 27 | 28 | let ty1 = ast::StructType { 29 | attr_name: Ident::new("attr1"), 30 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::U8), 31 | }; 32 | let ty2 = ast::StructType { 33 | attr_name: Ident::new("attr2"), 34 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::U16), 35 | }; 36 | let ty3 = ast::StructType { 37 | attr_name: Ident::new("attr3"), 38 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::U32), 39 | }; 40 | let ty4 = ast::StructType { 41 | attr_name: Ident::new("attr4"), 42 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::U64), 43 | }; 44 | let ty5 = ast::StructType { 45 | attr_name: Ident::new("attr5"), 46 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::I8), 47 | }; 48 | let ty6 = ast::StructType { 49 | attr_name: Ident::new("attr6"), 50 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::I16), 51 | }; 52 | let ty7 = ast::StructType { 53 | attr_name: Ident::new("attr7"), 54 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::I32), 55 | }; 56 | let ty8 = ast::StructType { 57 | attr_name: Ident::new("attr8"), 58 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::I64), 59 | }; 60 | let ty9 = ast::StructType { 61 | attr_name: Ident::new("attr9"), 62 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::Bool), 63 | }; 64 | let ty10 = ast::StructType { 65 | attr_name: Ident::new("attr10"), 66 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::F32), 67 | }; 68 | let ty11 = ast::StructType { 69 | attr_name: Ident::new("attr11"), 70 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::F64), 71 | }; 72 | let ty12 = ast::StructType { 73 | attr_name: Ident::new("attr12"), 74 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::Char), 75 | }; 76 | let ty14 = ast::StructType { 77 | attr_name: Ident::new("attr14"), 78 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::Ptr), 79 | }; 80 | let ty15 = ast::StructType { 81 | attr_name: Ident::new("attr15"), 82 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::None), 83 | }; 84 | let ty16 = ast::StructType { 85 | attr_name: Ident::new("attr16"), 86 | attr_type: ast::Type::Array(Box::new(ast::Type::Primitive(ast::PrimitiveTypes::I16)), 10), 87 | }; 88 | let ty17 = ast::StructType { 89 | attr_name: Ident::new("attr17"), 90 | attr_type: ast::Type::Struct(ast::StructTypes { 91 | name: Ident::new("type5"), 92 | attributes: vec![], 93 | }), 94 | }; 95 | let type_ast = ast::StructTypes { 96 | name: Ident::new("type2"), 97 | attributes: vec![ 98 | ty1.clone(), 99 | ty2.clone(), 100 | ty3.clone(), 101 | ty4.clone(), 102 | ty5.clone(), 103 | ty6.clone(), 104 | ty7.clone(), 105 | ty8.clone(), 106 | ty9.clone(), 107 | ty10.clone(), 108 | ty11.clone(), 109 | ty12.clone(), 110 | ty14.clone(), 111 | ty15.clone(), 112 | ty16.clone(), 113 | ty17.clone(), 114 | ], 115 | }; 116 | let type_into2: StructTypes = type_ast.clone().into(); 117 | assert_eq!(type_into2.name, "type2"); 118 | assert_eq!(type_into2.attributes.len(), 16); 119 | 120 | // Index=0 the same, so we can check directly 121 | assert_eq!(ty1.attr_type.name(), "u8"); 122 | let attr1 = type_into2.attributes.get(&("attr1".into())).unwrap(); 123 | let ty1: StructAttributeType = ty1.into(); 124 | assert_eq!(attr1, &ty1); 125 | assert_eq!(type_into2.get_attribute_index(&("attr2".into())), Some(1)); 126 | assert_eq!( 127 | type_into2.get_attribute_type(&("attr2".into())), 128 | Some(Type::Primitive(PrimitiveTypes::U16)) 129 | ); 130 | assert_eq!(attr1.attr_name, ty1.attr_name); 131 | assert_eq!(attr1.attr_type, ty1.attr_type); 132 | assert_eq!(attr1.attr_type.name().to_string(), "u8"); 133 | assert_eq!(attr1.attr_type.name().name(), "u8"); 134 | assert_eq!(attr1.attr_index, 0); 135 | 136 | let attr2 = type_into2.attributes.get(&("attr2".into())).unwrap(); 137 | assert_eq!(ty2.attr_type.name(), "u16"); 138 | let ty2: StructAttributeType = ty2.into(); 139 | assert_eq!(attr2.attr_name, ty2.attr_name); 140 | assert_eq!(attr2.attr_type, ty2.attr_type); 141 | assert_eq!(attr2.attr_type.to_string(), "u16"); 142 | assert_eq!(attr2.attr_index, 1); 143 | 144 | let attr3 = type_into2.attributes.get(&("attr3".into())).unwrap(); 145 | assert_eq!(ty3.attr_type.name(), "u32"); 146 | let ty3: StructAttributeType = ty3.into(); 147 | assert_eq!(attr3.attr_name, ty3.attr_name); 148 | assert_eq!(attr3.attr_type, ty3.attr_type); 149 | assert_eq!(attr3.attr_type.to_string(), "u32"); 150 | assert_eq!(attr3.attr_index, 2); 151 | 152 | let attr4 = type_into2.attributes.get(&("attr4".into())).unwrap(); 153 | assert_eq!(ty4.attr_type.name(), "u64"); 154 | let ty4: StructAttributeType = ty4.into(); 155 | assert_eq!(attr4.attr_name, ty4.attr_name); 156 | assert_eq!(attr4.attr_type, ty4.attr_type); 157 | assert_eq!(attr4.attr_type.to_string(), "u64"); 158 | assert_eq!(attr4.attr_index, 3); 159 | 160 | let attr5 = type_into2.attributes.get(&("attr5".into())).unwrap(); 161 | assert_eq!(ty5.attr_type.name(), "i8"); 162 | let ty5: StructAttributeType = ty5.into(); 163 | assert_eq!(attr5.attr_name, ty5.attr_name); 164 | assert_eq!(attr5.attr_type, ty5.attr_type); 165 | assert_eq!(attr5.attr_type.to_string(), "i8"); 166 | assert_eq!(attr5.attr_index, 4); 167 | 168 | let attr6 = type_into2.attributes.get(&("attr6".into())).unwrap(); 169 | assert_eq!(ty6.attr_type.name(), "i16"); 170 | let ty6: StructAttributeType = ty6.into(); 171 | assert_eq!(attr6.attr_name, ty6.attr_name); 172 | assert_eq!(attr6.attr_type, ty6.attr_type); 173 | assert_eq!(attr6.attr_type.to_string(), "i16"); 174 | assert_eq!(attr6.attr_index, 5); 175 | 176 | let attr7 = type_into2.attributes.get(&("attr7".into())).unwrap(); 177 | assert_eq!(ty7.attr_type.name(), "i32"); 178 | let ty7: StructAttributeType = ty7.into(); 179 | assert_eq!(attr7.attr_name, ty7.attr_name); 180 | assert_eq!(attr7.attr_type, ty7.attr_type); 181 | assert_eq!(attr7.attr_type.to_string(), "i32"); 182 | assert_eq!(attr7.attr_index, 6); 183 | 184 | let attr8 = type_into2.attributes.get(&("attr8".into())).unwrap(); 185 | assert_eq!(ty8.attr_type.name(), "i64"); 186 | let ty8: StructAttributeType = ty8.into(); 187 | assert_eq!(attr8.attr_name, ty8.attr_name); 188 | assert_eq!(attr8.attr_type, ty8.attr_type); 189 | assert_eq!(attr8.attr_type.to_string(), "i64"); 190 | assert_eq!(attr8.attr_index, 7); 191 | 192 | let attr9 = type_into2.attributes.get(&("attr9".into())).unwrap(); 193 | assert_eq!(ty9.attr_type.name(), "bool"); 194 | let ty9: StructAttributeType = ty9.into(); 195 | assert_eq!(attr9.attr_name, ty9.attr_name); 196 | assert_eq!(attr9.attr_type, ty9.attr_type); 197 | assert_eq!(attr9.attr_type.to_string(), "bool"); 198 | assert_eq!(attr9.attr_index, 8); 199 | 200 | let attr10 = type_into2.attributes.get(&("attr10".into())).unwrap(); 201 | assert_eq!(ty10.attr_type.name(), "f32"); 202 | let ty10: StructAttributeType = ty10.into(); 203 | assert_eq!(attr10.attr_name, ty10.attr_name); 204 | assert_eq!(attr10.attr_type, ty10.attr_type); 205 | assert_eq!(attr10.attr_type.to_string(), "f32"); 206 | assert_eq!(attr10.attr_index, 9); 207 | 208 | let attr11 = type_into2.attributes.get(&("attr11".into())).unwrap(); 209 | assert_eq!(ty11.attr_type.name(), "f64"); 210 | let ty11: StructAttributeType = ty11.into(); 211 | assert_eq!(attr11.attr_name, ty11.attr_name); 212 | assert_eq!(attr11.attr_type, ty11.attr_type); 213 | assert_eq!(attr11.attr_type.to_string(), "f64"); 214 | assert_eq!(attr11.attr_index, 10); 215 | 216 | let attr12 = type_into2.attributes.get(&("attr12".into())).unwrap(); 217 | assert_eq!(ty12.attr_type.name(), "char"); 218 | let ty12: StructAttributeType = ty12.into(); 219 | assert_eq!(attr12.attr_name, ty12.attr_name); 220 | assert_eq!(attr12.attr_type, ty12.attr_type); 221 | assert_eq!(attr12.attr_type.to_string(), "char"); 222 | assert_eq!(attr12.attr_index, 11); 223 | 224 | let attr14 = type_into2.attributes.get(&("attr14".into())).unwrap(); 225 | assert_eq!(ty14.attr_type.name(), "ptr"); 226 | let ty14: StructAttributeType = ty14.into(); 227 | assert_eq!(attr14.attr_name, ty14.attr_name); 228 | assert_eq!(attr14.attr_type, ty14.attr_type); 229 | assert_eq!(attr14.attr_type.to_string(), "ptr"); 230 | assert_eq!(attr14.attr_index, 12); 231 | 232 | let attr15 = type_into2.attributes.get(&("attr15".into())).unwrap(); 233 | assert_eq!(ty15.attr_type.name(), "()"); 234 | let ty15: StructAttributeType = ty15.into(); 235 | assert_eq!(attr15.attr_name, ty15.attr_name); 236 | assert_eq!(attr15.attr_type, ty15.attr_type); 237 | assert_eq!(attr15.attr_type.to_string(), "()"); 238 | assert_eq!(attr15.attr_index, 13); 239 | 240 | let attr16 = type_into2.attributes.get(&("attr16".into())).unwrap(); 241 | assert_eq!(ty16.attr_type.name(), "[\"i16\";10]"); 242 | let ty16: StructAttributeType = ty16.into(); 243 | assert_eq!(attr16.attr_name, ty16.attr_name); 244 | assert_eq!(attr16.attr_type, ty16.attr_type); 245 | assert_eq!(attr16.attr_type.to_string(), "[\"i16\";10]"); 246 | assert_eq!(attr16.attr_index, 14); 247 | 248 | let attr17 = type_into2.attributes.get(&("attr17".into())).unwrap(); 249 | assert_eq!(ty17.attr_type.name(), "type5"); 250 | let ty17: StructAttributeType = ty17.into(); 251 | assert_eq!(attr17.attr_name, ty17.attr_name); 252 | assert_eq!(attr17.attr_type, ty17.attr_type); 253 | assert_eq!(attr17.attr_type.to_string(), "type5"); 254 | assert_eq!(attr17.attr_index, 15); 255 | 256 | //======================= 257 | // Common type tests 258 | let pty = Type::Primitive(PrimitiveTypes::U16); 259 | assert_eq!(pty.get_struct(), None); 260 | assert_eq!(pty.get_attribute_type(&("attr1".into())), None); 261 | assert_eq!(pty.get_attribute_index(&("attr1".into())), None); 262 | assert_eq!(pty.get_method("fn1".to_string()), None); 263 | assert!(!pty.is_attribute(&("attr1".into()))); 264 | assert!(!pty.is_method("fn1".to_string())); 265 | 266 | let main_type: Type = Type::Struct(type_into2.clone()); 267 | assert_eq!(&type_into2, &main_type.get_struct().unwrap()); 268 | assert_eq!( 269 | main_type.get_attribute_type(&("attr3".into())).unwrap(), 270 | Type::Primitive(PrimitiveTypes::U32) 271 | ); 272 | let attr3_name: ValueName = "attr3".into(); 273 | assert_eq!(main_type.get_attribute_index(&attr3_name).unwrap(), 2); 274 | assert_eq!(attr3_name.to_string(), "attr3"); 275 | assert_eq!(main_type.get_method("fn1".to_string()), None); 276 | assert!(main_type.is_attribute(&("attr3".into()))); 277 | assert!(!main_type.is_method("fn1".to_string())); 278 | 279 | let st_type = ast::StructTypes { 280 | name: Ident::new("type3"), 281 | attributes: vec![], 282 | }; 283 | let arr_type_ast = ast::Type::Array(Box::new(ast::Type::Struct(st_type)), 10); 284 | assert_eq!(arr_type_ast.name(), "[\"type3\";10]"); 285 | } 286 | 287 | #[test] 288 | fn types_declaration() { 289 | let mut t = SemanticTest::new(); 290 | let type_decl = ast::StructTypes { 291 | name: Ident::new("type1"), 292 | attributes: vec![], 293 | }; 294 | t.state.types(&type_decl.clone()); 295 | assert!(t.is_empty_error()); 296 | 297 | let state = t.state.global.context.clone().get(); 298 | assert_eq!(state.len(), 1); 299 | assert_eq!( 300 | state[0], 301 | SemanticStackContext::Types { 302 | type_decl: type_decl.clone().into() 303 | } 304 | ); 305 | 306 | let ty1 = ast::StructType { 307 | attr_name: Ident::new("attr1"), 308 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::Char), 309 | }; 310 | let ty2 = ast::StructType { 311 | attr_name: Ident::new("attr2"), 312 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::U8), 313 | }; 314 | let type_decl2 = ast::StructTypes { 315 | name: Ident::new("type2"), 316 | attributes: vec![ty1, ty2], 317 | }; 318 | t.state.types(&type_decl2.clone()); 319 | assert!(t.is_empty_error()); 320 | let state = t.state.global.context.clone().get(); 321 | assert_eq!(state.len(), 2); 322 | assert_eq!( 323 | state[0], 324 | SemanticStackContext::Types { 325 | type_decl: type_decl.into() 326 | } 327 | ); 328 | assert_eq!( 329 | state[1], 330 | SemanticStackContext::Types { 331 | type_decl: type_decl2.clone().into() 332 | } 333 | ); 334 | 335 | t.state.types(&type_decl2.clone()); 336 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 337 | assert!( 338 | t.check_error(StateErrorKind::TypeAlreadyExist), 339 | "Errors: {:?}", 340 | t.state.errors[0] 341 | ); 342 | let state = t.state.global.context.clone().get(); 343 | assert_eq!(state.len(), 2); 344 | } 345 | 346 | #[test] 347 | fn code_location() { 348 | let x = ast::CodeLocation::new(10, 100); 349 | assert_eq!(x.line(), 10); 350 | assert_eq!(x.offset(), 100); 351 | } 352 | -------------------------------------------------------------------------------- /tests/codec_tests.rs: -------------------------------------------------------------------------------- 1 | mod utils; 2 | 3 | #[cfg(test)] 4 | #[cfg(feature = "codec")] 5 | mod test { 6 | use crate::utils::{CustomExpression, CustomExpressionInstruction, SemanticTest}; 7 | use semantic_analyzer::ast::{self, CodeLocation, Ident}; 8 | use semantic_analyzer::types::block_state::BlockState; 9 | use semantic_analyzer::types::condition::{ 10 | Condition, IfLoopBodyStatement, LogicCondition, LoopBodyStatement, 11 | }; 12 | use semantic_analyzer::types::error::{StateErrorKind, StateErrorLocation, StateErrorResult}; 13 | use semantic_analyzer::types::expression::{ 14 | ExpressionOperations, ExpressionResult, ExpressionResultValue, ExpressionStructValue, 15 | ExtendedExpressionValue, 16 | }; 17 | use semantic_analyzer::types::types::{PrimitiveTypes, Type}; 18 | use semantic_analyzer::types::{InnerValueName, LabelName, PrimitiveValue, Value}; 19 | use std::cell::RefCell; 20 | use std::rc::Rc; 21 | 22 | #[test] 23 | fn basic_ast_serialize() { 24 | let mut t = SemanticTest::new(); 25 | 26 | let imports: ast::ImportPath = vec![ast::ImportName::new(Ident::new("import1"))]; 27 | let import_stm = ast::MainStatement::Import(imports); 28 | 29 | let constant1 = ast::Constant { 30 | name: ast::ConstantName::new(Ident::new("const1")), 31 | constant_type: ast::Type::Primitive(ast::PrimitiveTypes::None), 32 | constant_value: ast::ConstantExpression { 33 | value: ast::ConstantValue::Constant(ast::ConstantName::new(Ident::new("const2"))), 34 | operation: None, 35 | }, 36 | }; 37 | let constant_stm = ast::MainStatement::Constant(constant1.clone()); 38 | 39 | let ty = ast::StructTypes { 40 | name: Ident::new("StructType"), 41 | attributes: vec![ast::StructType { 42 | attr_name: Ident::new("y"), 43 | attr_type: ast::Type::Primitive(ast::PrimitiveTypes::U64), 44 | }], 45 | }; 46 | let ty_stm = ast::MainStatement::Types(ty.clone()); 47 | 48 | let let_binding = ast::LetBinding { 49 | name: ast::ValueName::new(Ident::new("x")), 50 | mutable: true, 51 | value_type: None, 52 | value: Box::new(ast::Expression { 53 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool( 54 | false, 55 | )), 56 | operation: None, 57 | }), 58 | }; 59 | let body_let_binding = ast::BodyStatement::LetBinding(let_binding.clone()); 60 | let body_binding = ast::BodyStatement::Binding(ast::Binding { 61 | name: ast::ValueName::new(Ident::new("x")), 62 | value: Box::new(ast::Expression { 63 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool( 64 | true, 65 | )), 66 | operation: None, 67 | }), 68 | }); 69 | let body_fn_call = ast::BodyStatement::FunctionCall(ast::FunctionCall { 70 | name: ast::FunctionName::new(Ident::new("fn2")), 71 | parameters: vec![], 72 | }); 73 | let body_if = ast::BodyStatement::If(ast::IfStatement { 74 | condition: ast::IfCondition::Single(ast::Expression { 75 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool( 76 | true, 77 | )), 78 | operation: Some(( 79 | ast::ExpressionOperations::And, 80 | Box::new(ast::Expression { 81 | expression_value: ast::ExpressionValue::PrimitiveValue( 82 | ast::PrimitiveValue::Bool(true), 83 | ), 84 | operation: None, 85 | }), 86 | )), 87 | }), 88 | body: ast::IfBodyStatements::If(vec![ast::IfBodyStatement::FunctionCall( 89 | ast::FunctionCall { 90 | name: ast::FunctionName::new(Ident::new("fn2")), 91 | parameters: vec![], 92 | }, 93 | )]), 94 | else_statement: None, 95 | else_if_statement: None, 96 | }); 97 | let body_loop = ast::BodyStatement::Loop(vec![ 98 | ast::LoopBodyStatement::If(ast::IfStatement { 99 | condition: ast::IfCondition::Logic(ast::ExpressionLogicCondition { 100 | left: ast::ExpressionCondition { 101 | left: ast::Expression { 102 | expression_value: ast::ExpressionValue::PrimitiveValue( 103 | ast::PrimitiveValue::U32(10), 104 | ), 105 | operation: None, 106 | }, 107 | condition: ast::Condition::GreatEq, 108 | right: ast::Expression { 109 | expression_value: ast::ExpressionValue::PrimitiveValue( 110 | ast::PrimitiveValue::U32(20), 111 | ), 112 | operation: None, 113 | }, 114 | }, 115 | right: Some(( 116 | ast::LogicCondition::Or, 117 | Box::new(ast::ExpressionLogicCondition { 118 | left: ast::ExpressionCondition { 119 | left: ast::Expression { 120 | expression_value: ast::ExpressionValue::PrimitiveValue( 121 | ast::PrimitiveValue::U32(30), 122 | ), 123 | operation: None, 124 | }, 125 | condition: ast::Condition::Less, 126 | right: ast::Expression { 127 | expression_value: ast::ExpressionValue::PrimitiveValue( 128 | ast::PrimitiveValue::U32(40), 129 | ), 130 | operation: None, 131 | }, 132 | }, 133 | right: None, 134 | }), 135 | )), 136 | }), 137 | else_statement: None, 138 | else_if_statement: None, 139 | body: ast::IfBodyStatements::Loop(vec![ 140 | ast::IfLoopBodyStatement::LetBinding(let_binding.clone()), 141 | ast::IfLoopBodyStatement::Break, 142 | ]), 143 | }), 144 | ast::LoopBodyStatement::FunctionCall(ast::FunctionCall { 145 | name: ast::FunctionName::new(Ident::new("fn2")), 146 | parameters: vec![], 147 | }), 148 | ]); 149 | let body_return = ast::BodyStatement::Return(ast::Expression { 150 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 151 | operation: None, 152 | }); 153 | let fn1 = ast::FunctionStatement::new( 154 | ast::FunctionName::new(Ident::new("fn1")), 155 | vec![], 156 | ast::Type::Primitive(ast::PrimitiveTypes::Bool), 157 | vec![ 158 | body_let_binding.clone(), 159 | body_binding, 160 | body_fn_call, 161 | body_if, 162 | body_loop, 163 | body_return.clone(), 164 | ], 165 | ); 166 | let fn1_stm = ast::MainStatement::Function(fn1); 167 | 168 | let body_expr_return = ast::BodyStatement::Expression(ast::Expression { 169 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::U32(23)), 170 | operation: None, 171 | }); 172 | let fn2 = ast::FunctionStatement::new( 173 | ast::FunctionName::new(Ident::new("fn2")), 174 | vec![ast::FunctionParameter { 175 | name: ast::ParameterName::new(Ident::new("x")), 176 | parameter_type: ast::Type::Primitive(ast::PrimitiveTypes::U32), 177 | }], 178 | ast::Type::Primitive(ast::PrimitiveTypes::U32), 179 | vec![body_expr_return], 180 | ); 181 | let fn2_stm = ast::MainStatement::Function(fn2.clone()); 182 | 183 | let main_stm: ast::Main< 184 | CustomExpressionInstruction, 185 | CustomExpression, 186 | > = vec![import_stm, constant_stm, ty_stm, fn1_stm, fn2_stm]; 187 | let json = serde_json::to_string(&main_stm).unwrap(); 188 | let ser_ast: ast::Main< 189 | CustomExpressionInstruction, 190 | CustomExpression, 191 | > = serde_json::from_str(&json).unwrap(); 192 | assert_eq!(main_stm, ser_ast); 193 | 194 | t.state.run(&main_stm); 195 | assert!(t.is_empty_error()); 196 | let _json_state = serde_json::to_string(&t.state).unwrap(); 197 | } 198 | 199 | #[test] 200 | fn ident_serialize() { 201 | let id = Ident::new("x"); 202 | let id_json = serde_json::to_string(&id).unwrap(); 203 | assert_eq!( 204 | id_json, 205 | r#"{"offset":0,"line":1,"fragment":"x","extra":null}"# 206 | ); 207 | let new_id: Ident = serde_json::from_str(&id_json).unwrap(); 208 | assert_eq!(id, new_id); 209 | } 210 | 211 | #[test] 212 | fn ast_extended_serde_check() { 213 | // It covers uncovered serde parts 214 | let pv = ast::PrimitiveValue::None; 215 | let to_json = serde_json::to_string(&pv).unwrap(); 216 | let to_val = serde_json::from_str(&to_json).unwrap(); 217 | assert_eq!(pv, to_val); 218 | 219 | let pv = ast::PrimitiveValue::Ptr; 220 | let to_json = serde_json::to_string(&pv).unwrap(); 221 | let to_val = serde_json::from_str(&to_json).unwrap(); 222 | assert_eq!(pv, to_val); 223 | 224 | let pv = ast::PrimitiveValue::F32(1.2); 225 | let to_json = serde_json::to_string(&pv).unwrap(); 226 | let to_val = serde_json::from_str(&to_json).unwrap(); 227 | assert_eq!(pv, to_val); 228 | 229 | let cl = ast::CodeLocation::new(10, 20); 230 | let to_json = serde_json::to_string(&cl).unwrap(); 231 | let to_val = serde_json::from_str(&to_json).unwrap(); 232 | assert_eq!(cl, to_val); 233 | 234 | let est = ast::ExpressionStructValue { 235 | name: ast::ValueName::new(Ident::new("x")), 236 | attribute: ast::ValueName::new(Ident::new("y")), 237 | }; 238 | let to_json = serde_json::to_string(&est).unwrap(); 239 | let to_val = serde_json::from_str(&to_json).unwrap(); 240 | assert_eq!(est, to_val); 241 | 242 | let lbs = ast::LoopBodyStatement::< 243 | CustomExpressionInstruction, 244 | CustomExpression, 245 | >::Continue; 246 | let to_json = serde_json::to_string(&lbs).unwrap(); 247 | let to_val = serde_json::from_str(&to_json).unwrap(); 248 | assert_eq!(lbs, to_val); 249 | } 250 | 251 | #[test] 252 | fn semantic_extended_serde_check() { 253 | // It covers uncovered serde parts 254 | let iv: InnerValueName = "x".into(); 255 | let to_json = serde_json::to_string(&iv).unwrap(); 256 | let to_val = serde_json::from_str(&to_json).unwrap(); 257 | assert_eq!(iv, to_val); 258 | 259 | let lbl: LabelName = String::from("lbl").into(); 260 | let to_json = serde_json::to_string(&lbl).unwrap(); 261 | let to_val = serde_json::from_str(&to_json).unwrap(); 262 | assert_eq!(lbl, to_val); 263 | 264 | let v = Value { 265 | inner_name: "x".into(), 266 | inner_type: Type::Primitive(PrimitiveTypes::Ptr), 267 | mutable: false, 268 | alloca: false, 269 | malloc: false, 270 | }; 271 | let to_json = serde_json::to_string(&v).unwrap(); 272 | let to_val = serde_json::from_str(&to_json).unwrap(); 273 | assert_eq!(v, to_val); 274 | 275 | let parent_bs: BlockState = BlockState::new(None); 276 | let bs = BlockState::new(Some(Rc::new(RefCell::new(parent_bs)))); 277 | let to_json = serde_json::to_string(&bs).unwrap(); 278 | let _to_val: BlockState = 279 | serde_json::from_str(&to_json).unwrap(); 280 | 281 | let lcond = LogicCondition::Or; 282 | let to_json = serde_json::to_string(&lcond).unwrap(); 283 | let to_val = serde_json::from_str(&to_json).unwrap(); 284 | assert_eq!(lcond, to_val); 285 | 286 | let cond = Condition::GreatEq; 287 | let to_json = serde_json::to_string(&cond).unwrap(); 288 | let to_val = serde_json::from_str(&to_json).unwrap(); 289 | assert_eq!(cond, to_val); 290 | 291 | let lbs = LoopBodyStatement::Break; 292 | let to_json = serde_json::to_string(&lbs).unwrap(); 293 | let to_val = serde_json::from_str(&to_json).unwrap(); 294 | assert_eq!(lbs, to_val); 295 | 296 | let lbs = IfLoopBodyStatement::Break; 297 | let to_json = serde_json::to_string(&lbs).unwrap(); 298 | let to_val = serde_json::from_str(&to_json).unwrap(); 299 | assert_eq!(lbs, to_val); 300 | 301 | let pv = PrimitiveValue::Ptr; 302 | let to_json = serde_json::to_string(&pv).unwrap(); 303 | let to_val = serde_json::from_str(&to_json).unwrap(); 304 | assert_eq!(pv, to_val); 305 | 306 | let ex_res = ExpressionResult { 307 | expr_type: Type::Primitive(PrimitiveTypes::None), 308 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Ptr), 309 | }; 310 | let to_json = serde_json::to_string(&ex_res).unwrap(); 311 | let to_val = serde_json::from_str(&to_json).unwrap(); 312 | assert_eq!(ex_res, to_val); 313 | 314 | let ex_s = ExpressionStructValue { 315 | name: "x".to_string().into(), 316 | attribute: "y".to_string().into(), 317 | }; 318 | let to_json = serde_json::to_string(&ex_s).unwrap(); 319 | let to_val = serde_json::from_str(&to_json).unwrap(); 320 | assert_eq!(ex_s, to_val); 321 | 322 | let exp_op = ExpressionOperations::And; 323 | let to_json = serde_json::to_string(&exp_op).unwrap(); 324 | let to_val = serde_json::from_str(&to_json).unwrap(); 325 | assert_eq!(exp_op, to_val); 326 | 327 | let state_err = StateErrorResult { 328 | kind: StateErrorKind::Common, 329 | value: "test".to_string(), 330 | location: StateErrorLocation(CodeLocation::new(10, 20)), 331 | }; 332 | let to_json = serde_json::to_string(&state_err).unwrap(); 333 | let to_val = serde_json::from_str(&to_json).unwrap(); 334 | assert_eq!(state_err, to_val); 335 | 336 | let expr_raw = r#""x""#; 337 | let ext_expr: ExtendedExpressionValue = serde_json::from_str(expr_raw).unwrap(); 338 | let to_json = serde_json::to_string(&ext_expr).unwrap(); 339 | assert_eq!(to_json, expr_raw); 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /src/types/mod.rs: -------------------------------------------------------------------------------- 1 | //! # Types 2 | //! Semantic analyzer type. 3 | //! Contains basic entities: 4 | //! - Semantic types system 5 | //! - Semantic basic elements types 6 | //! - Block state types 7 | //! - Error types 8 | 9 | #![allow(clippy::module_inception)] 10 | 11 | /// Block state types 12 | pub mod block_state; 13 | /// Condition types 14 | pub mod condition; 15 | /// Error types 16 | pub mod error; 17 | /// Expression types 18 | pub mod expression; 19 | /// Basic semantic types 20 | pub mod semantic; 21 | /// Types for type system 22 | pub mod types; 23 | 24 | use self::condition::{IfStatement, LoopBodyStatement}; 25 | use self::expression::{Expression, ExpressionOperations}; 26 | use self::types::Type; 27 | use crate::ast; 28 | use crate::ast::GetName; 29 | use crate::types::semantic::{ExtendedExpression, SemanticContextInstruction}; 30 | #[cfg(feature = "codec")] 31 | use serde::{Deserialize, Serialize}; 32 | use std::fmt::Display; 33 | 34 | /// Value name type 35 | #[derive(Debug, Clone, Eq, Hash, PartialEq)] 36 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 37 | pub struct ValueName(String); 38 | 39 | impl From> for ValueName { 40 | fn from(value: ast::ValueName<'_>) -> Self { 41 | Self(value.name()) 42 | } 43 | } 44 | 45 | impl From for ValueName { 46 | fn from(value: String) -> Self { 47 | Self(value) 48 | } 49 | } 50 | 51 | impl From<&str> for ValueName { 52 | fn from(value: &str) -> Self { 53 | Self(value.to_string()) 54 | } 55 | } 56 | 57 | impl Display for ValueName { 58 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 59 | write!(f, "{}", self.0.clone()) 60 | } 61 | } 62 | 63 | /// Inner value name type 64 | #[derive(Debug, Clone, Eq, Hash, PartialEq)] 65 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 66 | pub struct InnerValueName(String); 67 | 68 | impl From for InnerValueName { 69 | fn from(value: ValueName) -> Self { 70 | Self(value.0) 71 | } 72 | } 73 | 74 | impl From for InnerValueName { 75 | fn from(value: String) -> Self { 76 | Self(value) 77 | } 78 | } 79 | 80 | impl From<&str> for InnerValueName { 81 | fn from(value: &str) -> Self { 82 | Self(value.to_string()) 83 | } 84 | } 85 | 86 | impl Display for InnerValueName { 87 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 88 | write!(f, "{}", self.0.clone()) 89 | } 90 | } 91 | 92 | /// Label name type 93 | #[derive(Debug, Clone, Eq, Hash, PartialEq)] 94 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 95 | pub struct LabelName(String); 96 | 97 | impl From for LabelName { 98 | fn from(value: String) -> Self { 99 | Self(value) 100 | } 101 | } 102 | 103 | impl Display for LabelName { 104 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 105 | write!(f, "{}", self.0.clone()) 106 | } 107 | } 108 | 109 | /// Function name type 110 | #[derive(Debug, Clone, Eq, Hash, PartialEq)] 111 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 112 | pub struct FunctionName(String); 113 | 114 | impl From for FunctionName { 115 | fn from(value: String) -> Self { 116 | Self(value) 117 | } 118 | } 119 | 120 | impl From> for FunctionName { 121 | fn from(value: ast::FunctionName<'_>) -> Self { 122 | Self(value.to_string()) 123 | } 124 | } 125 | 126 | impl Display for FunctionName { 127 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 128 | write!(f, "{}", self.0.clone()) 129 | } 130 | } 131 | 132 | /// Constant name type 133 | #[derive(Debug, Clone, Eq, Hash, PartialEq)] 134 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 135 | pub struct ConstantName(String); 136 | 137 | impl From> for ConstantName { 138 | fn from(value: ast::ConstantName<'_>) -> Self { 139 | Self(value.name()) 140 | } 141 | } 142 | 143 | impl From for ConstantName { 144 | fn from(value: String) -> Self { 145 | Self(value) 146 | } 147 | } 148 | 149 | impl Display for ConstantName { 150 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 151 | write!(f, "{}", self.0.clone()) 152 | } 153 | } 154 | 155 | /// Constant value can contain other constant or primitive value 156 | #[derive(Debug, Clone, PartialEq)] 157 | #[cfg_attr( 158 | feature = "codec", 159 | derive(Serialize, Deserialize), 160 | serde(tag = "type", content = "content") 161 | )] 162 | pub enum ConstantValue { 163 | Constant(ConstantName), 164 | Value(PrimitiveValue), 165 | } 166 | 167 | impl From> for ConstantValue { 168 | fn from(value: ast::ConstantValue<'_>) -> Self { 169 | match value { 170 | ast::ConstantValue::Constant(v) => Self::Constant(v.into()), 171 | ast::ConstantValue::Value(v) => Self::Value(v.into()), 172 | } 173 | } 174 | } 175 | 176 | /// Constant expression represent expression operation between 177 | /// constant values, and represent flat tree 178 | #[derive(Debug, Clone, PartialEq)] 179 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 180 | pub struct ConstantExpression { 181 | /// Constant value for expression operation 182 | pub value: ConstantValue, 183 | /// Optional expression operation and next constant expression entry point 184 | pub operation: Option<(ExpressionOperations, Box)>, 185 | } 186 | 187 | impl From> for ConstantExpression { 188 | fn from(value: ast::ConstantExpression<'_>) -> Self { 189 | Self { 190 | value: value.value.into(), 191 | operation: value 192 | .operation 193 | .map(|(op, expr)| (op.into(), Box::new(expr.as_ref().clone().into()))), 194 | } 195 | } 196 | } 197 | 198 | /// # Constant 199 | /// Can contain: name, type 200 | #[derive(Debug, Clone, PartialEq)] 201 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 202 | pub struct Constant { 203 | /// Constant name 204 | pub name: ConstantName, 205 | /// Constant type 206 | pub constant_type: Type, 207 | /// Constant value represented through constant expression 208 | pub constant_value: ConstantExpression, 209 | } 210 | 211 | impl From> for Constant { 212 | fn from(value: ast::Constant<'_>) -> Self { 213 | Self { 214 | name: value.name.into(), 215 | constant_type: value.constant_type.into(), 216 | constant_value: value.constant_value.into(), 217 | } 218 | } 219 | } 220 | 221 | /// # Values 222 | /// Can contain inner data: name, type, memory allocation status: 223 | /// - alloca - stack allocation 224 | /// - malloc - malloc allocation 225 | #[derive(Debug, Clone, Eq, PartialEq)] 226 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 227 | pub struct Value { 228 | /// Inner value name 229 | pub inner_name: InnerValueName, 230 | /// Inner value type 231 | pub inner_type: Type, 232 | /// Mutability flag 233 | pub mutable: bool, 234 | /// Stack allocation flag 235 | pub alloca: bool, 236 | /// Memory allocation flag 237 | pub malloc: bool, 238 | } 239 | 240 | /// # Function 241 | /// Function declaration analyze contains: 242 | /// - function name 243 | /// - function type 244 | /// - parameters of functions (with types only) 245 | /// 246 | /// It used to detect functions in state and 247 | /// their parameters to use in normal execution 248 | /// flog. 249 | #[derive(Debug, Clone, Eq, PartialEq)] 250 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 251 | pub struct Function { 252 | /// Inner function name 253 | pub inner_name: FunctionName, 254 | /// Inner (return) type 255 | pub inner_type: Type, 256 | /// Function parameters types 257 | pub parameters: Vec, 258 | } 259 | 260 | /// Parameter name type for Functions parameter 261 | #[derive(Debug, Clone, PartialEq, Eq)] 262 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 263 | pub struct ParameterName(String); 264 | 265 | impl From> for ParameterName { 266 | fn from(value: ast::ParameterName<'_>) -> Self { 267 | Self(value.to_string()) 268 | } 269 | } 270 | 271 | /// Function parameter one of the basic entity for `FunctionStatement` 272 | #[derive(Debug, Clone, Eq, PartialEq)] 273 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 274 | pub struct FunctionParameter { 275 | /// Function parameter name 276 | pub name: ParameterName, 277 | /// Function parameter type 278 | pub parameter_type: Type, 279 | } 280 | 281 | impl From> for FunctionParameter { 282 | fn from(value: ast::FunctionParameter<'_>) -> Self { 283 | Self { 284 | name: value.name.into(), 285 | parameter_type: value.parameter_type.into(), 286 | } 287 | } 288 | } 289 | 290 | impl Display for FunctionParameter { 291 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 292 | write!(f, "{}", self.name.0.clone()) 293 | } 294 | } 295 | 296 | /// # Function statement 297 | /// Function statement is basic type that represent function itself. 298 | /// The basic function struct elements: 299 | /// - function name 300 | /// - function parameters 301 | /// - function result type 302 | /// - function body statements 303 | #[derive(Debug, PartialEq, Clone)] 304 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 305 | pub struct FunctionStatement { 306 | /// Function name 307 | pub name: FunctionName, 308 | /// Function parameters 309 | pub parameters: Vec, 310 | /// Function result type 311 | pub result_type: Type, 312 | /// Function body statements 313 | pub body: Vec, 314 | } 315 | 316 | impl> From> 317 | for FunctionStatement 318 | { 319 | fn from(value: ast::FunctionStatement<'_, I, E>) -> Self { 320 | Self { 321 | name: value.name.into(), 322 | parameters: value.parameters.iter().map(|v| v.clone().into()).collect(), 323 | result_type: value.result_type.into(), 324 | body: value.body.iter().map(|v| v.clone().into()).collect(), 325 | } 326 | } 327 | } 328 | 329 | /// # Body statement 330 | /// Statement of body. Body is basic entity for functions and 331 | /// represent basic functions elements. 332 | #[derive(Debug, Clone, PartialEq)] 333 | #[cfg_attr( 334 | feature = "codec", 335 | derive(Serialize, Deserialize), 336 | serde(tag = "type", content = "content") 337 | )] 338 | pub enum BodyStatement { 339 | LetBinding(LetBinding), 340 | Binding(Binding), 341 | FunctionCall(FunctionCall), 342 | If(IfStatement), 343 | Loop(Vec), 344 | Expression(Expression), 345 | Return(Expression), 346 | } 347 | 348 | impl> From> 349 | for BodyStatement 350 | { 351 | fn from(value: ast::BodyStatement<'_, I, E>) -> Self { 352 | match value { 353 | ast::BodyStatement::LetBinding(v) => Self::LetBinding(v.into()), 354 | ast::BodyStatement::Binding(v) => Self::Binding(v.into()), 355 | ast::BodyStatement::FunctionCall(v) => Self::FunctionCall(v.into()), 356 | ast::BodyStatement::If(v) => Self::If(v.into()), 357 | ast::BodyStatement::Loop(v) => Self::Loop(v.iter().map(|v| v.clone().into()).collect()), 358 | ast::BodyStatement::Expression(v) => Self::Expression(v.into()), 359 | ast::BodyStatement::Return(v) => Self::Return(v.into()), 360 | } 361 | } 362 | } 363 | 364 | /// # Let binding 365 | /// Value initialization through binding. 366 | #[derive(Debug, Clone, PartialEq)] 367 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 368 | pub struct LetBinding { 369 | /// Value name 370 | pub name: ValueName, 371 | /// Value mutability flag 372 | pub mutable: bool, 373 | /// Value type 374 | pub value_type: Option, 375 | /// Value bind expression 376 | pub value: Box, 377 | } 378 | 379 | impl Display for LetBinding { 380 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 381 | write!(f, "{}", self.name) 382 | } 383 | } 384 | 385 | impl> From> 386 | for LetBinding 387 | { 388 | fn from(value: ast::LetBinding<'_, I, E>) -> Self { 389 | Self { 390 | name: value.name.into(), 391 | mutable: value.mutable, 392 | value_type: value.value_type.map(Into::into), 393 | value: Box::new(value.value.as_ref().clone().into()), 394 | } 395 | } 396 | } 397 | 398 | /// Primitive value is most primitive and basic values entity. 399 | /// It's basic elements for all other values elements. 400 | #[derive(Debug, Clone, PartialEq)] 401 | #[cfg_attr( 402 | feature = "codec", 403 | derive(Serialize, Deserialize), 404 | serde(tag = "type", content = "content") 405 | )] 406 | pub enum PrimitiveValue { 407 | U8(u8), 408 | U16(u16), 409 | U32(u32), 410 | U64(u64), 411 | I8(i8), 412 | I16(i16), 413 | I32(i32), 414 | I64(i64), 415 | F32(f32), 416 | F64(f64), 417 | Bool(bool), 418 | Char(char), 419 | Ptr, 420 | None, 421 | } 422 | 423 | impl From for PrimitiveValue { 424 | fn from(value: ast::PrimitiveValue) -> Self { 425 | match value { 426 | ast::PrimitiveValue::U8(v) => Self::U8(v), 427 | ast::PrimitiveValue::U16(v) => Self::U16(v), 428 | ast::PrimitiveValue::U32(v) => Self::U32(v), 429 | ast::PrimitiveValue::U64(v) => Self::U64(v), 430 | ast::PrimitiveValue::I8(v) => Self::I8(v), 431 | ast::PrimitiveValue::I16(v) => Self::I16(v), 432 | ast::PrimitiveValue::I32(v) => Self::I32(v), 433 | ast::PrimitiveValue::I64(v) => Self::I64(v), 434 | ast::PrimitiveValue::F32(v) => Self::F32(v), 435 | ast::PrimitiveValue::F64(v) => Self::F64(v), 436 | ast::PrimitiveValue::Bool(v) => Self::Bool(v), 437 | ast::PrimitiveValue::Char(v) => Self::Char(v), 438 | ast::PrimitiveValue::Ptr => Self::Ptr, 439 | ast::PrimitiveValue::None => Self::None, 440 | } 441 | } 442 | } 443 | 444 | impl Display for PrimitiveValue { 445 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 446 | let str = match self { 447 | Self::U8(val) => val.clone().to_string(), 448 | Self::U16(val) => val.clone().to_string(), 449 | Self::U32(val) => val.clone().to_string(), 450 | Self::U64(val) => val.clone().to_string(), 451 | Self::I8(val) => val.clone().to_string(), 452 | Self::I16(val) => val.clone().to_string(), 453 | Self::I32(val) => val.clone().to_string(), 454 | Self::I64(val) => val.clone().to_string(), 455 | Self::F32(val) => val.clone().to_string(), 456 | Self::F64(val) => val.clone().to_string(), 457 | Self::Bool(val) => val.to_string(), 458 | Self::Char(c) => format!("{c}"), 459 | Self::Ptr => "ptr".to_string(), 460 | Self::None => "None".to_string(), 461 | }; 462 | write!(f, "{str}") 463 | } 464 | } 465 | 466 | /// # Function call 467 | /// Basic struct for function call representation 468 | #[derive(Debug, Clone, PartialEq)] 469 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 470 | pub struct FunctionCall { 471 | /// Call function name 472 | pub name: FunctionName, 473 | /// Call function parameters contains expressions 474 | pub parameters: Vec, 475 | } 476 | 477 | impl Display for FunctionCall { 478 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 479 | write!(f, "{}", self.name) 480 | } 481 | } 482 | 483 | impl> From> 484 | for FunctionCall 485 | { 486 | fn from(value: ast::FunctionCall<'_, I, E>) -> Self { 487 | Self { 488 | name: value.name.into(), 489 | parameters: value.parameters.iter().map(|v| v.clone().into()).collect(), 490 | } 491 | } 492 | } 493 | 494 | /// `Binding` represents mutable binding for previously bind values 495 | #[derive(Debug, Clone, PartialEq)] 496 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 497 | pub struct Binding { 498 | /// Binding value name 499 | pub name: ValueName, 500 | /// Value expression representation 501 | pub value: Box, 502 | } 503 | 504 | impl Display for Binding { 505 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 506 | write!(f, "{}", self.name) 507 | } 508 | } 509 | 510 | impl> From> 511 | for Binding 512 | { 513 | fn from(value: ast::Binding<'_, I, E>) -> Self { 514 | Self { 515 | name: value.name.into(), 516 | value: Box::new(value.value.as_ref().clone().into()), 517 | } 518 | } 519 | } 520 | -------------------------------------------------------------------------------- /src/types/block_state.rs: -------------------------------------------------------------------------------- 1 | //! # Block State types 2 | //! Block state Semantic types. 3 | 4 | use super::semantic::{ExtendedSemanticContext, SemanticContextInstruction, SemanticStack}; 5 | use super::{Constant, Function, FunctionParameter, InnerValueName, LabelName, Value, ValueName}; 6 | use crate::types::condition::{Condition, LogicCondition}; 7 | use crate::types::expression::{ExpressionOperations, ExpressionResult}; 8 | use crate::types::semantic::SemanticContext; 9 | #[cfg(feature = "codec")] 10 | use serde::{Deserialize, Serialize}; 11 | use std::cell::RefCell; 12 | use std::collections::{HashMap, HashSet}; 13 | use std::rc::Rc; 14 | 15 | /// # Block state 16 | /// - `values` - contains unique values map for current state but not unique 17 | /// for parent states. The map contains key-value: `value_name` (unique 18 | /// only for current state); and `Value` itself - value parameters. 19 | /// - `inner_values_name` - is entity that represent inner value name - it 20 | /// can be different from `Value` name because it should be unique for all 21 | /// parent states. For example, of 3 values with name `x`, inner value 22 | /// name will be: [`x`, `x.0`, `x.1`]. It mean, inner value name can 23 | /// contain `value counter` as end of the name. 24 | /// - `labels` - labels set, for conditional operation. Unique for current 25 | /// and all paren states. 26 | /// - `last_register_number` - represent register counter for current and 27 | /// all parent states for `Codegen`. Register represented as `u64` and 28 | /// should be linearly incremented. 29 | /// - `manual_return` - flag indicated, that return was invoked from 30 | /// other state, for example: if-flow, loop-flow 31 | /// - `parent` - represent parent states. 32 | #[derive(Debug)] 33 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 34 | pub struct BlockState { 35 | /// State values 36 | pub values: HashMap, 37 | /// Used to keep all names in the block state (and parent) as unique 38 | pub inner_values_name: HashSet, 39 | /// State labels for conditional operations 40 | pub labels: HashSet, 41 | /// Last register for unique register representation 42 | pub last_register_number: u64, 43 | /// Manual return from other states 44 | pub manual_return: bool, 45 | /// Parent state 46 | #[cfg_attr( 47 | feature = "codec", 48 | serde( 49 | serialize_with = "rc_serializer::serialize_option", 50 | deserialize_with = "rc_serializer::deserialize_option" 51 | ) 52 | )] 53 | pub parent: Option>>>, 54 | /// children states 55 | #[cfg_attr( 56 | feature = "codec", 57 | serde( 58 | serialize_with = "rc_serializer::serialize_vec", 59 | deserialize_with = "rc_serializer::deserialize_vec" 60 | ) 61 | )] 62 | pub children: Vec>>>, 63 | /// Semantic stack context for Block state 64 | context: SemanticStack, 65 | } 66 | 67 | impl BlockState { 68 | /// Init block state with optional `parent` state 69 | #[must_use] 70 | pub fn new(parent: Option>>) -> Self { 71 | // Get values from parent 72 | let (last_register_number, inner_values_name, labels, manual_return) = 73 | parent.clone().map_or_else( 74 | || (0, HashSet::new(), HashSet::new(), false), 75 | |p| { 76 | let parent = p.borrow(); 77 | ( 78 | parent.last_register_number, 79 | parent.inner_values_name.clone(), 80 | parent.labels.clone(), 81 | parent.manual_return, 82 | ) 83 | }, 84 | ); 85 | Self { 86 | values: HashMap::new(), 87 | children: vec![], 88 | inner_values_name, 89 | labels, 90 | last_register_number, 91 | manual_return, 92 | parent, 93 | context: SemanticStack::new(), 94 | } 95 | } 96 | 97 | #[must_use] 98 | pub fn get_context(&self) -> SemanticStack { 99 | self.context.clone() 100 | } 101 | 102 | /// Set `last_register_number` for current and parent states 103 | fn set_register(&mut self, last_register_number: u64) { 104 | self.last_register_number = last_register_number; 105 | // Set `last_register_number` for parents 106 | if let Some(parent) = &self.parent { 107 | parent.borrow_mut().set_register(last_register_number); 108 | } 109 | } 110 | 111 | /// Increment register 112 | pub fn inc_register(&mut self) { 113 | self.set_register(self.last_register_number + 1); 114 | } 115 | 116 | /// Get child Block state 117 | pub fn set_child(&mut self, child: Rc>) { 118 | self.children.push(child); 119 | } 120 | 121 | /// Set value inner name to current state and parent states 122 | pub fn set_inner_value_name(&mut self, name: &InnerValueName) { 123 | self.inner_values_name.insert(name.clone()); 124 | if let Some(parent) = &self.parent { 125 | parent.borrow_mut().set_inner_value_name(name); 126 | } 127 | } 128 | 129 | /// Check is `inner_value_name` exist in current and parent states 130 | #[must_use] 131 | pub fn is_inner_value_name_exist(&self, name: &InnerValueName) -> bool { 132 | if self.inner_values_name.contains(name) { 133 | return true; 134 | } else if let Some(parent) = &self.parent { 135 | return parent.borrow().is_inner_value_name_exist(name); 136 | } 137 | false 138 | } 139 | 140 | /// Get `Value` by value name from current state. 141 | /// If not found on current state - recursively find in parent states. 142 | #[must_use] 143 | pub fn get_value_name(&self, name: &ValueName) -> Option { 144 | if let Some(val) = self.values.get(name) { 145 | return Some(val.clone()); 146 | } else if let Some(parent) = &self.parent { 147 | return parent.borrow().get_value_name(name); 148 | } 149 | None 150 | } 151 | 152 | /// Check is label name exist in current and parent states 153 | #[must_use] 154 | pub fn is_label_name_exist(&self, name: &LabelName) -> bool { 155 | if self.labels.contains(name) { 156 | return true; 157 | } else if let Some(parent) = &self.parent { 158 | return parent.borrow().is_label_name_exist(name); 159 | } 160 | false 161 | } 162 | 163 | /// Set label name to current and all parent states 164 | pub fn set_label_name(&mut self, name: &LabelName) { 165 | self.labels.insert(name.clone()); 166 | if let Some(parent) = &self.parent { 167 | parent.borrow_mut().set_label_name(name); 168 | } 169 | } 170 | 171 | /// Set attribute counter - increment, if counter exist. 172 | #[must_use] 173 | pub fn set_attr_counter(val: &str) -> String { 174 | let val_attr: Vec<&str> = val.split('.').collect(); 175 | if val_attr.len() == 2 { 176 | let i: u64 = val_attr[1].parse().unwrap_or_default(); 177 | format!("{}.{:?}", val_attr[0], i + 1) 178 | } else { 179 | format!("{}.0", val_attr[0]) 180 | } 181 | } 182 | 183 | /// Get and set next label for condition operations 184 | /// - If label doesn't exist in State - just insert to State and 185 | /// self return 186 | /// - if label exists, get label counter 187 | pub fn get_and_set_next_label(&mut self, label: &LabelName) -> LabelName { 188 | // Check is label exists. If doesn't set it to State and return self 189 | if !self.is_label_name_exist(label) { 190 | self.set_label_name(label); 191 | return label.clone(); 192 | } 193 | // If label exists, split and get number of label counter 194 | let name: LabelName = Self::set_attr_counter(&label.to_string()).into(); 195 | if self.is_label_name_exist(&name) { 196 | self.get_and_set_next_label(&name) 197 | } else { 198 | self.set_label_name(&name); 199 | name 200 | } 201 | } 202 | 203 | /// Get next `inner_value_name` by name counter for current and 204 | /// parent states. The `inner_value_name` should always be unique. 205 | #[must_use] 206 | pub fn get_next_inner_name(&self, val: &InnerValueName) -> InnerValueName { 207 | // Increment inner value name counter for shadowed variable 208 | let name: InnerValueName = Self::set_attr_counter(&val.to_string()).into(); 209 | if self.is_inner_value_name_exist(&name) { 210 | self.get_next_inner_name(&name) 211 | } else { 212 | name 213 | } 214 | } 215 | 216 | /// Set return status flag for current and parent states 217 | pub fn set_return(&mut self) { 218 | self.manual_return = true; 219 | if let Some(parent) = &self.parent { 220 | parent.borrow_mut().set_return(); 221 | } 222 | } 223 | } 224 | 225 | impl SemanticContext for BlockState { 226 | fn expression_value(&mut self, expression: Value, register_number: u64) { 227 | self.context 228 | .expression_value(expression.clone(), register_number); 229 | if let Some(parent) = &self.parent { 230 | parent 231 | .borrow_mut() 232 | .expression_value(expression, register_number); 233 | } 234 | } 235 | 236 | fn expression_const(&mut self, expression: Constant, register_number: u64) { 237 | self.context 238 | .expression_const(expression.clone(), register_number); 239 | if let Some(parent) = &self.parent { 240 | parent 241 | .borrow_mut() 242 | .expression_const(expression, register_number); 243 | } 244 | } 245 | 246 | fn expression_struct_value(&mut self, expression: Value, index: u32, register_number: u64) { 247 | self.context 248 | .expression_struct_value(expression.clone(), index, register_number); 249 | if let Some(parent) = &self.parent { 250 | parent 251 | .borrow_mut() 252 | .expression_struct_value(expression, index, register_number); 253 | } 254 | } 255 | 256 | fn expression_operation( 257 | &mut self, 258 | operation: ExpressionOperations, 259 | left_value: ExpressionResult, 260 | right_value: ExpressionResult, 261 | register_number: u64, 262 | ) { 263 | self.context.expression_operation( 264 | operation.clone(), 265 | left_value.clone(), 266 | right_value.clone(), 267 | register_number, 268 | ); 269 | if let Some(parent) = &self.parent { 270 | parent.borrow_mut().expression_operation( 271 | operation, 272 | left_value, 273 | right_value, 274 | register_number, 275 | ); 276 | } 277 | } 278 | 279 | fn call(&mut self, call: Function, params: Vec, register_number: u64) { 280 | self.context 281 | .call(call.clone(), params.clone(), register_number); 282 | if let Some(parent) = &self.parent { 283 | parent.borrow_mut().call(call, params, register_number); 284 | } 285 | } 286 | 287 | fn let_binding(&mut self, let_decl: Value, expr_result: ExpressionResult) { 288 | self.context 289 | .let_binding(let_decl.clone(), expr_result.clone()); 290 | if let Some(parent) = &self.parent { 291 | parent.borrow_mut().let_binding(let_decl, expr_result); 292 | } 293 | } 294 | 295 | fn binding(&mut self, val: Value, expr_result: ExpressionResult) { 296 | self.context.binding(val.clone(), expr_result.clone()); 297 | if let Some(parent) = &self.parent { 298 | parent.borrow_mut().binding(val, expr_result); 299 | } 300 | } 301 | 302 | fn expression_function_return(&mut self, expr_result: ExpressionResult) { 303 | self.context.expression_function_return(expr_result.clone()); 304 | if let Some(parent) = &self.parent { 305 | parent.borrow_mut().expression_function_return(expr_result); 306 | } 307 | } 308 | 309 | fn expression_function_return_with_label(&mut self, expr_result: ExpressionResult) { 310 | self.context 311 | .expression_function_return_with_label(expr_result.clone()); 312 | if let Some(parent) = &self.parent { 313 | parent 314 | .borrow_mut() 315 | .expression_function_return_with_label(expr_result); 316 | } 317 | } 318 | 319 | fn set_label(&mut self, label: LabelName) { 320 | self.context.set_label(label.clone()); 321 | if let Some(parent) = &self.parent { 322 | parent.borrow_mut().set_label(label); 323 | } 324 | } 325 | 326 | fn jump_to(&mut self, label: LabelName) { 327 | self.context.jump_to(label.clone()); 328 | if let Some(parent) = &self.parent { 329 | parent.borrow_mut().jump_to(label); 330 | } 331 | } 332 | 333 | fn if_condition_expression( 334 | &mut self, 335 | expr_result: ExpressionResult, 336 | label_if_begin: LabelName, 337 | label_if_end: LabelName, 338 | ) { 339 | self.context.if_condition_expression( 340 | expr_result.clone(), 341 | label_if_begin.clone(), 342 | label_if_end.clone(), 343 | ); 344 | if let Some(parent) = &self.parent { 345 | parent 346 | .borrow_mut() 347 | .if_condition_expression(expr_result, label_if_begin, label_if_end); 348 | } 349 | } 350 | 351 | fn condition_expression( 352 | &mut self, 353 | left_result: ExpressionResult, 354 | right_result: ExpressionResult, 355 | condition: Condition, 356 | register_number: u64, 357 | ) { 358 | self.context.condition_expression( 359 | left_result.clone(), 360 | right_result.clone(), 361 | condition.clone(), 362 | register_number, 363 | ); 364 | if let Some(parent) = &self.parent { 365 | parent.borrow_mut().condition_expression( 366 | left_result, 367 | right_result, 368 | condition, 369 | register_number, 370 | ); 371 | } 372 | } 373 | 374 | fn jump_function_return(&mut self, expr_result: ExpressionResult) { 375 | self.context.jump_function_return(expr_result.clone()); 376 | if let Some(parent) = &self.parent { 377 | parent.borrow_mut().jump_function_return(expr_result); 378 | } 379 | } 380 | 381 | fn logic_condition( 382 | &mut self, 383 | logic_condition: LogicCondition, 384 | left_register_result: u64, 385 | right_register_result: u64, 386 | register_number: u64, 387 | ) { 388 | self.context.logic_condition( 389 | logic_condition.clone(), 390 | left_register_result, 391 | right_register_result, 392 | register_number, 393 | ); 394 | if let Some(parent) = &self.parent { 395 | parent.borrow_mut().logic_condition( 396 | logic_condition, 397 | left_register_result, 398 | right_register_result, 399 | register_number, 400 | ); 401 | } 402 | } 403 | 404 | fn if_condition_logic( 405 | &mut self, 406 | label_if_begin: LabelName, 407 | label_if_end: LabelName, 408 | result_register: u64, 409 | ) { 410 | self.context.if_condition_logic( 411 | label_if_begin.clone(), 412 | label_if_end.clone(), 413 | result_register, 414 | ); 415 | if let Some(parent) = &self.parent { 416 | parent 417 | .borrow_mut() 418 | .if_condition_logic(label_if_begin, label_if_end, result_register); 419 | } 420 | } 421 | 422 | fn function_arg(&mut self, value: Value, func_arg: FunctionParameter) { 423 | self.context.function_arg(value.clone(), func_arg.clone()); 424 | if let Some(parent) = &self.parent { 425 | parent.borrow_mut().function_arg(value, func_arg); 426 | } 427 | } 428 | } 429 | 430 | impl ExtendedSemanticContext for BlockState { 431 | fn extended_expression(&mut self, expr: &I) { 432 | self.context.extended_expression(expr); 433 | if let Some(parent) = &self.parent { 434 | parent.borrow_mut().extended_expression(expr); 435 | } 436 | } 437 | } 438 | 439 | /// Custom Serde serializers for `Rc>` 440 | #[cfg(feature = "codec")] 441 | pub mod rc_serializer { 442 | use super::{Rc, RefCell}; 443 | use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer}; 444 | 445 | /// Serializer for `Rc`. 446 | #[allow(clippy::missing_errors_doc)] 447 | pub fn serialize(rc: &Rc>, serializer: S) -> Result 448 | where 449 | S: Serializer, 450 | T: Serialize, 451 | { 452 | T::serialize(&*rc.borrow(), serializer) 453 | } 454 | 455 | /// Serializer for `Option>`. 456 | #[allow(clippy::missing_errors_doc)] 457 | pub fn serialize_option( 458 | val: &Option>>, 459 | serializer: S, 460 | ) -> Result 461 | where 462 | S: Serializer, 463 | T: Serialize, 464 | { 465 | match val { 466 | Some(rc) => serialize(rc, serializer), 467 | None => serializer.serialize_none(), 468 | } 469 | } 470 | 471 | /// Serializer for `Vec>`. 472 | #[allow(clippy::missing_errors_doc)] 473 | pub fn serialize_vec(val: &Vec>>, serializer: S) -> Result 474 | where 475 | S: Serializer, 476 | T: Serialize, 477 | { 478 | let mut seq = serializer.serialize_seq(Some(val.len()))?; 479 | for item in val { 480 | seq.serialize_element(&*item.borrow())?; 481 | } 482 | seq.end() 483 | } 484 | 485 | /// Deserializer for `Rc` 486 | #[allow(clippy::missing_errors_doc)] 487 | pub fn deserialize<'de, D, T>(deserializer: D) -> Result>, D::Error> 488 | where 489 | D: Deserializer<'de>, 490 | T: Deserialize<'de>, 491 | { 492 | let value = T::deserialize(deserializer)?; 493 | Ok(Rc::new(RefCell::new(value))) 494 | } 495 | 496 | /// Deserializer for `Option>` 497 | #[allow(clippy::missing_errors_doc)] 498 | pub fn deserialize_option<'de, D, T>( 499 | deserializer: D, 500 | ) -> Result>>, D::Error> 501 | where 502 | D: Deserializer<'de>, 503 | T: Deserialize<'de>, 504 | { 505 | let opt = Option::::deserialize(deserializer)?; 506 | Ok(opt.map(|value| Rc::new(RefCell::new(value)))) 507 | } 508 | 509 | /// Deserializer for `Vec>` 510 | #[allow(clippy::missing_errors_doc)] 511 | // grcov-excl-start 512 | pub fn deserialize_vec<'de, D, T>(deserializer: D) -> Result>>, D::Error> 513 | where 514 | D: Deserializer<'de>, 515 | T: Deserialize<'de>, 516 | { 517 | let vec = Vec::::deserialize(deserializer)?; 518 | Ok(vec 519 | .into_iter() 520 | .map(|item| Rc::new(RefCell::new(item))) 521 | .collect()) 522 | } // grcov-excl-end 523 | } 524 | -------------------------------------------------------------------------------- /tests/loop_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{CustomExpression, CustomExpressionInstruction, SemanticTest}; 2 | use semantic_analyzer::ast; 3 | use semantic_analyzer::ast::Ident; 4 | use semantic_analyzer::types::block_state::BlockState; 5 | use semantic_analyzer::types::condition::LoopBodyStatement; 6 | use semantic_analyzer::types::error::StateErrorKind; 7 | use semantic_analyzer::types::expression::{ExpressionResult, ExpressionResultValue}; 8 | use semantic_analyzer::types::semantic::SemanticStackContext; 9 | use semantic_analyzer::types::types::{PrimitiveTypes, Type}; 10 | use semantic_analyzer::types::{Function, PrimitiveValue, Value}; 11 | use std::cell::RefCell; 12 | use std::rc::Rc; 13 | 14 | mod utils; 15 | 16 | #[test] 17 | fn loop_transform() { 18 | let let_binding = ast::LetBinding { 19 | name: ast::ValueName::new(Ident::new("x")), 20 | mutable: false, 21 | value_type: None, 22 | value: Box::new(ast::Expression { 23 | expression_value: ast::ExpressionValue::< 24 | CustomExpressionInstruction, 25 | CustomExpression, 26 | >::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 27 | operation: None, 28 | }), 29 | }; 30 | let binding = ast::Binding { 31 | name: ast::ValueName::new(Ident::new("x")), 32 | value: Box::new(ast::Expression { 33 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 34 | operation: None, 35 | }), 36 | }; 37 | let fn_call = ast::FunctionCall { 38 | name: ast::FunctionName::new(Ident::new("fn1")), 39 | parameters: vec![], 40 | }; 41 | let if_statement = ast::IfStatement { 42 | condition: ast::IfCondition::Single(ast::Expression { 43 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::F32(1.2)), 44 | operation: None, 45 | }), 46 | body: ast::IfBodyStatements::If(vec![]), 47 | else_statement: None, 48 | else_if_statement: None, 49 | }; 50 | let loop_statement = ast::LoopBodyStatement::Break; 51 | let return_statement = ast::Expression { 52 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::F32(1.2)), 53 | operation: None, 54 | }; 55 | let loop_stmts = vec![ 56 | ast::LoopBodyStatement::LetBinding(let_binding.clone()), 57 | ast::LoopBodyStatement::Binding(binding.clone()), 58 | ast::LoopBodyStatement::FunctionCall(fn_call.clone()), 59 | ast::LoopBodyStatement::If(if_statement.clone()), 60 | ast::LoopBodyStatement::Loop(vec![loop_statement.clone()]), 61 | ast::LoopBodyStatement::Return(return_statement.clone()), 62 | ast::LoopBodyStatement::Break, 63 | ast::LoopBodyStatement::Continue, 64 | ]; 65 | // For grcov 66 | let _ = format!("{loop_stmts:#?}"); 67 | for loop_stmt in loop_stmts { 68 | let loop_stmt_into: LoopBodyStatement = loop_stmt.into(); 69 | // For grcov 70 | let _ = format!("{loop_stmt_into:#?}"); 71 | match loop_stmt_into { 72 | LoopBodyStatement::LetBinding(val) => assert_eq!(val, let_binding.clone().into()), 73 | LoopBodyStatement::Binding(val) => assert_eq!(val, binding.clone().into()), 74 | LoopBodyStatement::FunctionCall(val) => assert_eq!(val, fn_call.clone().into()), 75 | LoopBodyStatement::If(val) => assert_eq!(val, if_statement.clone().into()), 76 | LoopBodyStatement::Loop(val) => assert_eq!(val, vec![loop_statement.clone().into()]), 77 | LoopBodyStatement::Return(val) => assert_eq!(val, return_statement.clone().into()), 78 | LoopBodyStatement::Break => assert_eq!( 79 | LoopBodyStatement::Break, 80 | ast::LoopBodyStatement::< 81 | CustomExpressionInstruction, 82 | CustomExpression, 83 | >::Break 84 | .into() 85 | ), 86 | LoopBodyStatement::Continue => assert_eq!( 87 | LoopBodyStatement::Continue, 88 | ast::LoopBodyStatement::< 89 | CustomExpressionInstruction, 90 | CustomExpression, 91 | >::Continue 92 | .into() 93 | ), 94 | } 95 | } 96 | } 97 | 98 | #[test] 99 | fn loop_statements() { 100 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 101 | let mut t = SemanticTest::new(); 102 | 103 | let fn2 = ast::FunctionStatement::new( 104 | ast::FunctionName::new(Ident::new("fn2")), 105 | vec![], 106 | ast::Type::Primitive(ast::PrimitiveTypes::U16), 107 | vec![ast::BodyStatement::Expression(ast::Expression { 108 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::U16(23)), 109 | operation: None, 110 | })], 111 | ); 112 | t.state.function_declaration(&fn2); 113 | 114 | let loop_body_let_binding = ast::LoopBodyStatement::LetBinding(ast::LetBinding { 115 | name: ast::ValueName::new(Ident::new("x")), 116 | mutable: true, 117 | value_type: None, 118 | value: Box::new(ast::Expression { 119 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool( 120 | false, 121 | )), 122 | operation: None, 123 | }), 124 | }); 125 | let loop_body_binding = ast::LoopBodyStatement::Binding(ast::Binding { 126 | name: ast::ValueName::new(Ident::new("x")), 127 | value: Box::new(ast::Expression { 128 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 129 | operation: None, 130 | }), 131 | }); 132 | let loop_body_fn_call = ast::LoopBodyStatement::FunctionCall(ast::FunctionCall { 133 | name: ast::FunctionName::new(Ident::new("fn2")), 134 | parameters: vec![], 135 | }); 136 | let loop_body_if = ast::LoopBodyStatement::If(ast::IfStatement { 137 | condition: ast::IfCondition::Single(ast::Expression { 138 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 139 | operation: None, 140 | }), 141 | body: ast::IfBodyStatements::Loop(vec![ast::IfLoopBodyStatement::FunctionCall( 142 | ast::FunctionCall { 143 | name: ast::FunctionName::new(Ident::new("fn2")), 144 | parameters: vec![], 145 | }, 146 | )]), 147 | else_statement: None, 148 | else_if_statement: None, 149 | }); 150 | let loop_body_loop = ast::LoopBodyStatement::Loop(vec![ast::LoopBodyStatement::FunctionCall( 151 | ast::FunctionCall { 152 | name: ast::FunctionName::new(Ident::new("fn2")), 153 | parameters: vec![], 154 | }, 155 | )]); 156 | 157 | let loop_stmt = [ 158 | loop_body_let_binding, 159 | loop_body_binding, 160 | loop_body_fn_call, 161 | loop_body_if, 162 | loop_body_loop, 163 | ]; 164 | t.state.loop_statement(&loop_stmt, &block_state); 165 | 166 | assert!(t.is_empty_error()); 167 | let main_ctx = block_state.borrow().get_context().get(); 168 | assert_eq!(main_ctx.len(), 17); 169 | assert!(block_state.borrow().parent.is_none()); 170 | assert!(block_state.borrow().parent.is_none()); 171 | assert_eq!(block_state.borrow().children.len(), 1); 172 | 173 | let ctx = block_state.borrow().children[0].clone(); 174 | assert!(ctx.borrow().parent.is_some()); 175 | assert_eq!(ctx.borrow().children.len(), 2); 176 | 177 | let ch_ctx1 = ctx.borrow().children[0].clone(); 178 | assert!(ch_ctx1.borrow().parent.is_some()); 179 | assert!(ch_ctx1.borrow().children.is_empty()); 180 | 181 | let ctx1 = ch_ctx1.borrow().get_context().clone().get(); 182 | assert_eq!(ctx1.len(), 5); 183 | assert_eq!( 184 | ctx1[0], 185 | SemanticStackContext::IfConditionExpression { 186 | expr_result: ExpressionResult { 187 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 188 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(true)), 189 | }, 190 | label_if_begin: String::from("if_begin").into(), 191 | label_if_end: String::from("if_end").into(), 192 | } 193 | ); 194 | assert_eq!( 195 | ctx1[1], 196 | SemanticStackContext::SetLabel { 197 | label: String::from("if_begin").into() 198 | } 199 | ); 200 | assert_eq!( 201 | ctx1[2], 202 | SemanticStackContext::Call { 203 | call: Function { 204 | inner_name: String::from("fn2").into(), 205 | inner_type: Type::Primitive(PrimitiveTypes::U16), 206 | parameters: vec![], 207 | }, 208 | params: vec![], 209 | register_number: 2, 210 | } 211 | ); 212 | assert_eq!( 213 | ctx1[3], 214 | SemanticStackContext::JumpTo { 215 | label: String::from("if_end").into() 216 | } 217 | ); 218 | assert_eq!( 219 | ctx1[4], 220 | SemanticStackContext::SetLabel { 221 | label: String::from("if_end").into() 222 | } 223 | ); 224 | 225 | let ch_ctx2 = ctx.borrow().children[1].clone(); 226 | assert!(ch_ctx2.borrow().parent.is_some()); 227 | assert!(ch_ctx2.borrow().children.is_empty()); 228 | 229 | let ctx2 = ch_ctx2.borrow().get_context().clone().get(); 230 | assert_eq!(ctx2.len(), 5); 231 | assert_eq!( 232 | ctx2[0], 233 | SemanticStackContext::JumpTo { 234 | label: String::from("loop_begin.0").into() 235 | } 236 | ); 237 | assert_eq!( 238 | ctx2[1], 239 | SemanticStackContext::SetLabel { 240 | label: String::from("loop_begin.0").into() 241 | } 242 | ); 243 | assert_eq!( 244 | ctx2[2], 245 | SemanticStackContext::Call { 246 | call: Function { 247 | inner_name: String::from("fn2").into(), 248 | inner_type: Type::Primitive(PrimitiveTypes::U16), 249 | parameters: vec![], 250 | }, 251 | params: vec![], 252 | register_number: 3, 253 | } 254 | ); 255 | assert_eq!( 256 | ctx2[3], 257 | SemanticStackContext::JumpTo { 258 | label: String::from("loop_begin.0").into() 259 | } 260 | ); 261 | assert_eq!( 262 | ctx2[4], 263 | SemanticStackContext::SetLabel { 264 | label: String::from("loop_end.0").into() 265 | } 266 | ); 267 | 268 | let stm_ctx = ctx.borrow().get_context().clone().get(); 269 | assert_eq!(stm_ctx.len(), 17); 270 | assert_eq!(stm_ctx, main_ctx); 271 | assert_eq!( 272 | stm_ctx[0], 273 | SemanticStackContext::JumpTo { 274 | label: String::from("loop_begin").into() 275 | } 276 | ); 277 | assert_eq!( 278 | stm_ctx[1], 279 | SemanticStackContext::SetLabel { 280 | label: String::from("loop_begin").into() 281 | } 282 | ); 283 | assert_eq!( 284 | stm_ctx[2], 285 | SemanticStackContext::LetBinding { 286 | let_decl: Value { 287 | inner_name: "x.0".into(), 288 | inner_type: Type::Primitive(PrimitiveTypes::Bool), 289 | mutable: true, 290 | alloca: false, 291 | malloc: false, 292 | }, 293 | expr_result: ExpressionResult { 294 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 295 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(false)), 296 | }, 297 | } 298 | ); 299 | assert_eq!( 300 | stm_ctx[3], 301 | SemanticStackContext::Binding { 302 | val: Value { 303 | inner_name: "x.0".into(), 304 | inner_type: Type::Primitive(PrimitiveTypes::Bool), 305 | mutable: true, 306 | alloca: false, 307 | malloc: false, 308 | }, 309 | expr_result: ExpressionResult { 310 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 311 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(true)), 312 | }, 313 | } 314 | ); 315 | assert_eq!( 316 | stm_ctx[4], 317 | SemanticStackContext::Call { 318 | call: Function { 319 | inner_name: String::from("fn2").into(), 320 | inner_type: Type::Primitive(PrimitiveTypes::U16), 321 | parameters: vec![], 322 | }, 323 | params: vec![], 324 | register_number: 1, 325 | } 326 | ); 327 | assert_eq!(stm_ctx[5], ctx1[0]); 328 | assert_eq!(stm_ctx[6], ctx1[1]); 329 | assert_eq!(stm_ctx[7], ctx1[2]); 330 | assert_eq!(stm_ctx[8], ctx1[3]); 331 | assert_eq!(stm_ctx[9], ctx1[4]); 332 | assert_eq!(stm_ctx[10], ctx2[0]); 333 | assert_eq!(stm_ctx[11], ctx2[1]); 334 | assert_eq!(stm_ctx[12], ctx2[2]); 335 | assert_eq!(stm_ctx[13], ctx2[3]); 336 | assert_eq!(stm_ctx[14], ctx2[4]); 337 | assert_eq!( 338 | stm_ctx[15], 339 | SemanticStackContext::JumpTo { 340 | label: String::from("loop_begin").into() 341 | } 342 | ); 343 | assert_eq!( 344 | stm_ctx[16], 345 | SemanticStackContext::SetLabel { 346 | label: String::from("loop_end").into() 347 | } 348 | ); 349 | } 350 | 351 | #[test] 352 | fn loop_statements_instructions_after_return() { 353 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 354 | let mut t = SemanticTest::new(); 355 | 356 | let loop_body_let_binding = ast::LoopBodyStatement::LetBinding(ast::LetBinding { 357 | name: ast::ValueName::new(Ident::new("x")), 358 | mutable: true, 359 | value_type: None, 360 | value: Box::new(ast::Expression { 361 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool( 362 | false, 363 | )), 364 | operation: None, 365 | }), 366 | }); 367 | let loop_body_return = ast::LoopBodyStatement::Return(ast::Expression { 368 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 369 | operation: None, 370 | }); 371 | 372 | let loop_stmt = [loop_body_return, loop_body_let_binding]; 373 | t.state.loop_statement(&loop_stmt, &block_state); 374 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 375 | assert!( 376 | t.check_error(StateErrorKind::ForbiddenCodeAfterReturnDeprecated), 377 | "Errors: {:?}", 378 | t.state.errors[0] 379 | ); 380 | } 381 | 382 | #[test] 383 | fn loop_statements_instructions_after_break() { 384 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 385 | let mut t = SemanticTest::new(); 386 | 387 | let loop_body_let_binding = ast::LoopBodyStatement::LetBinding(ast::LetBinding { 388 | name: ast::ValueName::new(Ident::new("x")), 389 | mutable: true, 390 | value_type: None, 391 | value: Box::new(ast::Expression { 392 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool( 393 | false, 394 | )), 395 | operation: None, 396 | }), 397 | }); 398 | let loop_body_break = ast::LoopBodyStatement::Break; 399 | 400 | let loop_stmt = [loop_body_break, loop_body_let_binding]; 401 | t.state.loop_statement(&loop_stmt, &block_state); 402 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 403 | assert!( 404 | t.check_error(StateErrorKind::ForbiddenCodeAfterBreakDeprecated), 405 | "Errors: {:?}", 406 | t.state.errors[0] 407 | ); 408 | } 409 | 410 | #[test] 411 | fn loop_statements_instructions_after_continue() { 412 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 413 | let mut t = SemanticTest::new(); 414 | 415 | let loop_body_let_binding = ast::LoopBodyStatement::LetBinding(ast::LetBinding { 416 | name: ast::ValueName::new(Ident::new("x")), 417 | mutable: true, 418 | value_type: None, 419 | value: Box::new(ast::Expression { 420 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool( 421 | false, 422 | )), 423 | operation: None, 424 | }), 425 | }); 426 | let loop_body_continue = ast::LoopBodyStatement::Continue; 427 | 428 | let loop_stmt = [loop_body_continue, loop_body_let_binding]; 429 | t.state.loop_statement(&loop_stmt, &block_state); 430 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 431 | assert!( 432 | t.check_error(StateErrorKind::ForbiddenCodeAfterContinueDeprecated), 433 | "Errors: {:?}", 434 | t.state.errors[0] 435 | ); 436 | } 437 | 438 | #[test] 439 | fn loop_statements_with_return_invocation() { 440 | let block_state = Rc::new(RefCell::new(BlockState::new(None))); 441 | let mut t = SemanticTest::new(); 442 | 443 | let loop_body_let_binding = ast::LoopBodyStatement::LetBinding(ast::LetBinding { 444 | name: ast::ValueName::new(Ident::new("x")), 445 | mutable: true, 446 | value_type: None, 447 | value: Box::new(ast::Expression { 448 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool( 449 | false, 450 | )), 451 | operation: None, 452 | }), 453 | }); 454 | let loop_body_return = ast::LoopBodyStatement::Return(ast::Expression { 455 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 456 | operation: None, 457 | }); 458 | 459 | let loop_stmt = [loop_body_let_binding, loop_body_return]; 460 | t.state.loop_statement(&loop_stmt, &block_state); 461 | 462 | let main_ctx = block_state.borrow().get_context().get(); 463 | assert_eq!(main_ctx.len(), 4); 464 | assert!(block_state.borrow().parent.is_none()); 465 | assert!(block_state.borrow().parent.is_none()); 466 | assert_eq!(block_state.borrow().children.len(), 1); 467 | 468 | let ctx = block_state.borrow().children[0].clone(); 469 | assert!(ctx.borrow().parent.is_some()); 470 | assert!(ctx.borrow().children.is_empty()); 471 | 472 | let stm_ctx = ctx.borrow().get_context().clone().get(); 473 | assert_eq!(stm_ctx.len(), 4); 474 | assert_eq!(stm_ctx, main_ctx); 475 | assert_eq!( 476 | stm_ctx[0], 477 | SemanticStackContext::JumpTo { 478 | label: String::from("loop_begin").into() 479 | } 480 | ); 481 | assert_eq!( 482 | stm_ctx[1], 483 | SemanticStackContext::SetLabel { 484 | label: String::from("loop_begin").into() 485 | } 486 | ); 487 | assert_eq!( 488 | stm_ctx[2], 489 | SemanticStackContext::LetBinding { 490 | let_decl: Value { 491 | inner_name: "x.0".into(), 492 | inner_type: Type::Primitive(PrimitiveTypes::Bool), 493 | mutable: true, 494 | alloca: false, 495 | malloc: false, 496 | }, 497 | expr_result: ExpressionResult { 498 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 499 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(false)), 500 | }, 501 | } 502 | ); 503 | assert_eq!( 504 | stm_ctx[3], 505 | SemanticStackContext::JumpFunctionReturn { 506 | expr_result: ExpressionResult { 507 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 508 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(true)), 509 | } 510 | } 511 | ); 512 | 513 | assert!(t.is_empty_error()); 514 | } 515 | -------------------------------------------------------------------------------- /src/types/semantic.rs: -------------------------------------------------------------------------------- 1 | //! # Semantic types 2 | //! Semantic analyzer result state types. 3 | //! It contains `SemanticStack` as Semantic results Context data. 4 | 5 | use super::condition::{Condition, LogicCondition}; 6 | use super::expression::{ExpressionOperations, ExpressionResult}; 7 | use super::types::StructTypes; 8 | use super::{Constant, Function, FunctionParameter, FunctionStatement, LabelName, Value}; 9 | use crate::semantic::State; 10 | use crate::types::block_state::BlockState; 11 | #[cfg(feature = "codec")] 12 | use serde::{Deserialize, Serialize}; 13 | use std::cell::RefCell; 14 | use std::fmt::Debug; 15 | use std::rc::Rc; 16 | 17 | /// Semantic Context trait contain instructions set functions 18 | /// for Global Stack context. It includes: 19 | /// - functions 20 | /// - types 21 | /// - constants 22 | pub trait GlobalSemanticContext { 23 | fn function_declaration(&mut self, fn_decl: FunctionStatement); 24 | fn constant(&mut self, const_decl: Constant); 25 | fn types(&mut self, type_decl: StructTypes); 26 | } 27 | 28 | /// Semantic Context trait contain instructions set functions 29 | /// for the Stack context. 30 | pub trait SemanticContext { 31 | fn expression_value(&mut self, expression: Value, register_number: u64); 32 | fn expression_const(&mut self, expression: Constant, register_number: u64); 33 | fn expression_struct_value(&mut self, expression: Value, index: u32, register_number: u64); 34 | fn expression_operation( 35 | &mut self, 36 | operation: ExpressionOperations, 37 | left_value: ExpressionResult, 38 | right_value: ExpressionResult, 39 | register_number: u64, 40 | ); 41 | fn call(&mut self, call: Function, params: Vec, register_number: u64); 42 | fn let_binding(&mut self, let_decl: Value, expr_result: ExpressionResult); 43 | fn binding(&mut self, val: Value, expr_result: ExpressionResult); 44 | fn expression_function_return(&mut self, expr_result: ExpressionResult); 45 | fn expression_function_return_with_label(&mut self, expr_result: ExpressionResult); 46 | fn set_label(&mut self, label: LabelName); 47 | fn jump_to(&mut self, label: LabelName); 48 | fn if_condition_expression( 49 | &mut self, 50 | expr_result: ExpressionResult, 51 | label_if_begin: LabelName, 52 | label_if_end: LabelName, 53 | ); 54 | fn condition_expression( 55 | &mut self, 56 | left_result: ExpressionResult, 57 | right_result: ExpressionResult, 58 | condition: Condition, 59 | register_number: u64, 60 | ); 61 | fn jump_function_return(&mut self, expr_result: ExpressionResult); 62 | fn logic_condition( 63 | &mut self, 64 | logic_condition: LogicCondition, 65 | left_register_result: u64, 66 | right_register_result: u64, 67 | register_number: u64, 68 | ); 69 | fn if_condition_logic( 70 | &mut self, 71 | label_if_begin: LabelName, 72 | label_if_end: LabelName, 73 | result_register: u64, 74 | ); 75 | fn function_arg(&mut self, value: Value, func_arg: FunctionParameter); 76 | } 77 | 78 | /// Extended Semantic Context trait contain instructions set functions 79 | /// for the Extended Stack context. 80 | pub trait ExtendedSemanticContext { 81 | fn extended_expression(&mut self, expr: &I); 82 | } 83 | 84 | /// Semantic Context trait contains custom instruction implementation 85 | /// to flexibly extend context instructions. It represents ivs derided 86 | /// traits: `Debug` and `Serialize` + `Deserialize` 87 | pub trait SemanticContextInstruction: Debug + Clone + PartialEq {} 88 | 89 | /// Extended Expression for semantic analyzer. 90 | pub trait ExtendedExpression: Debug + Clone + PartialEq { 91 | /// Custom expression. Ast should be received from `GetAst` trait. 92 | fn expression( 93 | &self, 94 | state: &mut State, 95 | block_state: &Rc>>, 96 | ) -> ExpressionResult; 97 | } 98 | 99 | /// # Semantic stack 100 | /// Semantic stack represent stack of Semantic Context results 101 | #[derive(Debug, Clone, PartialEq)] 102 | #[cfg_attr(feature = "codec", derive(Serialize, Deserialize))] 103 | pub struct SemanticStack(Vec>); 104 | 105 | impl Default for SemanticStack { 106 | fn default() -> Self { 107 | Self::new() 108 | } 109 | } 110 | 111 | impl SemanticStack { 112 | /// Init Semantic stack 113 | #[must_use] 114 | pub const fn new() -> Self { 115 | Self(vec![]) 116 | } 117 | 118 | /// Push Context data to the stack 119 | pub fn push(&mut self, value: SemanticStackContext) { 120 | self.0.push(value); 121 | } 122 | 123 | /// Get all context stack data as array data 124 | #[must_use] 125 | pub fn get(self) -> Vec> { 126 | self.0 127 | } 128 | } 129 | 130 | impl GlobalSemanticContext for SemanticStack { 131 | /// Push Context to the stack as function declaration data. 132 | /// Function declaration instruction. 133 | /// 134 | /// ## Parameters 135 | /// - `fn_decl` - function declaration parameters 136 | fn function_declaration(&mut self, fn_decl: FunctionStatement) { 137 | self.push(SemanticStackContext::FunctionDeclaration { fn_decl }); 138 | } 139 | 140 | /// Push Context to the stack as constant data. 141 | /// Constant declaration instruction. 142 | /// 143 | /// ## Parameters 144 | /// - `const_decl` - constant declaration parameters 145 | fn constant(&mut self, const_decl: Constant) { 146 | self.push(SemanticStackContext::Constant { const_decl }); 147 | } 148 | 149 | /// Push Context to the stack as types data. 150 | /// Types declaration instruction. 151 | /// 152 | /// ## Parameters 153 | /// - `type_decl` - type declaration parameters 154 | fn types(&mut self, type_decl: StructTypes) { 155 | self.push(SemanticStackContext::Types { type_decl }); 156 | } 157 | } 158 | 159 | impl SemanticContext for SemanticStack { 160 | /// Push Context to the stack as expression value data. 161 | /// 162 | /// ## Parameters 163 | /// - `expression` - contains expression value 164 | /// - `register_number` - register to store result data 165 | fn expression_value(&mut self, expression: Value, register_number: u64) { 166 | self.push(SemanticStackContext::ExpressionValue { 167 | expression, 168 | register_number, 169 | }); 170 | } 171 | 172 | /// Push Context to the stack as expression const data. 173 | /// 174 | /// ## Parameters 175 | /// - `expression` - contains expression constant 176 | /// - `register_number` - register to store result data 177 | fn expression_const(&mut self, expression: Constant, register_number: u64) { 178 | self.push(SemanticStackContext::ExpressionConst { 179 | expression, 180 | register_number, 181 | }); 182 | } 183 | 184 | /// Push Context to the stack as expression struct value data. 185 | /// 186 | /// ## Parameters 187 | /// - `expression` - contains expression value for specific `Structure` attribute 188 | /// - `index` - represent attribute index in the `Structure` type 189 | /// - `register_number` - register to store result data 190 | fn expression_struct_value(&mut self, expression: Value, index: u32, register_number: u64) { 191 | self.push(SemanticStackContext::ExpressionStructValue { 192 | expression, 193 | index, 194 | register_number, 195 | }); 196 | } 197 | 198 | /// Push Context to the stack as expression operation data. 199 | /// `expression_operation` imply operation between `left_value` and 200 | /// `right_value` and store result to `register_number`. 201 | /// 202 | /// ## Parameters 203 | /// - `operation` - specific operation 204 | /// - `left_value` - left expression result 205 | /// - `right_value` - right expression result 206 | /// - `register_number` - register to store result of expression operation 207 | fn expression_operation( 208 | &mut self, 209 | operation: ExpressionOperations, 210 | left_value: ExpressionResult, 211 | right_value: ExpressionResult, 212 | register_number: u64, 213 | ) { 214 | self.push(SemanticStackContext::ExpressionOperation { 215 | operation, 216 | left_value, 217 | right_value, 218 | register_number, 219 | }); 220 | } 221 | 222 | /// Push Context to the stack as function call data. 223 | /// Function call instruction with parameters and result data. 224 | /// 225 | /// ## Parameters 226 | /// - `call` - function declaration data 227 | /// - `params` - function parameters 228 | /// - `register_number` - register to store result of function call 229 | fn call(&mut self, call: Function, params: Vec, register_number: u64) { 230 | self.push(SemanticStackContext::Call { 231 | call, 232 | params, 233 | register_number, 234 | }); 235 | } 236 | 237 | /// Push Context to the stack as let-binding data. 238 | /// Let binding instruction that "bind" expression result to 239 | /// the new value. 240 | /// 241 | /// ## Parameters 242 | /// - `let_decl` - value declaration 243 | /// - `expr_result` - expression result that will be bind to the value 244 | fn let_binding(&mut self, let_decl: Value, expr_result: ExpressionResult) { 245 | self.push(SemanticStackContext::LetBinding { 246 | let_decl, 247 | expr_result, 248 | }); 249 | } 250 | 251 | /// Push Context to the stack as binding data. 252 | /// Binding instruction that "bind" expression result to 253 | /// the old. previously init value. 254 | /// 255 | /// ## Parameters 256 | /// - `val` - value declaration 257 | /// - `expr_result` - expression result that will be bind to the value 258 | fn binding(&mut self, val: Value, expr_result: ExpressionResult) { 259 | self.push(SemanticStackContext::Binding { val, expr_result }); 260 | } 261 | 262 | /// Push Context to the stack as expression function return data. 263 | /// Return instruction, should be used in the end of functions. 264 | /// Alwats should be only once. 265 | /// 266 | /// ## Parameters 267 | /// - `expr_result` - result data for the return 268 | fn expression_function_return(&mut self, expr_result: ExpressionResult) { 269 | self.push(SemanticStackContext::ExpressionFunctionReturn { expr_result }); 270 | } 271 | 272 | /// Push Context to the stack as `expression function return with label` data. 273 | /// Return instruction with additional logic. Most useful case when 274 | /// `return` previously was call from `if-body` or `loop-body.`. 275 | /// As additional behavior this `expression_function_return_with_label` should 276 | /// set `return` label. It will allow `jump-to-return` case. Also 277 | /// before `return` label Codegen, for normal instruction flow, must 278 | /// jump to `return` label anyway. 279 | /// 280 | /// ## Parameters 281 | /// - `expr_result` - result data for the return 282 | fn expression_function_return_with_label(&mut self, expr_result: ExpressionResult) { 283 | self.push(SemanticStackContext::ExpressionFunctionReturnWithLabel { expr_result }); 284 | } 285 | 286 | /// Push Context to the stack as `set label` data. 287 | /// Set label. Useful for any kind of jump operations and conditional flow. 288 | /// 289 | /// ## Parameters 290 | /// - `label` - label name 291 | fn set_label(&mut self, label: LabelName) { 292 | self.push(SemanticStackContext::SetLabel { label }); 293 | } 294 | 295 | /// Push Context to the stack as `jump to` data. 296 | /// Unconditional direct jump to label. 297 | /// 298 | /// ## Parameters 299 | /// - `label` - label for the jump 300 | fn jump_to(&mut self, label: LabelName) { 301 | self.push(SemanticStackContext::JumpTo { label }); 302 | } 303 | 304 | /// Push Context to the stack as `if condition expression` data. 305 | /// `if-condition expression` represent if-condition, when if expression 306 | /// is "true" jump to `label_if_begin` else `label_if_end`. 307 | /// 308 | /// ## Parameters 309 | /// - `expr_result` - expression result of `if-condition` for 310 | /// conditional instruction 311 | /// - `label_if_begin` - label for jump if expression is "true" 312 | /// - `label_if_end` - label for jump if expression is "false" 313 | fn if_condition_expression( 314 | &mut self, 315 | expr_result: ExpressionResult, 316 | label_if_begin: LabelName, 317 | label_if_end: LabelName, 318 | ) { 319 | self.push(SemanticStackContext::IfConditionExpression { 320 | expr_result, 321 | label_if_begin, 322 | label_if_end, 323 | }); 324 | } 325 | 326 | /// Push Context to the stack as `condition expression` data. 327 | /// Condition expression between left and right condition calculation. 328 | /// 329 | /// ## Parameters 330 | /// - `left_result` - left expression result 331 | /// - `right_result` - right expression result 332 | /// - `condition` - condition operation 333 | /// - `register_number` - register to store result of expression operation 334 | fn condition_expression( 335 | &mut self, 336 | left_result: ExpressionResult, 337 | right_result: ExpressionResult, 338 | condition: Condition, 339 | register_number: u64, 340 | ) { 341 | self.push(SemanticStackContext::ConditionExpression { 342 | left_result, 343 | right_result, 344 | condition, 345 | register_number, 346 | }); 347 | } 348 | 349 | /// Push Context to the stack as `jump function return` data. 350 | /// Jump to function return with expression result data. Label for jumping 351 | /// to return position (always end of function) should be always the same 352 | /// and should be managed by Codegen. 353 | /// 354 | /// ## Parameters 355 | /// - `expr_result` - expression result for return condition 356 | fn jump_function_return(&mut self, expr_result: ExpressionResult) { 357 | self.push(SemanticStackContext::JumpFunctionReturn { expr_result }); 358 | } 359 | 360 | /// Push Context to the stack as `logic condition` data. 361 | /// Operate with registers: left and right for specific logic condition. 362 | /// Result of calculation stored to `register_number`. 363 | /// 364 | /// ## Parameters 365 | /// - `left_register_result` - result of left condition 366 | /// - `right_register_result` - result of right condition 367 | /// - `register_number` - register to store instruction result 368 | fn logic_condition( 369 | &mut self, 370 | logic_condition: LogicCondition, 371 | left_register_result: u64, 372 | right_register_result: u64, 373 | register_number: u64, 374 | ) { 375 | self.push(SemanticStackContext::LogicCondition { 376 | logic_condition, 377 | left_register_result, 378 | right_register_result, 379 | register_number, 380 | }); 381 | } 382 | 383 | /// Push Context to the stack as `if condition logic` data. 384 | /// `if_condition_logic` instruction read data from `result_register` 385 | /// and conditionally jump: if "true' to `label_if_begin` or 386 | /// `label_if_end` if "false" (data contained as result after 387 | /// reading `result_register`). 388 | /// 389 | /// ## Parameters 390 | /// - `label_if_begin` - label for a jump if `result_register` contains 391 | /// result with "true" 392 | /// - `label_if_end` - label for a jump if `result_register` contains 393 | /// result with "false". It can be not only `if_end` but any kind (for 394 | /// example `if_else`) 395 | /// - `result_register` - contains register of previous condition logic 396 | /// calculations. 397 | fn if_condition_logic( 398 | &mut self, 399 | label_if_begin: LabelName, 400 | label_if_end: LabelName, 401 | result_register: u64, 402 | ) { 403 | self.push(SemanticStackContext::IfConditionLogic { 404 | label_if_begin, 405 | label_if_end, 406 | result_register, 407 | }); 408 | } 409 | 410 | /// Push Context to the stack as `function argument` data. 411 | /// This instruction should allocate pointer (if argument type is 412 | /// not Ptr) and store argument value to the pointer. 413 | /// 414 | /// ## Parameters 415 | /// - `func_arg` - function parameter data 416 | fn function_arg(&mut self, value: Value, func_arg: FunctionParameter) { 417 | self.push(SemanticStackContext::FunctionArg { value, func_arg }); 418 | } 419 | } 420 | 421 | impl ExtendedSemanticContext for SemanticStack { 422 | /// Extended Expression instruction. 423 | /// AS argument trait, that contains instruction method that returns 424 | /// instruction parameters. 425 | fn extended_expression(&mut self, expr: &I) { 426 | self.push(SemanticStackContext::ExtendedExpression(Box::new( 427 | expr.clone(), 428 | ))); 429 | } 430 | } 431 | 432 | /// # Semantic stack Context 433 | /// Context data of Semantic results. Contains type declarations 434 | /// for specific instructions. 435 | #[derive(Debug, Clone, PartialEq)] 436 | #[cfg_attr( 437 | feature = "codec", 438 | derive(Serialize, Deserialize), 439 | serde(tag = "type", content = "content") 440 | )] 441 | pub enum SemanticStackContext { 442 | ExpressionValue { 443 | expression: Value, 444 | register_number: u64, 445 | }, 446 | ExpressionConst { 447 | expression: Constant, 448 | register_number: u64, 449 | }, 450 | ExpressionStructValue { 451 | expression: Value, 452 | index: u32, 453 | register_number: u64, 454 | }, 455 | ExpressionOperation { 456 | operation: ExpressionOperations, 457 | left_value: ExpressionResult, 458 | right_value: ExpressionResult, 459 | register_number: u64, 460 | }, 461 | Call { 462 | call: Function, 463 | params: Vec, 464 | register_number: u64, 465 | }, 466 | LetBinding { 467 | let_decl: Value, 468 | expr_result: ExpressionResult, 469 | }, 470 | Binding { 471 | val: Value, 472 | expr_result: ExpressionResult, 473 | }, 474 | FunctionDeclaration { 475 | fn_decl: FunctionStatement, 476 | }, 477 | Constant { 478 | const_decl: Constant, 479 | }, 480 | Types { 481 | type_decl: StructTypes, 482 | }, 483 | ExpressionFunctionReturn { 484 | expr_result: ExpressionResult, 485 | }, 486 | ExpressionFunctionReturnWithLabel { 487 | expr_result: ExpressionResult, 488 | }, 489 | SetLabel { 490 | label: LabelName, 491 | }, 492 | JumpTo { 493 | label: LabelName, 494 | }, 495 | IfConditionExpression { 496 | expr_result: ExpressionResult, 497 | label_if_begin: LabelName, 498 | label_if_end: LabelName, 499 | }, 500 | ConditionExpression { 501 | left_result: ExpressionResult, 502 | right_result: ExpressionResult, 503 | condition: Condition, 504 | register_number: u64, 505 | }, 506 | JumpFunctionReturn { 507 | expr_result: ExpressionResult, 508 | }, 509 | LogicCondition { 510 | logic_condition: LogicCondition, 511 | left_register_result: u64, 512 | right_register_result: u64, 513 | register_number: u64, 514 | }, 515 | IfConditionLogic { 516 | label_if_begin: LabelName, 517 | label_if_end: LabelName, 518 | result_register: u64, 519 | }, 520 | FunctionArg { 521 | value: Value, 522 | func_arg: FunctionParameter, 523 | }, 524 | ExtendedExpression(Box), 525 | } 526 | -------------------------------------------------------------------------------- /tests/main_tests.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{CustomExpression, CustomExpressionInstruction, SemanticTest}; 2 | use semantic_analyzer::ast::{self, GetName, Ident}; 3 | use semantic_analyzer::types::error::StateErrorKind; 4 | use semantic_analyzer::types::expression::ExpressionOperations; 5 | use semantic_analyzer::types::{ 6 | expression::{ExpressionResult, ExpressionResultValue}, 7 | semantic::SemanticStackContext, 8 | types::{PrimitiveTypes, Type}, 9 | Function, PrimitiveValue, Value, 10 | }; 11 | 12 | mod utils; 13 | 14 | #[test] 15 | fn main_run() { 16 | let mut t = SemanticTest::new(); 17 | let imports: ast::ImportPath = vec![ast::ImportName::new(Ident::new("import1"))]; 18 | let import_stm = ast::MainStatement::Import(imports); 19 | 20 | let constant1 = ast::Constant { 21 | name: ast::ConstantName::new(Ident::new("const1")), 22 | constant_type: ast::Type::Primitive(ast::PrimitiveTypes::None), 23 | constant_value: ast::ConstantExpression { 24 | value: ast::ConstantValue::Constant(ast::ConstantName::new(Ident::new("const2"))), 25 | operation: None, 26 | }, 27 | }; 28 | let constant_stm = ast::MainStatement::Constant(constant1.clone()); 29 | 30 | let ty = ast::StructTypes { 31 | name: Ident::new("StructType"), 32 | attributes: vec![], 33 | }; 34 | let ty_stm = ast::MainStatement::Types(ty.clone()); 35 | 36 | let body_let_binding = ast::BodyStatement::LetBinding(ast::LetBinding { 37 | name: ast::ValueName::new(Ident::new("x")), 38 | mutable: true, 39 | value_type: None, 40 | value: Box::new(ast::Expression { 41 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool( 42 | false, 43 | )), 44 | operation: None, 45 | }), 46 | }); 47 | let body_binding = ast::BodyStatement::Binding(ast::Binding { 48 | name: ast::ValueName::new(Ident::new("x")), 49 | value: Box::new(ast::Expression { 50 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 51 | operation: None, 52 | }), 53 | }); 54 | let body_fn_call = ast::BodyStatement::FunctionCall(ast::FunctionCall { 55 | name: ast::FunctionName::new(Ident::new("fn2")), 56 | parameters: vec![], 57 | }); 58 | let body_if = ast::BodyStatement::If(ast::IfStatement { 59 | condition: ast::IfCondition::Single(ast::Expression { 60 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 61 | operation: None, 62 | }), 63 | body: ast::IfBodyStatements::If(vec![ast::IfBodyStatement::FunctionCall( 64 | ast::FunctionCall { 65 | name: ast::FunctionName::new(Ident::new("fn2")), 66 | parameters: vec![], 67 | }, 68 | )]), 69 | else_statement: None, 70 | else_if_statement: None, 71 | }); 72 | let body_loop = ast::BodyStatement::Loop(vec![ast::LoopBodyStatement::FunctionCall( 73 | ast::FunctionCall { 74 | name: ast::FunctionName::new(Ident::new("fn2")), 75 | parameters: vec![], 76 | }, 77 | )]); 78 | let body_return = ast::BodyStatement::Return(ast::Expression { 79 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 80 | operation: None, 81 | }); 82 | let fn1 = ast::FunctionStatement::new( 83 | ast::FunctionName::new(Ident::new("fn1")), 84 | vec![], 85 | ast::Type::Primitive(ast::PrimitiveTypes::Bool), 86 | vec![ 87 | body_let_binding, 88 | body_binding, 89 | body_fn_call, 90 | body_if, 91 | body_loop, 92 | body_return.clone(), 93 | ], 94 | ); 95 | let fn_stm = ast::MainStatement::Function(fn1.clone()); 96 | 97 | let body_expr_return = ast::BodyStatement::Expression(ast::Expression { 98 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::U16(23)), 99 | operation: None, 100 | }); 101 | let fn2 = ast::FunctionStatement::new( 102 | ast::FunctionName::new(Ident::new("fn2")), 103 | vec![], 104 | ast::Type::Primitive(ast::PrimitiveTypes::U16), 105 | vec![body_expr_return], 106 | ); 107 | let fn2_stm = ast::MainStatement::Function(fn2.clone()); 108 | let main_stm: ast::Main< 109 | CustomExpressionInstruction, 110 | CustomExpression, 111 | > = vec![import_stm, constant_stm, ty_stm, fn_stm, fn2_stm]; 112 | // For grcov 113 | let _ = format!("{main_stm:#?}"); 114 | t.state.run(&main_stm); 115 | assert!(t.is_empty_error()); 116 | 117 | assert_eq!( 118 | t.state 119 | .global 120 | .constants 121 | .get(&constant1.clone().name().into()) 122 | .unwrap(), 123 | &(constant1.clone().into()) 124 | ); 125 | assert_eq!( 126 | t.state.global.types.get(&ty.clone().name().into()).unwrap(), 127 | &Type::Struct(ty.clone().into()) 128 | ); 129 | let fn_state = t 130 | .state 131 | .global 132 | .functions 133 | .get(&fn1.clone().name().into()) 134 | .unwrap(); 135 | assert_eq!(fn_state.inner_name, fn1.name.clone().into()); 136 | assert_eq!(fn_state.inner_type, fn1.result_type.clone().into()); 137 | assert!(fn_state.parameters.is_empty()); 138 | 139 | // Function body context 140 | assert_eq!(t.state.context.len(), 2); 141 | let ctx1 = t.state.context[0].borrow(); 142 | assert_eq!(ctx1.children.len(), 2); 143 | assert!(ctx1.parent.is_none()); 144 | let ctx2 = t.state.context[1].borrow(); 145 | assert!(ctx2.children.is_empty()); 146 | assert!(ctx2.parent.is_none()); 147 | 148 | let ch_ctx1 = ctx1.children[0].clone(); 149 | assert!(ch_ctx1.borrow().parent.is_some()); 150 | assert!(ch_ctx1.borrow().children.is_empty()); 151 | 152 | let ch_ctx2 = ctx1.children[1].clone(); 153 | assert!(ch_ctx2.borrow().parent.is_some()); 154 | assert!(ch_ctx2.borrow().children.is_empty()); 155 | 156 | // Semantic stack context for the block fn2 157 | let st_ctx2 = ctx2.get_context().clone().get(); 158 | assert_eq!(st_ctx2.len(), 1); 159 | assert_eq!( 160 | st_ctx2[0], 161 | SemanticStackContext::ExpressionFunctionReturn { 162 | expr_result: ExpressionResult { 163 | expr_type: Type::Primitive(PrimitiveTypes::U16), 164 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::U16(23)), 165 | } 166 | } 167 | ); 168 | 169 | let st_ch_ctx1 = ch_ctx1.borrow().get_context().clone().get(); 170 | assert_eq!(st_ch_ctx1.len(), 5); 171 | assert_eq!( 172 | st_ch_ctx1[0], 173 | SemanticStackContext::IfConditionExpression { 174 | expr_result: ExpressionResult { 175 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 176 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(true)), 177 | }, 178 | label_if_begin: String::from("if_begin").into(), 179 | label_if_end: String::from("if_end").into(), 180 | } 181 | ); 182 | assert_eq!( 183 | st_ch_ctx1[1], 184 | SemanticStackContext::SetLabel { 185 | label: String::from("if_begin").into() 186 | } 187 | ); 188 | assert_eq!( 189 | st_ch_ctx1[2], 190 | SemanticStackContext::Call { 191 | call: Function { 192 | inner_name: String::from("fn2").into(), 193 | inner_type: Type::Primitive(PrimitiveTypes::U16), 194 | parameters: vec![], 195 | }, 196 | params: vec![], 197 | register_number: 2, 198 | } 199 | ); 200 | assert_eq!( 201 | st_ch_ctx1[3], 202 | SemanticStackContext::JumpTo { 203 | label: String::from("if_end").into() 204 | } 205 | ); 206 | assert_eq!( 207 | st_ch_ctx1[4], 208 | SemanticStackContext::SetLabel { 209 | label: String::from("if_end").into() 210 | } 211 | ); 212 | 213 | let st_ch_ctx2 = ch_ctx2.borrow().get_context().clone().get(); 214 | assert_eq!(st_ch_ctx2.len(), 5); 215 | assert_eq!( 216 | st_ch_ctx2[0], 217 | SemanticStackContext::JumpTo { 218 | label: String::from("loop_begin").into() 219 | } 220 | ); 221 | assert_eq!( 222 | st_ch_ctx2[1], 223 | SemanticStackContext::SetLabel { 224 | label: String::from("loop_begin").into() 225 | } 226 | ); 227 | assert_eq!( 228 | st_ch_ctx2[2], 229 | SemanticStackContext::Call { 230 | call: Function { 231 | inner_name: String::from("fn2").into(), 232 | inner_type: Type::Primitive(PrimitiveTypes::U16), 233 | parameters: vec![], 234 | }, 235 | params: vec![], 236 | register_number: 3, 237 | } 238 | ); 239 | assert_eq!( 240 | st_ch_ctx2[3], 241 | SemanticStackContext::JumpTo { 242 | label: String::from("loop_begin").into() 243 | } 244 | ); 245 | assert_eq!( 246 | st_ch_ctx2[4], 247 | SemanticStackContext::SetLabel { 248 | label: String::from("loop_end").into() 249 | } 250 | ); 251 | 252 | // Global semantic stack context 253 | let st_global_context = t.state.global.context.get(); 254 | assert_eq!(st_global_context.len(), 4); 255 | assert_eq!( 256 | st_global_context[0], 257 | SemanticStackContext::Types { 258 | type_decl: ty.into() 259 | } 260 | ); 261 | assert_eq!( 262 | st_global_context[1], 263 | SemanticStackContext::Constant { 264 | const_decl: constant1.into() 265 | } 266 | ); 267 | assert_eq!( 268 | st_global_context[2], 269 | SemanticStackContext::FunctionDeclaration { 270 | fn_decl: fn1.into() 271 | } 272 | ); 273 | assert_eq!( 274 | st_global_context[3], 275 | SemanticStackContext::FunctionDeclaration { 276 | fn_decl: fn2.into() 277 | } 278 | ); 279 | 280 | // Semantic stack context for the block fn1 281 | let st_ctx1 = ctx1.get_context().clone().get(); 282 | assert_eq!(st_ctx1.len(), 14); 283 | assert_eq!( 284 | st_ctx1[0], 285 | SemanticStackContext::LetBinding { 286 | let_decl: Value { 287 | inner_name: "x.0".into(), 288 | inner_type: Type::Primitive(PrimitiveTypes::Bool), 289 | mutable: true, 290 | alloca: false, 291 | malloc: false, 292 | }, 293 | expr_result: ExpressionResult { 294 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 295 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(false)), 296 | }, 297 | } 298 | ); 299 | assert_eq!( 300 | st_ctx1[1], 301 | SemanticStackContext::Binding { 302 | val: Value { 303 | inner_name: "x.0".into(), 304 | inner_type: Type::Primitive(PrimitiveTypes::Bool), 305 | mutable: true, 306 | alloca: false, 307 | malloc: false, 308 | }, 309 | expr_result: ExpressionResult { 310 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 311 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(true)), 312 | }, 313 | } 314 | ); 315 | assert_eq!( 316 | st_ctx1[2], 317 | SemanticStackContext::Call { 318 | call: Function { 319 | inner_name: String::from("fn2").into(), 320 | inner_type: Type::Primitive(PrimitiveTypes::U16), 321 | parameters: vec![], 322 | }, 323 | params: vec![], 324 | register_number: 1, 325 | } 326 | ); 327 | assert_eq!(st_ctx1[3], st_ch_ctx1[0]); 328 | assert_eq!(st_ctx1[4], st_ch_ctx1[1]); 329 | assert_eq!(st_ctx1[5], st_ch_ctx1[2]); 330 | assert_eq!(st_ctx1[6], st_ch_ctx1[3]); 331 | assert_eq!(st_ctx1[7], st_ch_ctx1[4]); 332 | assert_eq!(st_ctx1[8], st_ch_ctx2[0]); 333 | assert_eq!(st_ctx1[9], st_ch_ctx2[1]); 334 | assert_eq!(st_ctx1[10], st_ch_ctx2[2]); 335 | assert_eq!(st_ctx1[11], st_ch_ctx2[3]); 336 | assert_eq!(st_ctx1[12], st_ch_ctx2[4]); 337 | assert_eq!( 338 | st_ctx1[13], 339 | SemanticStackContext::ExpressionFunctionReturn { 340 | expr_result: ExpressionResult { 341 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 342 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(true)), 343 | } 344 | } 345 | ); 346 | } 347 | 348 | #[test] 349 | fn double_return() { 350 | let mut t = SemanticTest::new(); 351 | let body_return = ast::BodyStatement::Return(ast::Expression { 352 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 353 | operation: None, 354 | }); 355 | let body_expr = ast::BodyStatement::Expression(ast::Expression { 356 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 357 | operation: None, 358 | }); 359 | let fn1 = ast::FunctionStatement::new( 360 | ast::FunctionName::new(Ident::new("fn1")), 361 | vec![], 362 | ast::Type::Primitive(ast::PrimitiveTypes::Bool), 363 | vec![body_return, body_expr], 364 | ); 365 | let fn_stm = ast::MainStatement::Function(fn1); 366 | let main_stm: ast::Main< 367 | CustomExpressionInstruction, 368 | CustomExpression, 369 | > = vec![fn_stm]; 370 | t.state.run(&main_stm); 371 | assert!(t.check_errors_len(2), "Errors: {:?}", t.state.errors.len()); 372 | assert!(t.check_error_index(0, StateErrorKind::ForbiddenCodeAfterReturnDeprecated)); 373 | assert!(t.check_error_index(1, StateErrorKind::ReturnAlreadyCalled)); 374 | } 375 | 376 | #[test] 377 | fn wrong_return_type() { 378 | let mut t = SemanticTest::new(); 379 | let body_return = ast::BodyStatement::Return(ast::Expression { 380 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::I8(10)), 381 | operation: None, 382 | }); 383 | let fn1 = ast::FunctionStatement::new( 384 | ast::FunctionName::new(Ident::new("fn1")), 385 | vec![], 386 | ast::Type::Primitive(ast::PrimitiveTypes::Bool), 387 | vec![body_return], 388 | ); 389 | let fn_stm = ast::MainStatement::Function(fn1); 390 | let main_stm: ast::Main< 391 | CustomExpressionInstruction, 392 | CustomExpression, 393 | > = vec![fn_stm]; 394 | t.state.run(&main_stm); 395 | assert!(t.check_errors_len(1), "Errors: {:?}", t.state.errors.len()); 396 | assert!( 397 | t.check_error(StateErrorKind::WrongReturnType), 398 | "Errors: {:?}", 399 | t.state.errors[0] 400 | ); 401 | } 402 | 403 | #[test] 404 | fn expression_as_return() { 405 | let mut t = SemanticTest::new(); 406 | let body_expr = ast::BodyStatement::Expression(ast::Expression { 407 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 408 | operation: None, 409 | }); 410 | let fn1 = ast::FunctionStatement::new( 411 | ast::FunctionName::new(Ident::new("fn1")), 412 | vec![], 413 | ast::Type::Primitive(ast::PrimitiveTypes::Bool), 414 | vec![body_expr], 415 | ); 416 | let fn_stm = ast::MainStatement::Function(fn1.clone()); 417 | let main_stm: ast::Main< 418 | CustomExpressionInstruction, 419 | CustomExpression, 420 | > = vec![fn_stm]; 421 | t.state.run(&main_stm); 422 | assert!(t.is_empty_error()); 423 | 424 | // Function body context 425 | assert_eq!(t.state.context.len(), 1); 426 | let ctx = t.state.context[0].borrow(); 427 | assert!(ctx.children.is_empty()); 428 | assert!(ctx.parent.is_none()); 429 | 430 | // Semantic stack context for the block 431 | let st_ctx = ctx.get_context().clone().get(); 432 | assert_eq!(st_ctx.len(), 1); 433 | assert_eq!( 434 | st_ctx[0], 435 | SemanticStackContext::ExpressionFunctionReturn { 436 | expr_result: ExpressionResult { 437 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 438 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(true)), 439 | } 440 | } 441 | ); 442 | 443 | // Global semantic stack context 444 | let st_global_context = t.state.global.context.get(); 445 | assert_eq!(st_global_context.len(), 1); 446 | assert_eq!( 447 | st_global_context[0], 448 | SemanticStackContext::FunctionDeclaration { 449 | fn_decl: fn1.into() 450 | } 451 | ); 452 | } 453 | 454 | #[test] 455 | fn if_return_from_function() { 456 | let mut t = SemanticTest::new(); 457 | let body_expr_return = ast::BodyStatement::Expression(ast::Expression { 458 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::I8(5)), 459 | operation: None, 460 | }); 461 | let if_expr_return = ast::Expression { 462 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::I8(10)), 463 | operation: None, 464 | }; 465 | let if_expr = ast::Expression { 466 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::Bool(true)), 467 | operation: None, 468 | }; 469 | let body_if = ast::BodyStatement::If(ast::IfStatement { 470 | condition: ast::IfCondition::Single(if_expr), 471 | body: ast::IfBodyStatements::If(vec![ast::IfBodyStatement::Return(if_expr_return)]), 472 | else_statement: None, 473 | else_if_statement: None, 474 | }); 475 | let fn1 = ast::FunctionStatement::new( 476 | ast::FunctionName::new(Ident::new("fn1")), 477 | vec![], 478 | ast::Type::Primitive(ast::PrimitiveTypes::I8), 479 | vec![body_if, body_expr_return], 480 | ); 481 | let fn_stm = ast::MainStatement::Function(fn1.clone()); 482 | let main_stm: ast::Main< 483 | CustomExpressionInstruction, 484 | CustomExpression, 485 | > = vec![fn_stm]; 486 | t.state.run(&main_stm); 487 | assert!(t.is_empty_error()); 488 | 489 | // Function body context 490 | assert_eq!(t.state.context.len(), 1); 491 | let ctx = t.state.context[0].borrow(); 492 | assert_eq!(ctx.children.len(), 1); 493 | assert!(ctx.parent.is_none()); 494 | 495 | // Children block context 496 | let children_ctx = ctx.children[0].borrow(); 497 | assert!(children_ctx.children.is_empty()); 498 | assert!(children_ctx.parent.is_some()); 499 | 500 | // Children semantic stack context for the block 501 | let st_children_ctx = children_ctx.get_context().clone().get(); 502 | assert_eq!(st_children_ctx.len(), 4); 503 | assert_eq!( 504 | st_children_ctx[0], 505 | SemanticStackContext::IfConditionExpression { 506 | expr_result: ExpressionResult { 507 | expr_type: Type::Primitive(PrimitiveTypes::Bool), 508 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::Bool(true)), 509 | }, 510 | label_if_begin: String::from("if_begin").into(), 511 | label_if_end: String::from("if_end").into(), 512 | } 513 | ); 514 | assert_eq!( 515 | st_children_ctx[1], 516 | SemanticStackContext::SetLabel { 517 | label: String::from("if_begin").into() 518 | } 519 | ); 520 | assert_eq!( 521 | st_children_ctx[2], 522 | SemanticStackContext::JumpFunctionReturn { 523 | expr_result: ExpressionResult { 524 | expr_type: Type::Primitive(PrimitiveTypes::I8), 525 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::I8(10)), 526 | } 527 | } 528 | ); 529 | assert_eq!( 530 | st_children_ctx[3], 531 | SemanticStackContext::SetLabel { 532 | label: String::from("if_end").into() 533 | } 534 | ); 535 | 536 | // Semantic stack context for the block 537 | let st_ctx = ctx.get_context().get(); 538 | assert_eq!(st_ctx.len(), 5); 539 | assert_eq!(st_ctx[0], st_children_ctx[0]); 540 | assert_eq!(st_ctx[1], st_children_ctx[1]); 541 | assert_eq!(st_ctx[2], st_children_ctx[2]); 542 | assert_eq!(st_ctx[3], st_children_ctx[3]); 543 | assert_eq!( 544 | st_ctx[4], 545 | SemanticStackContext::ExpressionFunctionReturnWithLabel { 546 | expr_result: ExpressionResult { 547 | expr_type: Type::Primitive(PrimitiveTypes::I8), 548 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::I8(5)), 549 | } 550 | } 551 | ); 552 | 553 | // Global semantic stack context 554 | let st_global_context = t.state.global.context.get(); 555 | assert_eq!(st_global_context.len(), 1); 556 | assert_eq!( 557 | st_global_context[0], 558 | SemanticStackContext::FunctionDeclaration { 559 | fn_decl: fn1.into() 560 | } 561 | ); 562 | } 563 | 564 | #[test] 565 | fn function_args_and_let_binding() { 566 | let mut t = SemanticTest::new(); 567 | let body_let_binding = ast::BodyStatement::LetBinding(ast::LetBinding { 568 | name: ast::ValueName::new(Ident::new("y")), 569 | mutable: true, 570 | value_type: Some(ast::Type::Primitive(ast::PrimitiveTypes::U64)), 571 | value: Box::new(ast::Expression { 572 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::U64(23)), 573 | operation: Some(( 574 | ast::ExpressionOperations::Plus, 575 | Box::new(ast::Expression { 576 | expression_value: ast::ExpressionValue::ValueName(ast::ValueName::new( 577 | Ident::new("x"), 578 | )), 579 | operation: None, 580 | }), 581 | )), 582 | }), 583 | }); 584 | let body_expr_return = ast::BodyStatement::Expression(ast::Expression { 585 | expression_value: ast::ExpressionValue::ValueName(ast::ValueName::new(Ident::new("y"))), 586 | operation: None, 587 | }); 588 | 589 | let fn_param1 = ast::FunctionParameter { 590 | name: ast::ParameterName::new(Ident::new("x")), 591 | parameter_type: ast::Type::Primitive(ast::PrimitiveTypes::U64), 592 | }; 593 | let fn1 = ast::FunctionStatement::new( 594 | ast::FunctionName::new(Ident::new("fn1")), 595 | vec![fn_param1.clone()], 596 | ast::Type::Primitive(ast::PrimitiveTypes::U64), 597 | vec![body_let_binding, body_expr_return], 598 | ); 599 | let fn_stm = ast::MainStatement::Function(fn1.clone()); 600 | let main_stm: ast::Main< 601 | CustomExpressionInstruction, 602 | CustomExpression, 603 | > = vec![fn_stm]; 604 | t.state.run(&main_stm); 605 | assert!(t.is_empty_error()); 606 | 607 | assert_eq!(t.state.context.len(), 1); 608 | let ctx = t.state.context[0].borrow(); 609 | assert!(ctx.children.is_empty()); 610 | assert!(ctx.parent.is_none()); 611 | 612 | let stm_ctx = ctx.get_context().get(); 613 | let ty = Type::Primitive(PrimitiveTypes::U64); 614 | let value_x = Value { 615 | inner_name: "x".into(), 616 | inner_type: ty.clone(), 617 | mutable: false, 618 | alloca: false, 619 | malloc: false, 620 | }; 621 | let value_y = Value { 622 | inner_name: "y.0".into(), 623 | inner_type: ty.clone(), 624 | mutable: true, 625 | alloca: false, 626 | malloc: false, 627 | }; 628 | assert_eq!( 629 | stm_ctx[0], 630 | SemanticStackContext::FunctionArg { 631 | value: value_x.clone(), 632 | func_arg: fn_param1.into(), 633 | } 634 | ); 635 | assert_eq!( 636 | stm_ctx[1], 637 | SemanticStackContext::ExpressionValue { 638 | expression: value_x, 639 | register_number: 1, 640 | } 641 | ); 642 | assert_eq!( 643 | stm_ctx[2], 644 | SemanticStackContext::ExpressionOperation { 645 | operation: ExpressionOperations::Plus, 646 | left_value: ExpressionResult { 647 | expr_type: ty.clone(), 648 | expr_value: ExpressionResultValue::PrimitiveValue(PrimitiveValue::U64(23)), 649 | }, 650 | right_value: ExpressionResult { 651 | expr_type: ty.clone(), 652 | expr_value: ExpressionResultValue::Register(1), 653 | }, 654 | register_number: 2, 655 | } 656 | ); 657 | assert_eq!( 658 | stm_ctx[3], 659 | SemanticStackContext::LetBinding { 660 | let_decl: value_y.clone(), 661 | expr_result: ExpressionResult { 662 | expr_type: ty.clone(), 663 | expr_value: ExpressionResultValue::Register(2), 664 | }, 665 | } 666 | ); 667 | assert_eq!( 668 | stm_ctx[4], 669 | SemanticStackContext::ExpressionValue { 670 | expression: value_y, 671 | register_number: 3, 672 | } 673 | ); 674 | assert_eq!( 675 | stm_ctx[5], 676 | SemanticStackContext::ExpressionFunctionReturn { 677 | expr_result: ExpressionResult { 678 | expr_type: ty.clone(), 679 | expr_value: ExpressionResultValue::Register(3), 680 | } 681 | } 682 | ); 683 | 684 | // Verify global entities 685 | let fn_state = t 686 | .state 687 | .global 688 | .functions 689 | .get(&fn1.clone().name().into()) 690 | .unwrap(); 691 | assert_eq!(fn_state.inner_name, fn1.name.clone().into()); 692 | assert_eq!(fn_state.inner_type, fn1.result_type.clone().into()); 693 | assert_eq!(fn_state.parameters.len(), 1); 694 | assert_eq!(fn_state.parameters[0], ty); 695 | let global_ctx = t.state.global.context.get(); 696 | assert_eq!(global_ctx.len(), 1); 697 | assert_eq!( 698 | global_ctx[0], 699 | SemanticStackContext::FunctionDeclaration { 700 | fn_decl: fn1.into() 701 | } 702 | ); 703 | } 704 | 705 | #[test] 706 | fn function_args_duplication() { 707 | let mut t = SemanticTest::new(); 708 | let body_expr_return = ast::BodyStatement::Expression(ast::Expression { 709 | expression_value: ast::ExpressionValue::PrimitiveValue(ast::PrimitiveValue::U64(10)), 710 | operation: None, 711 | }); 712 | 713 | let fn_param1 = ast::FunctionParameter { 714 | name: ast::ParameterName::new(Ident::new("x")), 715 | parameter_type: ast::Type::Primitive(ast::PrimitiveTypes::U64), 716 | }; 717 | let fn_param2 = fn_param1.clone(); 718 | let fn1 = ast::FunctionStatement::new( 719 | ast::FunctionName::new(Ident::new("fn1")), 720 | vec![fn_param1.clone(), fn_param2.clone()], 721 | ast::Type::Primitive(ast::PrimitiveTypes::U64), 722 | vec![body_expr_return], 723 | ); 724 | let fn_stm = ast::MainStatement::Function(fn1.clone()); 725 | let main_stm: ast::Main< 726 | CustomExpressionInstruction, 727 | CustomExpression, 728 | > = vec![fn_stm]; 729 | t.state.run(&main_stm); 730 | assert!(t.check_errors_len(1)); 731 | assert!(t.check_error(StateErrorKind::FunctionArgumentNameDuplicated)); 732 | } 733 | --------------------------------------------------------------------------------