Skip to content

Commit

Permalink
Refactor analysis module into smaller modules.
Browse files Browse the repository at this point in the history
  • Loading branch information
kraigher committed Dec 29, 2019
1 parent 02a26ec commit d68066d
Show file tree
Hide file tree
Showing 11 changed files with 1,780 additions and 1,784 deletions.
11 changes: 8 additions & 3 deletions vhdl_parser/src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@
//
// Copyright (c) 2019, Olof Kraigher [email protected]

mod declarative_region;
mod library;
mod analyze;
mod concurrent;
mod declarative;
mod design_unit;
mod lock;
mod region;
mod root;
mod semantic;
mod sequential;

#[cfg(test)]
mod tests;

pub use self::library::DesignRoot;
pub use self::root::DesignRoot;
101 changes: 101 additions & 0 deletions vhdl_parser/src/analysis/analyze.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2019, Olof Kraigher [email protected]

use super::region::Region;
use super::root::DependencyRecorder;
use crate::data::*;

pub struct AnalyzeContext<'a> {
pub symtab: &'a SymbolTable,
pub work_sym: Symbol,
pub work_library_name: Symbol,
pub std_sym: Symbol,
pub standard_sym: Symbol,
pub root: DependencyRecorder<'a>,
}

impl<'a> AnalyzeContext<'a> {
pub fn new(
root: DependencyRecorder<'a>,
work_library_name: Symbol,
symtab: &'a SymbolTable,
) -> AnalyzeContext<'a> {
AnalyzeContext {
work_sym: symtab.insert(&Latin1String::new(b"work")),
work_library_name,
std_sym: symtab.insert(&Latin1String::new(b"std")),
standard_sym: symtab.insert(&Latin1String::new(b"standard")),
symtab,
root,
}
}
}

pub trait Analyze {
fn analyze(
&mut self,
context: &AnalyzeContext,
region: &mut Region<'_>,
diagnostics: &mut dyn DiagnosticHandler,
) -> FatalNullResult;
}

pub enum AnalysisError {
Fatal(CircularDependencyError),
NotFatal(Diagnostic),
}

#[derive(Clone, Debug)]
#[must_use]
pub struct CircularDependencyError {
reference: Option<SrcPos>,
}

impl CircularDependencyError {
pub fn new(reference: Option<&SrcPos>) -> CircularDependencyError {
CircularDependencyError {
reference: reference.cloned(),
}
}

pub fn push_into(self, diagnostics: &mut dyn DiagnosticHandler) {
if let Some(pos) = self.reference {
diagnostics.push(Diagnostic::error(
pos,
format!("Found circular dependency",),
));
}
}
}

pub type AnalysisResult<T> = Result<T, AnalysisError>;
pub type FatalResult<T> = Result<T, CircularDependencyError>;
pub type FatalNullResult = FatalResult<()>;

impl From<CircularDependencyError> for AnalysisError {
fn from(err: CircularDependencyError) -> AnalysisError {
AnalysisError::Fatal(err)
}
}

impl From<Diagnostic> for AnalysisError {
fn from(diagnostic: Diagnostic) -> AnalysisError {
AnalysisError::NotFatal(diagnostic)
}
}

impl AnalysisError {
// Add Non-fatal error to diagnostics or return fatal error
pub fn add_to(self, diagnostics: &mut dyn DiagnosticHandler) -> FatalNullResult {
match self {
AnalysisError::Fatal(err) => Err(err),
AnalysisError::NotFatal(diag) => {
diagnostics.push(diag);
Ok(())
}
}
}
}
186 changes: 186 additions & 0 deletions vhdl_parser/src/analysis/concurrent.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2019, Olof Kraigher [email protected]

use super::*;
use crate::ast::*;
use crate::data::*;
use analyze::*;
use region::*;

impl<'a> AnalyzeContext<'a> {
pub fn analyze_concurrent_part(
&self,
parent: &mut Region<'_>,
statements: &mut [LabeledConcurrentStatement],
diagnostics: &mut dyn DiagnosticHandler,
) -> FatalNullResult {
for statement in statements.iter_mut() {
self.analyze_concurrent_statement(parent, statement, diagnostics)?;
}

Ok(())
}

fn analyze_concurrent_statement(
&self,
parent: &mut Region<'_>,
statement: &mut LabeledConcurrentStatement,
diagnostics: &mut dyn DiagnosticHandler,
) -> FatalNullResult {
if let Some(ref label) = statement.label {
parent.add(label.clone(), AnyDeclaration::Constant, diagnostics);
}

match statement.statement {
ConcurrentStatement::Block(ref mut block) => {
let mut region = parent.nested();
self.analyze_declarative_part(&mut region, &mut block.decl, diagnostics)?;
self.analyze_concurrent_part(&mut region, &mut block.statements, diagnostics)?;
}
ConcurrentStatement::Process(ref mut process) => {
let ProcessStatement {
postponed: _,
sensitivity_list,
decl,
statements,
} = process;
if let Some(sensitivity_list) = sensitivity_list {
match sensitivity_list {
SensitivityList::Names(names) => {
for name in names.iter_mut() {
self.resolve_name(parent, &name.pos, &mut name.item, diagnostics)?;
}
}
SensitivityList::All => {}
}
}
let mut region = parent.nested();
self.analyze_declarative_part(&mut region, decl, diagnostics)?;
self.analyze_sequential_part(&mut region, statements, diagnostics)?;
}
ConcurrentStatement::ForGenerate(ref mut gen) => {
let ForGenerateStatement {
index_name,
discrete_range,
body,
} = gen;
self.analyze_discrete_range(parent, discrete_range, diagnostics)?;
let mut region = parent.nested();
region.add(index_name.clone(), AnyDeclaration::Constant, diagnostics);
self.analyze_generate_body(&mut region, body, diagnostics)?;
}
ConcurrentStatement::IfGenerate(ref mut gen) => {
let Conditionals {
conditionals,
else_item,
} = gen;
for conditional in conditionals.iter_mut() {
let Conditional { condition, item } = conditional;
self.analyze_expression(parent, condition, diagnostics)?;
let mut region = parent.nested();
self.analyze_generate_body(&mut region, item, diagnostics)?;
}
if let Some(ref mut else_item) = else_item {
let mut region = parent.nested();
self.analyze_generate_body(&mut region, else_item, diagnostics)?;
}
}
ConcurrentStatement::CaseGenerate(ref mut gen) => {
for alternative in gen.alternatives.iter_mut() {
let mut region = parent.nested();
self.analyze_generate_body(&mut region, &mut alternative.item, diagnostics)?;
}
}
ConcurrentStatement::Instance(ref mut instance) => {
self.analyze_instance(parent, instance, diagnostics)?;
}
ConcurrentStatement::Assignment(ref mut assign) => {
// @TODO more delaymechanism
let ConcurrentSignalAssignment { target, rhs, .. } = assign;
self.analyze_waveform_assignment(parent, target, rhs, diagnostics)?;
}
ConcurrentStatement::ProcedureCall(ref mut pcall) => {
let ConcurrentProcedureCall {
call,
postponed: _postponed,
} = pcall;
self.analyze_function_call(parent, call, diagnostics)?;
}
ConcurrentStatement::Assert(ref mut assert) => {
let ConcurrentAssertStatement {
postponed: _postponed,
statement:
AssertStatement {
condition,
report,
severity,
},
} = assert;
self.analyze_expression(parent, condition, diagnostics)?;
if let Some(expr) = report {
self.analyze_expression(parent, expr, diagnostics)?;
}
if let Some(expr) = severity {
self.analyze_expression(parent, expr, diagnostics)?;
}
}
};
Ok(())
}

fn analyze_generate_body(
&self,
region: &mut Region<'_>,
body: &mut GenerateBody,
diagnostics: &mut dyn DiagnosticHandler,
) -> FatalNullResult {
let GenerateBody {
alternative_label,
decl,
statements,
} = body;
if let Some(label) = alternative_label {
region.add(label.clone(), AnyDeclaration::Constant, diagnostics);
}
if let Some(ref mut decl) = decl {
self.analyze_declarative_part(region, decl, diagnostics)?;
}
self.analyze_concurrent_part(region, statements, diagnostics)?;

Ok(())
}

fn analyze_instance(
&self,
parent: &Region<'_>,
instance: &mut InstantiationStatement,
diagnostics: &mut dyn DiagnosticHandler,
) -> FatalNullResult {
match instance.unit {
// @TODO architecture
InstantiatedUnit::Entity(ref mut entity_name, ..) => {
if let Err(err) = self.resolve_selected_name(parent, entity_name) {
err.add_to(diagnostics)?;
}
}
InstantiatedUnit::Component(ref mut component_name) => {
if let Err(err) = self.resolve_selected_name(parent, component_name) {
err.add_to(diagnostics)?;
}
}
InstantiatedUnit::Configuration(ref mut config_name) => {
if let Err(err) = self.resolve_selected_name(parent, config_name) {
err.add_to(diagnostics)?;
}
}
};

self.analyze_assoc_elems(parent, &mut instance.generic_map, diagnostics)?;
self.analyze_assoc_elems(parent, &mut instance.port_map, diagnostics)?;

Ok(())
}
}
Loading

0 comments on commit d68066d

Please sign in to comment.