From 16eefc599398ba70c1159782d4d5e15578daac04 Mon Sep 17 00:00:00 2001 From: dalance Date: Fri, 17 Jan 2025 11:20:10 +0900 Subject: [PATCH] Introduce new type checker --- crates/analyzer/src/analyzer_error.rs | 18 + crates/analyzer/src/evaluator.rs | 1093 +++++++++++++---- .../src/handlers/check_clock_reset.rs | 7 +- crates/analyzer/src/handlers/check_enum.rs | 50 +- .../analyzer/src/handlers/check_expression.rs | 386 ++++-- .../src/handlers/create_symbol_table.rs | 11 +- crates/analyzer/src/namespace.rs | 10 + crates/analyzer/src/symbol.rs | 149 ++- crates/analyzer/src/symbol_path.rs | 10 + crates/analyzer/src/symbol_table.rs | 8 +- crates/analyzer/src/tests.rs | 121 +- crates/analyzer/src/var_ref.rs | 95 +- crates/emitter/src/emitter.rs | 31 +- crates/parser/src/veryl_grammar_trait.rs | 27 + crates/std/veryl/src/counter/counter.veryl | 2 +- 15 files changed, 1478 insertions(+), 540 deletions(-) diff --git a/crates/analyzer/src/analyzer_error.rs b/crates/analyzer/src/analyzer_error.rs index 6524a36c..5be3e398 100644 --- a/crates/analyzer/src/analyzer_error.rs +++ b/crates/analyzer/src/analyzer_error.rs @@ -1,3 +1,4 @@ +use crate::evaluator::EvaluatedError; use miette::{self, Diagnostic, NamedSource, SourceSpan}; use thiserror::Error; use veryl_parser::veryl_token::TokenRange; @@ -1756,4 +1757,21 @@ impl AnalyzerError { error_location: token.into(), } } + + pub fn evaluated_error(source: &str, error: &EvaluatedError) -> Self { + match error { + EvaluatedError::InvalidFactor { kind, token } => AnalyzerError::InvalidFactor { + identifier: token.to_string(), + kind: kind.clone(), + input: AnalyzerError::named_source(source, &token.into()), + error_location: token.into(), + }, + EvaluatedError::CallNonFunction { kind, token } => AnalyzerError::CallNonFunction { + identifier: token.to_string(), + kind: kind.clone(), + input: AnalyzerError::named_source(source, &token.into()), + error_location: token.into(), + }, + } + } } diff --git a/crates/analyzer/src/evaluator.rs b/crates/analyzer/src/evaluator.rs index ae0e17ee..e7f6d073 100644 --- a/crates/analyzer/src/evaluator.rs +++ b/crates/analyzer/src/evaluator.rs @@ -1,168 +1,526 @@ -use crate::symbol::{Type, TypeKind}; +use crate::symbol::{SymbolId, Type, TypeKind}; use crate::symbol_table::{self, ResolveError, ResolveResult}; use veryl_parser::veryl_grammar_trait::*; +use veryl_parser::veryl_token::Token; -#[derive(Clone, Copy, Debug)] -pub enum Evaluated { - Fixed { width: usize, value: isize }, - Variable { width: usize }, - Clock, - ClockPosedge, - ClockNegedge, - Reset, - ResetAsyncHigh, - ResetAsyncLow, - ResetSyncHigh, - ResetSyncLow, +#[derive(Clone, Debug)] +pub struct Evaluated { + pub value: EvaluatedValue, + pub r#type: EvaluatedType, + pub errors: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum EvaluatedValue { + Fixed(isize), + FixedArray(Vec), Unknown, - UnknownStatic, // A temporary enum value to indicate that a value is knowable statically, - // even if, currently, the compiler doesn't know what its value is + UnknownStatic, } -impl Evaluated { - fn is_known_static(&self) -> bool { - matches!(self, Evaluated::Fixed { .. } | Evaluated::UnknownStatic) +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum EvaluatedType { + Clock(EvaluatedTypeClock), + Reset(EvaluatedTypeReset), + Bit(EvaluatedTypeBit), + Logic(EvaluatedTypeLogic), + UserDefined(EvaluatedTypeUserDefined), + Unknown, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct EvaluatedTypeClock { + pub kind: EvaluatedTypeClockKind, + pub width: Vec, + pub array: Vec, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum EvaluatedTypeClockKind { + Implicit, + Posedge, + Negedge, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct EvaluatedTypeReset { + pub kind: EvaluatedTypeResetKind, + pub width: Vec, + pub array: Vec, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum EvaluatedTypeResetKind { + Implicit, + AsyncHigh, + AsyncLow, + SyncHigh, + SyncLow, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct EvaluatedTypeBit { + pub signed: bool, + pub width: Vec, + pub array: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct EvaluatedTypeLogic { + pub signed: bool, + pub width: Vec, + pub array: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct EvaluatedTypeUserDefined { + pub symbol: SymbolId, + pub width: Vec, + pub array: Vec, +} + +#[derive(Clone, Debug)] +pub enum EvaluatedError { + InvalidFactor { kind: String, token: Token }, + CallNonFunction { kind: String, token: Token }, +} + +fn reduction isize>( + value: isize, + width: Option, + func: T, +) -> Option { + if let Some(width) = width { + let mut tmp = value; + let mut ret = tmp & 1; + for _ in 1..width { + tmp >>= 1; + ret = func(ret, tmp & 1); + } + Some(ret) + } else { + None } +} - pub fn is_clock(&self) -> bool { +impl Evaluated { + pub fn is_known_static(&self) -> bool { matches!( - self, - Evaluated::Clock | Evaluated::ClockPosedge | Evaluated::ClockNegedge + self.value, + EvaluatedValue::Fixed(_) + | EvaluatedValue::FixedArray(_) + | EvaluatedValue::UnknownStatic ) } + pub fn is_clock(&self) -> bool { + matches!(self.r#type, EvaluatedType::Clock(_)) + } + pub fn is_reset(&self) -> bool { - matches!( - self, - Evaluated::Reset - | Evaluated::ResetAsyncHigh - | Evaluated::ResetAsyncLow - | Evaluated::ResetSyncHigh - | Evaluated::ResetSyncLow - ) + matches!(self.r#type, EvaluatedType::Reset(_)) + } + + pub fn get_value(&self) -> Option { + if let EvaluatedValue::Fixed(x) = self.value { + Some(x) + } else { + None + } + } + + pub fn get_width(&self) -> Vec { + match &self.r#type { + EvaluatedType::Clock(x) => x.width.clone(), + EvaluatedType::Reset(x) => x.width.clone(), + EvaluatedType::Bit(x) => x.width.clone(), + EvaluatedType::Logic(x) => x.width.clone(), + EvaluatedType::UserDefined(x) => x.width.clone(), + EvaluatedType::Unknown => Vec::new(), + } + } + + pub fn get_array(&self) -> Vec { + match &self.r#type { + EvaluatedType::Clock(x) => x.array.clone(), + EvaluatedType::Reset(x) => x.array.clone(), + EvaluatedType::Bit(x) => x.array.clone(), + EvaluatedType::Logic(x) => x.array.clone(), + EvaluatedType::UserDefined(x) => x.array.clone(), + EvaluatedType::Unknown => Vec::new(), + } + } + + pub fn get_total_width(&self) -> Option { + let width = match &self.r#type { + EvaluatedType::Clock(x) => Some(&x.width), + EvaluatedType::Reset(x) => Some(&x.width), + EvaluatedType::Bit(x) => Some(&x.width), + EvaluatedType::Logic(x) => Some(&x.width), + // TODO calc width of user defined type + EvaluatedType::UserDefined(_) => None, + EvaluatedType::Unknown => None, + }; + if let Some(width) = width { + if width.is_empty() { + None + } else { + Some(width.iter().product()) + } + } else { + None + } + } + + pub fn set_value(&mut self, value: isize) { + if let EvaluatedValue::Fixed(x) = &mut self.value { + *x = value; + } + } + + pub fn set_width(&mut self, width: Vec) { + match &mut self.r#type { + EvaluatedType::Clock(x) => x.width = width, + EvaluatedType::Reset(x) => x.width = width, + EvaluatedType::Bit(x) => x.width = width, + EvaluatedType::Logic(x) => x.width = width, + EvaluatedType::UserDefined(x) => x.width = width, + EvaluatedType::Unknown => (), + } + } + + pub fn set_array(&mut self, array: Vec) { + match &mut self.r#type { + EvaluatedType::Clock(x) => x.array = array, + EvaluatedType::Reset(x) => x.array = array, + EvaluatedType::Bit(x) => x.array = array, + EvaluatedType::Logic(x) => x.array = array, + EvaluatedType::UserDefined(x) => x.array = array, + EvaluatedType::Unknown => (), + } + } + + pub fn get_clock_kind(&self) -> Option { + match &self.r#type { + EvaluatedType::Clock(x) => Some(x.kind), + _ => None, + } } - fn binary_op usize, U: Fn(isize, isize) -> Option>( - left: Evaluated, - right: Evaluated, - width: T, - value: U, + pub fn get_reset_kind(&self) -> Option { + match &self.r#type { + EvaluatedType::Reset(x) => Some(x.kind), + _ => None, + } + } + + pub fn create_unknown() -> Evaluated { + Evaluated { + value: EvaluatedValue::Unknown, + r#type: EvaluatedType::Unknown, + errors: vec![], + } + } + + pub fn set_unknown(&mut self) { + self.value = EvaluatedValue::Unknown; + self.r#type = EvaluatedType::Unknown; + } + + pub fn create_unknown_static() -> Evaluated { + let mut ret = Self::create_unknown(); + ret.set_unknown_static(); + ret + } + + pub fn set_unknown_static(&mut self) { + self.value = EvaluatedValue::UnknownStatic; + self.r#type = EvaluatedType::Unknown; + } + + pub fn create_fixed( + value: isize, + signed: bool, + width: Vec, + array: Vec, ) -> Evaluated { - if let ( - Evaluated::Fixed { - width: width0, - value: value0, - }, - Evaluated::Fixed { - width: width1, - value: value1, - }, - ) = (left, right) - { - let value = value(value0, value1); - if let Some(value) = value { - Evaluated::Fixed { - width: width(width0, width1), - value, + let mut ret = Self::create_unknown(); + ret.set_fixed(value, signed, width, array); + ret + } + + pub fn set_fixed(&mut self, value: isize, signed: bool, width: Vec, array: Vec) { + self.value = EvaluatedValue::Fixed(value); + self.r#type = EvaluatedType::Bit(EvaluatedTypeBit { + signed, + width, + array, + }); + } + + pub fn create_variable(signed: bool, width: Vec, array: Vec) -> Evaluated { + let mut ret = Self::create_unknown(); + ret.set_variable(signed, width, array); + ret + } + + pub fn set_variable(&mut self, signed: bool, width: Vec, array: Vec) { + self.value = EvaluatedValue::Unknown; + self.r#type = EvaluatedType::Logic(EvaluatedTypeLogic { + signed, + width, + array, + }); + } + + pub fn create_clock( + kind: EvaluatedTypeClockKind, + width: Vec, + array: Vec, + ) -> Evaluated { + let mut ret = Self::create_unknown(); + ret.set_clock(kind, width, array); + ret + } + + pub fn set_clock( + &mut self, + kind: EvaluatedTypeClockKind, + width: Vec, + array: Vec, + ) { + self.value = EvaluatedValue::Unknown; + self.r#type = EvaluatedType::Clock(EvaluatedTypeClock { kind, width, array }); + } + + pub fn create_reset( + kind: EvaluatedTypeResetKind, + width: Vec, + array: Vec, + ) -> Evaluated { + let mut ret = Self::create_unknown(); + ret.set_reset(kind, width, array); + ret + } + + pub fn set_reset( + &mut self, + kind: EvaluatedTypeResetKind, + width: Vec, + array: Vec, + ) { + self.value = EvaluatedValue::Unknown; + self.r#type = EvaluatedType::Reset(EvaluatedTypeReset { kind, width, array }); + } + + pub fn select(mut self, mut beg: Evaluated, mut end: Evaluated) -> Evaluated { + let value = self.get_value(); + let width = self.get_width(); + let array = self.get_array(); + if let (Some(beg), Some(end)) = (beg.get_value(), end.get_value()) { + if let Some(x) = array.first() { + if *x == 1 { + // select width + + let select_width = width.first().unwrap_or(&0); + let mut rest = width[1..].to_vec(); + dbg!(select_width); + if end > beg { + // TODO index error + self.set_unknown(); + } else if beg >= *select_width as isize { + // TODO out of range error + self.set_unknown(); + } else { + let part_size: usize = if rest.is_empty() { + 1 + } else { + rest.iter().product() + }; + + let end_bit = end * part_size as isize; + let beg_bit = beg * part_size as isize; + + if let Some(value) = value { + let mask = !(1 << (beg_bit - end_bit + 1)); + let new_value = (value >> end_bit) & mask; + self.set_value(new_value); + } + + let new_width = if beg == end { + if rest.is_empty() { + vec![1] + } else { + rest + } + } else { + let mut new_width = vec![(beg - end + 1) as usize]; + new_width.append(&mut rest); + new_width + }; + + self.set_width(new_width); + } + } else { + // select array + + let select_array = array.first().unwrap_or(&0); + let _rest: Vec<_> = array[1..].iter().collect(); + if beg > end { + // TODO index error + self.set_unknown(); + } else if end >= *select_array as isize { + // TODO out of range error + self.set_unknown(); + } else { + self.set_unknown(); + } } } else { - Evaluated::Variable { - width: width(width0, width1), - } - } - } else if let ( - Evaluated::Fixed { width: width0, .. }, - Evaluated::Variable { width: width1 }, - ) = (left, right) - { - Evaluated::Variable { - width: width(width0, width1), - } - } else if let ( - Evaluated::Variable { width: width0 }, - Evaluated::Fixed { width: width1, .. }, - ) = (left, right) - { - Evaluated::Variable { - width: width(width0, width1), - } - } else if let ( - Evaluated::Variable { width: width0 }, - Evaluated::Variable { width: width1 }, - ) = (left, right) - { - Evaluated::Variable { - width: width(width0, width1), + self.set_unknown(); } } else { - Evaluated::Unknown + self.set_unknown(); } + + self.errors.append(&mut beg.errors); + self.errors.append(&mut end.errors); + self } - fn unary_op usize, U: Fn(isize) -> Option>( - left: Evaluated, - width: T, - value: U, + fn binary_op< + T: Fn(usize, usize, Option<&usize>) -> usize, + U: Fn(isize, isize) -> Option, + >( + mut left: Evaluated, + mut right: Evaluated, + context_width: Option<&usize>, + calc_width: T, + calc_value: U, ) -> Evaluated { - if let Evaluated::Fixed { - width: width0, - value: value0, - } = left - { - let value = value(value0); - if let Some(value) = value { - Evaluated::Fixed { - width: width(width0), - value, + // TODO array error + + let mut ret = match ( + left.get_value(), + right.get_value(), + left.get_total_width(), + right.get_total_width(), + ) { + (Some(value0), Some(value1), Some(width0), Some(width1)) => { + let value = calc_value(value0, value1); + let width = calc_width(width0, width1, context_width); + if let Some(value) = value { + Evaluated::create_fixed(value, false, vec![width], vec![1]) + } else { + Evaluated::create_variable(false, vec![width], vec![1]) } - } else { - Evaluated::Variable { - width: width(width0), + } + (_, _, Some(width0), Some(width1)) => { + let width = calc_width(width0, width1, context_width); + Evaluated::create_variable(false, vec![width], vec![1]) + } + _ => Evaluated::create_unknown(), + }; + + ret.errors.append(&mut left.errors); + ret.errors.append(&mut right.errors); + ret + } + + fn unary_op usize, U: Fn(isize) -> Option>( + mut left: Evaluated, + calc_width: T, + calc_value: U, + ) -> Evaluated { + // TODO array error + + let mut ret = match (left.get_value(), left.get_total_width()) { + (Some(value0), Some(width0)) => { + let value = calc_value(value0); + let width = calc_width(width0); + if let Some(value) = value { + Evaluated::create_fixed(value, false, vec![width], vec![1]) + } else { + Evaluated::create_variable(false, vec![width], vec![1]) } } - } else if let Evaluated::Variable { width: width0 } = left { - Evaluated::Variable { - width: width(width0), + (_, Some(width0)) => { + let width = calc_width(width0); + Evaluated::create_variable(false, vec![width], vec![1]) } - } else { - Evaluated::Unknown - } + _ => Evaluated::create_unknown(), + }; + + ret.errors.append(&mut left.errors); + ret } - fn pow(self, exp: Evaluated) -> Evaluated { + fn pow(self, exp: Evaluated, context_width: Option<&usize>) -> Evaluated { Self::binary_op( self, exp, - |x, _| x, + context_width, + |x, y, z| x.max(y).max(*z.unwrap_or(&0)), |x, y| y.try_into().map(|y| x.checked_pow(y)).ok().flatten(), ) } - fn div(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |x, y| x.max(y), |x, y| x.checked_div(y)) + fn div(self, exp: Evaluated, context_width: Option<&usize>) -> Evaluated { + Self::binary_op( + self, + exp, + context_width, + |x, y, z| x.max(y).max(*z.unwrap_or(&0)), + |x, y| x.checked_div(y), + ) } - fn rem(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |x, y| x.max(y), |x, y| x.checked_rem(y)) + fn rem(self, exp: Evaluated, context_width: Option<&usize>) -> Evaluated { + Self::binary_op( + self, + exp, + context_width, + |x, y, z| x.max(y).max(*z.unwrap_or(&0)), + |x, y| x.checked_rem(y), + ) } - fn mul(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |x, y| x.max(y), |x, y| x.checked_mul(y)) + fn mul(self, exp: Evaluated, context_width: Option<&usize>) -> Evaluated { + Self::binary_op( + self, + exp, + context_width, + |x, y, z| x.max(y).max(*z.unwrap_or(&0)), + |x, y| x.checked_mul(y), + ) } - fn add(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |x, y| x.max(y), |x, y| x.checked_add(y)) + fn add(self, exp: Evaluated, context_width: Option<&usize>) -> Evaluated { + Self::binary_op( + self, + exp, + context_width, + |x, y, z| x.max(y).max(*z.unwrap_or(&0)), + |x, y| x.checked_add(y), + ) } - fn sub(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |x, y| x.max(y), |x, y| x.checked_sub(y)) + fn sub(self, exp: Evaluated, context_width: Option<&usize>) -> Evaluated { + Self::binary_op( + self, + exp, + context_width, + |x, y, z| x.max(y).max(*z.unwrap_or(&0)), + |x, y| x.checked_sub(y), + ) } - fn unsigned_shl(self, exp: Evaluated) -> Evaluated { + fn unsigned_shl(self, exp: Evaluated, context_width: Option<&usize>) -> Evaluated { Self::binary_op( self, exp, - |x, _| x, + context_width, + |x, _, z| x.max(*z.unwrap_or(&0)), |x, y| { y.try_into() .map(|y| (x as usize).checked_shl(y).map(|x| x as isize)) @@ -172,11 +530,12 @@ impl Evaluated { ) } - fn unsigned_shr(self, exp: Evaluated) -> Evaluated { + fn unsigned_shr(self, exp: Evaluated, context_width: Option<&usize>) -> Evaluated { Self::binary_op( self, exp, - |x, _| x, + context_width, + |x, _, z| x.max(*z.unwrap_or(&0)), |x, y| { y.try_into() .map(|y| (x as usize).checked_shr(y).map(|x| x as isize)) @@ -186,53 +545,92 @@ impl Evaluated { ) } - fn signed_shl(self, exp: Evaluated) -> Evaluated { + fn signed_shl(self, exp: Evaluated, context_width: Option<&usize>) -> Evaluated { Self::binary_op( self, exp, - |x, _| x, + context_width, + |x, _, z| x.max(*z.unwrap_or(&0)), |x, y| y.try_into().map(|y| x.checked_shl(y)).ok().flatten(), ) } - fn signed_shr(self, exp: Evaluated) -> Evaluated { + fn signed_shr(self, exp: Evaluated, context_width: Option<&usize>) -> Evaluated { Self::binary_op( self, exp, - |x, _| x, + context_width, + |x, _, z| x.max(*z.unwrap_or(&0)), |x, y| y.try_into().map(|y| x.checked_shr(y)).ok().flatten(), ) } fn le(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |_, _| 1, |x, y| Some(x.cmp(&y).is_le() as isize)) + Self::binary_op( + self, + exp, + None, + |_, _, _| 1, + |x, y| Some(x.cmp(&y).is_le() as isize), + ) } fn ge(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |_, _| 1, |x, y| Some(x.cmp(&y).is_ge() as isize)) + Self::binary_op( + self, + exp, + None, + |_, _, _| 1, + |x, y| Some(x.cmp(&y).is_ge() as isize), + ) } fn lt(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |_, _| 1, |x, y| Some(x.cmp(&y).is_lt() as isize)) + Self::binary_op( + self, + exp, + None, + |_, _, _| 1, + |x, y| Some(x.cmp(&y).is_lt() as isize), + ) } fn gt(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |_, _| 1, |x, y| Some(x.cmp(&y).is_gt() as isize)) + Self::binary_op( + self, + exp, + None, + |_, _, _| 1, + |x, y| Some(x.cmp(&y).is_gt() as isize), + ) } fn eq(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |_, _| 1, |x, y| Some(x.cmp(&y).is_eq() as isize)) + Self::binary_op( + self, + exp, + None, + |_, _, _| 1, + |x, y| Some(x.cmp(&y).is_eq() as isize), + ) } fn ne(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |_, _| 1, |x, y| Some(x.cmp(&y).is_ne() as isize)) + Self::binary_op( + self, + exp, + None, + |_, _, _| 1, + |x, y| Some(x.cmp(&y).is_ne() as isize), + ) } fn andand(self, exp: Evaluated) -> Evaluated { Self::binary_op( self, exp, - |_, _| 1, + None, + |_, _, _| 1, |x, y| Some((x != 0 && y != 0) as isize), ) } @@ -241,25 +639,28 @@ impl Evaluated { Self::binary_op( self, exp, - |_, _| 1, + None, + |_, _, _| 1, |x, y| Some((x != 0 || y != 0) as isize), ) } fn and(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |x, y| x.max(y), |x, y| Some(x & y)) + Self::binary_op(self, exp, None, |x, y, _| x.max(y), |x, y| Some(x & y)) } fn or(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |x, y| x.max(y), |x, y| Some(x | y)) + Self::binary_op(self, exp, None, |x, y, _| x.max(y), |x, y| Some(x | y)) } fn xor(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |x, y| x.max(y), |x, y| Some(x ^ y)) + let ret = Self::binary_op(self, exp, None, |x, y, _| x.max(y), |x, y| Some(x ^ y)); + dbg!(&ret); + ret } fn xnor(self, exp: Evaluated) -> Evaluated { - Self::binary_op(self, exp, |x, y| x.max(y), |x, y| Some(!(x ^ y))) + Self::binary_op(self, exp, None, |x, y, _| x.max(y), |x, y| Some(!(x ^ y))) } fn plus(self) -> Evaluated { @@ -279,27 +680,54 @@ impl Evaluated { } fn reduction_and(self) -> Evaluated { - Self::unary_op(self, |_| 1, |_| None) + let width = self.get_total_width(); + Self::unary_op(self, |_| 1, |x| reduction(x, width, |x, y| x & y)) } fn reduction_or(self) -> Evaluated { - Self::unary_op(self, |_| 1, |_| None) + let width = self.get_total_width(); + Self::unary_op(self, |_| 1, |x| reduction(x, width, |x, y| x | y)) } fn reduction_nand(self) -> Evaluated { - Self::unary_op(self, |_| 1, |_| None) + let width = self.get_total_width(); + Self::unary_op( + self, + |_| 1, + |x| { + let ret = reduction(x, width, |x, y| x & y); + ret.map(|x| if x == 0 { 1 } else { 0 }) + }, + ) } fn reduction_nor(self) -> Evaluated { - Self::unary_op(self, |_| 1, |_| None) + let width = self.get_total_width(); + Self::unary_op( + self, + |_| 1, + |x| { + let ret = reduction(x, width, |x, y| x | y); + ret.map(|x| if x == 0 { 1 } else { 0 }) + }, + ) } fn reduction_xor(self) -> Evaluated { - Self::unary_op(self, |_| 1, |_| None) + let width = self.get_total_width(); + Self::unary_op(self, |_| 1, |x| reduction(x, width, |x, y| x ^ y)) } fn reduction_xnor(self) -> Evaluated { - Self::unary_op(self, |_| 1, |_| None) + let width = self.get_total_width(); + Self::unary_op( + self, + |_| 1, + |x| { + let ret = reduction(x, width, |x, y| x ^ y); + ret.map(|x| if x == 0 { 1 } else { 0 }) + }, + ) } } @@ -315,20 +743,20 @@ impl Evaluator { fn binary_operator(&mut self, operator: &str, left: Evaluated, right: Evaluated) -> Evaluated { match operator { - "**" => left.pow(right), - "/" => left.div(right), - "*" => left.mul(right), - "%" => left.rem(right), - "+" => left.add(right), - "-" => left.sub(right), - "<<<" => left.signed_shl(right), - ">>>" => left.signed_shr(right), - "<<" => left.unsigned_shl(right), - ">>" => left.unsigned_shr(right), + "**" => left.pow(right, self.context_width.first()), + "/" => left.div(right, self.context_width.first()), + "*" => left.mul(right, self.context_width.first()), + "%" => left.rem(right, self.context_width.first()), + "+" => left.add(right, self.context_width.first()), + "-" => left.sub(right, self.context_width.first()), + "<<<" => left.signed_shl(right, self.context_width.first()), + ">>>" => left.signed_shr(right, self.context_width.first()), + "<<" => left.unsigned_shl(right, self.context_width.first()), + ">>" => left.unsigned_shr(right, self.context_width.first()), "<=" => left.le(right), ">=" => left.ge(right), - "<" => left.lt(right), - ">" => left.gt(right), + "<:" => left.lt(right), + ">:" => left.gt(right), "===" => left.eq(right), "==?" => left.eq(right), "!==" => left.ne(right), @@ -342,7 +770,7 @@ impl Evaluator { "^" => left.xor(right), "~^" => left.xnor(right), "|" => left.or(right), - _ => Evaluated::Unknown, + _ => Evaluated::create_unknown(), } } @@ -359,54 +787,88 @@ impl Evaluator { "^" => left.reduction_xor(), "~^" => left.reduction_xnor(), "^~" => left.reduction_xnor(), - _ => Evaluated::Unknown, + _ => Evaluated::create_unknown(), } } - pub fn type_width(&mut self, x: Type) -> Option { + pub fn type_width(&mut self, x: Type) -> Option> { match x.kind { TypeKind::U32 | TypeKind::I32 | TypeKind::F32 => { if x.width.is_empty() { - Some(32) + Some(vec![32]) } else { + // TODO error None } } TypeKind::U64 | TypeKind::I64 | TypeKind::F64 => { if x.width.is_empty() { - Some(64) + Some(vec![64]) } else { + // TODO error None } } - TypeKind::Bit | TypeKind::Logic => { - if x.width.len() == 1 { - let width = self.expression(&x.width[0]); - if let Evaluated::Fixed { value, .. } = width { - if let Ok(width) = value.try_into() { - Some(width) + TypeKind::Bit + | TypeKind::Logic + | TypeKind::Clock + | TypeKind::ClockPosedge + | TypeKind::ClockNegedge + | TypeKind::Reset + | TypeKind::ResetAsyncHigh + | TypeKind::ResetAsyncLow + | TypeKind::ResetSyncHigh + | TypeKind::ResetSyncLow => { + if x.width.is_empty() { + Some(vec![1]) + } else { + let mut ret = Vec::new(); + for x in &x.width { + let width = self.expression(x); + if let EvaluatedValue::Fixed(value) = width.value { + if let Ok(width) = value.try_into() { + ret.push(width); + } else { + return None; + } } else { - None + return None; } + } + Some(ret) + } + } + _ => None, + } + } + + pub fn type_array(&mut self, x: Type) -> Option> { + if x.array.is_empty() { + Some(vec![1]) + } else { + let mut ret = Vec::new(); + for x in &x.array { + let width = self.expression(x); + if let EvaluatedValue::Fixed(value) = width.value { + if let Ok(width) = value.try_into() { + ret.push(width); } else { - None + return None; } - } else if x.width.is_empty() { - Some(1) } else { - None + return None; } } - _ => None, + Some(ret) } } fn exponent(&mut self, _arg: &Exponent) -> Evaluated { - Evaluated::Unknown + Evaluated::create_unknown() } fn fixed_point(&mut self, _arg: &FixedPoint) -> Evaluated { - Evaluated::Unknown + Evaluated::create_unknown() } fn based(&mut self, arg: &Based) -> Evaluated { @@ -422,24 +884,24 @@ impl Evaluator { "h" => 16, _ => unreachable!(), }; - let width = width.parse(); + let width = str::parse::(width); let value = isize::from_str_radix(value, radix); if let (Ok(width), Ok(value)) = (width, value) { - Evaluated::Fixed { width, value } + Evaluated::create_fixed(value, signed, vec![width], vec![1]) } else { - Evaluated::Unknown + Evaluated::create_unknown_static() } } else { - Evaluated::Unknown + Evaluated::create_unknown_static() } } fn base_less(&mut self, arg: &BaseLess) -> Evaluated { let text = arg.base_less_token.to_string().replace('_', ""); - if let Ok(value) = text.parse() { - Evaluated::Fixed { width: 32, value } + if let Ok(value) = str::parse::(&text) { + Evaluated::create_fixed(value, false, vec![32], vec![1]) } else { - Evaluated::Unknown + Evaluated::create_unknown() } } @@ -466,12 +928,10 @@ impl Evaluator { } }; if unknown { - Evaluated::Unknown + Evaluated::create_unknown() } else { - Evaluated::Fixed { - width: *self.context_width.last().unwrap_or(&0), - value, - } + let width = *self.context_width.last().unwrap_or(&0); + Evaluated::create_fixed(value, false, vec![width], vec![1]) } } @@ -611,19 +1071,56 @@ impl Evaluator { } fn expression11(&mut self, arg: &Expression11) -> Evaluated { - let ret = self.expression12(&arg.expression12); + let mut ret = self.expression12(&arg.expression12); if let Some(x) = &arg.expression11_opt { - match x.casting_type.as_ref() { - CastingType::Clock(_) => Evaluated::Clock, - CastingType::ClockPosedge(_) => Evaluated::ClockPosedge, - CastingType::ClockNegedge(_) => Evaluated::ClockNegedge, - CastingType::Reset(_) => Evaluated::Reset, - CastingType::ResetAsyncHigh(_) => Evaluated::ResetAsyncHigh, - CastingType::ResetAsyncLow(_) => Evaluated::ResetAsyncLow, - CastingType::ResetSyncHigh(_) => Evaluated::ResetSyncHigh, - CastingType::ResetSyncLow(_) => Evaluated::ResetSyncLow, - _ => ret, + let new_type = match x.casting_type.as_ref() { + CastingType::Clock(_) => Some(Evaluated::create_clock( + EvaluatedTypeClockKind::Implicit, + vec![1], + vec![1], + )), + CastingType::ClockPosedge(_) => Some(Evaluated::create_clock( + EvaluatedTypeClockKind::Posedge, + vec![1], + vec![1], + )), + CastingType::ClockNegedge(_) => Some(Evaluated::create_clock( + EvaluatedTypeClockKind::Negedge, + vec![1], + vec![1], + )), + CastingType::Reset(_) => Some(Evaluated::create_reset( + EvaluatedTypeResetKind::Implicit, + vec![1], + vec![1], + )), + CastingType::ResetAsyncHigh(_) => Some(Evaluated::create_reset( + EvaluatedTypeResetKind::AsyncHigh, + vec![1], + vec![1], + )), + CastingType::ResetAsyncLow(_) => Some(Evaluated::create_reset( + EvaluatedTypeResetKind::AsyncLow, + vec![1], + vec![1], + )), + CastingType::ResetSyncHigh(_) => Some(Evaluated::create_reset( + EvaluatedTypeResetKind::SyncHigh, + vec![1], + vec![1], + )), + CastingType::ResetSyncLow(_) => Some(Evaluated::create_reset( + EvaluatedTypeResetKind::SyncLow, + vec![1], + vec![1], + )), + _ => None, + }; + if let Some(x) = new_type { + // TODO check casting error + ret.r#type = x.r#type; } + ret } else { ret } @@ -658,7 +1155,7 @@ impl Evaluator { if let Ok(symbol) = symbol { symbol.found.evaluate() } else { - Evaluated::Unknown + Evaluated::create_unknown() } } @@ -668,17 +1165,72 @@ impl Evaluator { } fn expression_identifier(&mut self, arg: &ExpressionIdentifier) -> Evaluated { + // TODO array / bit select let symbol = symbol_table::resolve(arg); - self.identifier_helper(symbol) + + let last_select: Vec<_> = if arg.expression_identifier_list0.is_empty() { + arg.expression_identifier_list + .iter() + .map(|x| x.select.clone()) + .collect() + } else { + arg.expression_identifier_list0 + .last() + .unwrap() + .expression_identifier_list0_list + .iter() + .map(|x| x.select.clone()) + .collect() + }; + + let mut ret = self.identifier_helper(symbol); + + for s in &last_select { + let beg = self.expression(s.expression.as_ref()); + let end = if let Some(x) = &s.select_opt { + self.expression(x.expression.as_ref()) + } else { + beg.clone() + }; + + ret = ret.select(beg, end); + } + + ret } fn factor(&mut self, arg: &Factor) -> Evaluated { match arg { Factor::Number(x) => self.number(&x.number), Factor::IdentifierFactor(x) => { - if x.identifier_factor.identifier_factor_opt.is_some() { - // Function call - Evaluated::Unknown + if let Some(args) = &x.identifier_factor.identifier_factor_opt { + let args = &args.function_call.function_call_opt; + let func = x + .identifier_factor + .expression_identifier + .identifier() + .to_string(); + + if func.starts_with("$") { + self.system_function(&func, args) + } else { + let mut ret = Evaluated::create_unknown(); + + if let Ok(symbol) = symbol_table::resolve( + x.identifier_factor.expression_identifier.as_ref(), + ) { + if !symbol.found.kind.is_function() { + ret.errors.push(EvaluatedError::CallNonFunction { + kind: symbol.found.kind.to_kind_name(), + token: symbol.found.token, + }); + } + } + + // TODO return type of function + + ret + } } else { // Identifier self.expression_identifier(x.identifier_factor.expression_identifier.as_ref()) @@ -694,58 +1246,79 @@ impl Evaluator { Factor::IfExpression(x) => self.if_expression(&x.if_expression), Factor::CaseExpression(x) => self.case_expression(&x.case_expression), Factor::SwitchExpression(x) => self.switch_expression(&x.switch_expression), - Factor::StringLiteral(_) => Evaluated::Unknown, - Factor::FactorGroup(_) => Evaluated::Unknown, - Factor::InsideExpression(_) => Evaluated::Unknown, - Factor::OutsideExpression(_) => Evaluated::Unknown, - Factor::TypeExpression(_) => Evaluated::Unknown, - Factor::FactorTypeFactor(_) => Evaluated::Unknown, - } - } - - fn do_concatenation(&mut self, exp: Evaluated, rep: Evaluated) -> Evaluated { - match exp { - Evaluated::Fixed { - width: ewidth, - value: eval, - } => match rep { - Evaluated::Fixed { - width: rwidth, - value: rval, - } => { - let width = ewidth * rwidth; - let mut value = eval; - for _ in 0..rval { - value <<= ewidth; - value |= eval; - } - Evaluated::Fixed { width, value } - } - Evaluated::Variable { width: rwidth } => Evaluated::Variable { - width: ewidth * rwidth, - }, - Evaluated::UnknownStatic => Evaluated::UnknownStatic, - _ => Evaluated::Unknown, - }, - Evaluated::Variable { width: ewidth } => match rep { - Evaluated::Fixed { width: rwidth, .. } | Evaluated::Variable { width: rwidth } => { - Evaluated::Variable { - width: ewidth * rwidth, + Factor::StringLiteral(_) => Evaluated::create_unknown(), + Factor::FactorGroup(_) => Evaluated::create_unknown(), + Factor::InsideExpression(_) => Evaluated::create_unknown(), + Factor::OutsideExpression(_) => Evaluated::create_unknown(), + Factor::TypeExpression(_) => Evaluated::create_unknown(), + Factor::FactorTypeFactor(_) => Evaluated::create_unknown(), + } + } + + fn system_function(&mut self, name: &str, args: &Option) -> Evaluated { + let args: Vec = if let Some(x) = args { + x.argument_list.as_ref().into() + } else { + Vec::new() + }; + + match name { + "$clog2" => { + if let Some(arg) = args.first() { + let arg = self.expression(&arg.expression); + if let EvaluatedValue::Fixed(x) = arg.value { + let ret = isize::BITS - x.leading_zeros(); + Evaluated::create_fixed(ret as isize, false, vec![32], vec![1]) + } else { + Evaluated::create_unknown() } + } else { + Evaluated::create_unknown() } - Evaluated::UnknownStatic => Evaluated::UnknownStatic, - _ => Evaluated::Unknown, - }, - Evaluated::UnknownStatic => Evaluated::UnknownStatic, - _ => Evaluated::Unknown, + } + _ => Evaluated::create_unknown(), } } + fn do_concatenation(&mut self, mut x: Evaluated, mut y: Evaluated) -> Evaluated { + let mut ret = match ( + x.get_value(), + y.get_value(), + x.get_total_width(), + y.get_total_width(), + ) { + (Some(value0), Some(value1), Some(width0), Some(width1)) => { + let width = width0 + width1; + let value = (value0 << width1) | value1; + Evaluated::create_fixed(value, false, vec![width], vec![1]) + } + _ => { + if x.is_known_static() && y.is_known_static() { + Evaluated::create_unknown_static() + } else { + Evaluated::create_unknown() + } + } + }; + + ret.errors.append(&mut x.errors); + ret.errors.append(&mut y.errors); + ret + } + fn concatenation_item(&mut self, arg: &ConcatenationItem) -> Evaluated { let e = self.expression(arg.expression.as_ref()); if let Some(cio) = &arg.concatenation_item_opt { let c = self.expression(cio.expression.as_ref()); - self.do_concatenation(e, c) + if let EvaluatedValue::Fixed(c) = c.value { + let mut tmp = Evaluated::create_fixed(0, false, vec![0], vec![1]); + for _ in 0..c { + tmp = self.do_concatenation(tmp, e.clone()); + } + tmp + } else { + Evaluated::create_unknown() + } } else { e } @@ -761,22 +1334,20 @@ impl Evaluator { for cll in arg.concatenation_list_list.iter() { eval_vec.push(self.concatenation_list_list(cll)); } - eval_vec.reverse(); - let default_value = Evaluated::Fixed { width: 1, value: 0 }; - eval_vec - .iter() - .fold(default_value, |acc, x| self.do_concatenation(acc, *x)) + let default_value = Evaluated::create_fixed(0, false, vec![0], vec![1]); + eval_vec.iter().fold(default_value, |acc, x| { + self.do_concatenation(acc, x.clone()) + }) } fn array_literal_item_group_default_colon_expression( &mut self, arg: &ArrayLiteralItemGroupDefaulColonExpression, ) -> Evaluated { - match self.expression(arg.expression.as_ref()) { - Evaluated::Fixed { .. } => Evaluated::UnknownStatic, - Evaluated::Variable { .. } => Evaluated::Unknown, - Evaluated::UnknownStatic => unreachable!(), - _ => Evaluated::Unknown, + match self.expression(arg.expression.as_ref()).value { + EvaluatedValue::Fixed(_) => Evaluated::create_unknown_static(), + EvaluatedValue::UnknownStatic => unreachable!(), + _ => Evaluated::create_unknown(), } } @@ -817,24 +1388,30 @@ impl Evaluator { .map(|x| self.array_literal_list_list(x).is_known_static()) .fold(true, |acc, b| acc & b); if is_known_static { - Evaluated::UnknownStatic + Evaluated::create_unknown_static() } else { - Evaluated::Unknown + Evaluated::create_unknown() } } else { - Evaluated::Unknown + Evaluated::create_unknown() } } - fn if_expression(&mut self, _arg: &IfExpression) -> Evaluated { - Evaluated::Unknown + fn if_expression(&mut self, arg: &IfExpression) -> Evaluated { + let cond = self.expression(&arg.expression); + + if let EvaluatedValue::Fixed(1) = cond.value { + self.expression(&arg.expression0) + } else { + self.expression(&arg.expression1) + } } fn case_expression(&mut self, _arg: &CaseExpression) -> Evaluated { - Evaluated::Unknown + Evaluated::create_unknown() } fn switch_expression(&mut self, _arg: &SwitchExpression) -> Evaluated { - Evaluated::Unknown + Evaluated::create_unknown() } } diff --git a/crates/analyzer/src/handlers/check_clock_reset.rs b/crates/analyzer/src/handlers/check_clock_reset.rs index 484bc11d..c38f0c05 100644 --- a/crates/analyzer/src/handlers/check_clock_reset.rs +++ b/crates/analyzer/src/handlers/check_clock_reset.rs @@ -1,5 +1,5 @@ use crate::analyzer_error::AnalyzerError; -use crate::evaluator::{Evaluated, Evaluator}; +use crate::evaluator::{EvaluatedValue, Evaluator}; use crate::symbol::{SymbolKind, TypeKind}; use crate::symbol_table; use veryl_parser::veryl_grammar_trait::*; @@ -256,12 +256,11 @@ impl VerylGrammarTrait for CheckClockReset<'_> { } fn assignment(&mut self, arg: &Assignment) -> Result<(), ParolError> { - use Evaluated::*; if let HandlerPoint::Before = self.point { if self.in_if_reset { // Check to see right hand side of reset is const evaluable - match self.evaluator.expression(&arg.expression) { - UnknownStatic | Fixed { .. } => (), + match self.evaluator.expression(&arg.expression).value { + EvaluatedValue::UnknownStatic | EvaluatedValue::Fixed(_) => (), _ => { self.errors .push(AnalyzerError::invalid_reset_non_elaborative( diff --git a/crates/analyzer/src/handlers/check_enum.rs b/crates/analyzer/src/handlers/check_enum.rs index 8237d1ee..cfb65223 100644 --- a/crates/analyzer/src/handlers/check_enum.rs +++ b/crates/analyzer/src/handlers/check_enum.rs @@ -39,30 +39,34 @@ impl VerylGrammarTrait for CheckEnum<'_> { if let SymbolKind::Enum(r#enum) = enum_symbol.found.kind { if let Some(r#type) = r#enum.r#type { if let Some(width) = Evaluator::new().type_width(r#type) { - let variants = r#enum.members.len(); - if calc_width(variants - 1) > width { - let name = arg.identifier.identifier_token.to_string(); - self.errors.push(AnalyzerError::too_much_enum_variant( - &name, - variants, - width, - self.text, - &arg.identifier.as_ref().into(), - )); - } + if width.len() != 1 { + unimplemented!(); + } else { + let variants = r#enum.members.len(); + if calc_width(variants - 1) > width[0] { + let name = arg.identifier.identifier_token.to_string(); + self.errors.push(AnalyzerError::too_much_enum_variant( + &name, + variants, + width[0], + self.text, + &arg.identifier.as_ref().into(), + )); + } - for id in r#enum.members { - let member_symbol = symbol_table::get(id).unwrap(); - if let SymbolKind::EnumMember(member) = member_symbol.kind { - let member_value = member.value.value().unwrap_or(0); - if calc_width(member_value) > width { - self.errors.push(AnalyzerError::too_large_enum_variant( - &member_symbol.token.to_string(), - member_value as isize, - width, - self.text, - &member_symbol.token.into(), - )); + for id in r#enum.members { + let member_symbol = symbol_table::get(id).unwrap(); + if let SymbolKind::EnumMember(member) = member_symbol.kind { + let member_value = member.value.value().unwrap_or(0); + if calc_width(member_value) > width[0] { + self.errors.push(AnalyzerError::too_large_enum_variant( + &member_symbol.token.to_string(), + member_value as isize, + width[0], + self.text, + &member_symbol.token.into(), + )); + } } } } diff --git a/crates/analyzer/src/handlers/check_expression.rs b/crates/analyzer/src/handlers/check_expression.rs index e388e84d..52176c03 100644 --- a/crates/analyzer/src/handlers/check_expression.rs +++ b/crates/analyzer/src/handlers/check_expression.rs @@ -1,5 +1,5 @@ use crate::analyzer_error::AnalyzerError; -use crate::evaluator::{Evaluated, Evaluator}; +use crate::evaluator::{EvaluatedError, Evaluator}; use crate::symbol::{Direction, GenericBoundKind, SymbolId, SymbolKind}; use crate::symbol_table; use veryl_parser::veryl_grammar_trait::*; @@ -12,7 +12,6 @@ pub struct CheckExpression<'a> { pub errors: Vec, text: &'a str, point: HandlerPoint, - case_condition_depth: usize, evaluator: Evaluator, in_inst_declaration: bool, port_direction: Option, @@ -26,6 +25,13 @@ impl<'a> CheckExpression<'a> { ..Default::default() } } + + fn evaluated_error(&mut self, errors: &[EvaluatedError]) { + for e in errors { + self.errors + .push(AnalyzerError::evaluated_error(self.text, e)); + } + } } impl Handler for CheckExpression<'_> { @@ -55,167 +61,252 @@ fn is_defined_in_package(full_path: &[SymbolId]) -> bool { } impl VerylGrammarTrait for CheckExpression<'_> { - fn case_condition(&mut self, _arg: &CaseCondition) -> Result<(), ParolError> { - match self.point { - HandlerPoint::Before => self.case_condition_depth += 1, - HandlerPoint::After => self.case_condition_depth -= 1, - } - Ok(()) - } - - fn expression(&mut self, arg: &Expression) -> Result<(), ParolError> { - if let HandlerPoint::Before = self.point { - if self.case_condition_depth >= 1 { - let result = matches!(self.evaluator.expression(arg), Evaluated::Variable { .. }); - if result { - self.errors - .push(AnalyzerError::invalid_case_condition_non_elaborative( - self.text, - &arg.into(), - )); - } - } - } - Ok(()) - } - fn identifier_factor(&mut self, arg: &IdentifierFactor) -> Result<(), ParolError> { if let HandlerPoint::Before = self.point { let expid = arg.expression_identifier.as_ref(); if let Ok(rr) = symbol_table::resolve(expid) { - let identifier = rr.found.token.to_string(); - let token: TokenRange = arg.expression_identifier.as_ref().into(); - let kind_name = rr.found.kind.to_kind_name(); - - // Closure to delay AnalyzerError constructor to actual error - let error = - || AnalyzerError::invalid_factor(&identifier, &kind_name, self.text, &token); - - match rr.found.kind { - SymbolKind::Function(_) | SymbolKind::ModportFunctionMember(_) => { - if arg.identifier_factor_opt.is_none() { - self.errors.push(error()); - } - } - SymbolKind::SystemFunction => { - if arg.identifier_factor_opt.is_none() { - self.errors.push(error()); - } - } - // instance can be used as factor in inst_declaration - SymbolKind::Instance(_) if self.in_inst_declaration => (), - SymbolKind::Module(_) - | SymbolKind::ProtoModule(_) - | SymbolKind::Interface(_) - | SymbolKind::Instance(_) - | SymbolKind::Block - | SymbolKind::Package(_) - | SymbolKind::Modport(_) - | SymbolKind::Namespace - | SymbolKind::ClockDomain - | SymbolKind::Test(_) => { - self.errors.push(error()); - } - SymbolKind::Port(x) => { - if !self.in_inst_declaration { - match x.direction { - Direction::Interface | Direction::Modport => { - // modport and interface direction can be used as factor in inst_declaration - self.errors.push(error()); - } - _ => {} - } - } else if self.in_input_port_default_value { - // port cannot be used for port default value - self.errors.push(error()); - } - } - SymbolKind::Parameter(_) - | SymbolKind::EnumMember(_) - | SymbolKind::StructMember(_) - | SymbolKind::UnionMember(_) - if self.in_input_port_default_value => - { - if !is_defined_in_package(&rr.full_path) { - self.errors.push(error()); - } - } - SymbolKind::GenericParameter(x) if self.in_input_port_default_value => { - if !matches!(x.bound, GenericBoundKind::Const) { - self.errors.push(error()); - } - } - _ if self.in_input_port_default_value => { - self.errors.push(error()); - } - _ => {} - } - } - - if arg.identifier_factor_opt.is_some() { - // Must be a function call - let expid = arg.expression_identifier.as_ref(); - if let Ok(rr) = symbol_table::resolve(expid) { - let is_function = match &rr.found.kind { - SymbolKind::Function(_) - | SymbolKind::SystemVerilog - | SymbolKind::ModportFunctionMember(..) - | SymbolKind::SystemFunction => true, - SymbolKind::GenericInstance(x) => { - let base = symbol_table::get(x.base).unwrap(); - matches!( - base.kind, - SymbolKind::Function(_) - | SymbolKind::SystemVerilog - | SymbolKind::ModportFunctionMember(..) - | SymbolKind::SystemFunction - ) + // Only generic const or globally visible identifier can be used as port default value + if self.in_input_port_default_value { + let port_default_available = match &rr.found.kind { + SymbolKind::SystemFunction => true, + SymbolKind::GenericParameter(x) => { + matches!(x.bound, GenericBoundKind::Const) } - _ => false, + _ => is_defined_in_package(&rr.full_path), }; - if !is_function { + if !port_default_available { let identifier = rr.found.token.to_string(); let token: TokenRange = arg.expression_identifier.as_ref().into(); - self.errors.push(AnalyzerError::call_non_function( + let kind_name = rr.found.kind.to_kind_name(); + + self.errors.push(AnalyzerError::invalid_factor( &identifier, - &rr.found.kind.to_kind_name(), + &kind_name, self.text, &token, )); - } else if self.in_input_port_default_value - && !is_defined_in_package(&rr.full_path) - { - self.errors.push(AnalyzerError::invalid_factor( - &rr.found.token.to_string(), - &rr.found.kind.to_kind_name(), + } + } + } + } + Ok(()) + } + + fn let_statement(&mut self, arg: &LetStatement) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + Ok(()) + } + + fn identifier_statement(&mut self, arg: &IdentifierStatement) -> Result<(), ParolError> { + match arg.identifier_statement_group.as_ref() { + IdentifierStatementGroup::FunctionCall(_) => { + // TODO function check + } + IdentifierStatementGroup::Assignment(x) => { + let exp = self.evaluator.expression(&x.assignment.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + } + } + Ok(()) + } + + fn if_statement(&mut self, arg: &IfStatement) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + for x in &arg.if_statement_list { + let exp = self.evaluator.expression(&x.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + } + + Ok(()) + } + + fn if_reset_statement(&mut self, arg: &IfResetStatement) -> Result<(), ParolError> { + for x in &arg.if_reset_statement_list { + let exp = self.evaluator.expression(&x.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + } + + Ok(()) + } + + fn return_statement(&mut self, arg: &ReturnStatement) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + Ok(()) + } + + fn for_statement(&mut self, arg: &ForStatement) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.range.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + if let Some(x) = &arg.range.range_opt { + let exp = self.evaluator.expression(&x.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + } + + if let Some(x) = &arg.for_statement_opt { + let exp = self.evaluator.expression(&x.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + } + + Ok(()) + } + + fn case_statement(&mut self, arg: &CaseStatement) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.expression); + self.evaluated_error(&exp.errors); + + Ok(()) + } + + fn case_condition(&mut self, arg: &CaseCondition) -> Result<(), ParolError> { + let range_items: Vec = arg.into(); + + for x in range_items { + let exp = self.evaluator.expression(&x.range.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + if !exp.is_known_static() { + self.errors + .push(AnalyzerError::invalid_case_condition_non_elaborative( + self.text, + &x.range.expression.as_ref().into(), + )); + } + + if let Some(x) = &x.range.range_opt { + let exp = self.evaluator.expression(&x.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + if !exp.is_known_static() { + self.errors + .push(AnalyzerError::invalid_case_condition_non_elaborative( self.text, - &arg.expression_identifier.as_ref().into(), + &x.expression.as_ref().into(), )); - } } } } + + Ok(()) + } + + fn switch_condition(&mut self, arg: &SwitchCondition) -> Result<(), ParolError> { + let expressions: Vec = arg.into(); + + for x in expressions { + let exp = self.evaluator.expression(&x); + self.evaluated_error(&exp.errors); + + // TODO type check + } + + Ok(()) + } + + fn let_declaration(&mut self, arg: &LetDeclaration) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + Ok(()) + } + + fn const_declaration(&mut self, arg: &ConstDeclaration) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + Ok(()) + } + + fn assign_declaration(&mut self, arg: &AssignDeclaration) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + Ok(()) + } + + fn enum_item(&mut self, arg: &EnumItem) -> Result<(), ParolError> { + if let Some(x) = &arg.enum_item_opt { + let exp = self.evaluator.expression(&x.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + } Ok(()) } fn inst_declaration(&mut self, _arg: &InstDeclaration) -> Result<(), ParolError> { match self.point { - HandlerPoint::Before => self.in_inst_declaration = true, + HandlerPoint::Before => { + self.in_inst_declaration = true; + + // TODO check port connection + } HandlerPoint::After => self.in_inst_declaration = false, } Ok(()) } + fn with_parameter_item(&mut self, arg: &WithParameterItem) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + Ok(()) + } + fn port_type_concrete(&mut self, arg: &PortTypeConcrete) -> Result<(), ParolError> { match self.point { - HandlerPoint::Before => self.port_direction = Some(arg.direction.as_ref().into()), + HandlerPoint::Before => { + self.port_direction = Some(arg.direction.as_ref().into()); + + if let Some(x) = &arg.port_type_concrete_opt0 { + let exp = self.evaluator.expression(&x.port_default_value.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + } + } HandlerPoint::After => self.port_direction = None, } Ok(()) } - /// Semantic action for non-terminal 'PortDefaultValue' fn port_default_value(&mut self, _arg: &PortDefaultValue) -> Result<(), ParolError> { match self.point { HandlerPoint::Before => { @@ -226,4 +317,43 @@ impl VerylGrammarTrait for CheckExpression<'_> { } Ok(()) } + + fn generate_if_declaration(&mut self, arg: &GenerateIfDeclaration) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + for x in &arg.generate_if_declaration_list { + let exp = self.evaluator.expression(&x.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + } + + Ok(()) + } + + fn generate_for_declaration(&mut self, arg: &GenerateForDeclaration) -> Result<(), ParolError> { + let exp = self.evaluator.expression(&arg.range.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + + if let Some(x) = &arg.range.range_opt { + let exp = self.evaluator.expression(&x.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + } + + if let Some(x) = &arg.generate_for_declaration_opt { + let exp = self.evaluator.expression(&x.expression); + self.evaluated_error(&exp.errors); + + // TODO type check + } + + Ok(()) + } } diff --git a/crates/analyzer/src/handlers/create_symbol_table.rs b/crates/analyzer/src/handlers/create_symbol_table.rs index ff02b3c1..4bf06730 100644 --- a/crates/analyzer/src/handlers/create_symbol_table.rs +++ b/crates/analyzer/src/handlers/create_symbol_table.rs @@ -2,8 +2,7 @@ use crate::analyzer_error::AnalyzerError; use crate::attribute::Attribute as Attr; use crate::attribute::{AllowItem, EnumEncodingItem}; use crate::attribute_table; -use crate::evaluator::Evaluated; -use crate::evaluator::Evaluator; +use crate::evaluator::{EvaluatedValue, Evaluator}; use crate::namespace::Namespace; use crate::namespace_table; use crate::symbol::ClockDomain as SymClockDomain; @@ -300,7 +299,7 @@ impl<'a> CreateSymbolTable<'a> { fn evaluate_enum_value(&mut self, arg: &EnumItem) -> EnumMemberValue { if let Some(ref x) = arg.enum_item_opt { let evaluated = Evaluator::new().expression(&x.expression); - if let Evaluated::Fixed { value, .. } = evaluated { + if let EvaluatedValue::Fixed(value) = evaluated.value { let valid_variant = match self.enum_encoding { EnumEncodingItem::OneHot => value.count_ones() == 1, EnumEncodingItem::Gray => { @@ -741,7 +740,11 @@ impl VerylGrammarTrait for CreateSymbolTable<'_> { .as_ref() .map(|x| x.scalar_type.as_ref().into()); let width = if let Some(x) = r#type.clone() { - Evaluator::new().type_width(x).unwrap_or(0) + if let Some(x) = Evaluator::new().type_width(x) { + *x.first().unwrap_or(&0) + } else { + 0 + } } else { calc_width(members.len() - 1).max(self.enum_member_width) }; diff --git a/crates/analyzer/src/namespace.rs b/crates/analyzer/src/namespace.rs index f22d334d..5d902489 100644 --- a/crates/analyzer/src/namespace.rs +++ b/crates/analyzer/src/namespace.rs @@ -106,3 +106,13 @@ impl From<&[StrId]> for Namespace { } } } + +impl From<&str> for Namespace { + fn from(value: &str) -> Self { + let mut paths = Vec::new(); + for x in value.split("::") { + paths.push(x.into()); + } + Namespace { paths } + } +} diff --git a/crates/analyzer/src/symbol.rs b/crates/analyzer/src/symbol.rs index bfb3f6c1..a2f0ec0a 100644 --- a/crates/analyzer/src/symbol.rs +++ b/crates/analyzer/src/symbol.rs @@ -1,9 +1,11 @@ use crate::attribute::EnumEncodingItem; -use crate::evaluator::{Evaluated, Evaluator}; +use crate::evaluator::{ + Evaluated, EvaluatedError, EvaluatedTypeClockKind, EvaluatedTypeResetKind, Evaluator, +}; use crate::namespace::Namespace; use crate::symbol_path::{GenericSymbolPath, SymbolPath}; use crate::symbol_table; -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; use std::collections::HashMap; use std::fmt; use veryl_parser::resource_table::{PathId, StrId}; @@ -68,7 +70,7 @@ pub struct Symbol { pub references: Vec, pub generic_instances: Vec, pub imported: Vec, - pub evaluated: Cell>, + pub evaluated: RefCell>, pub allow_unused: bool, pub public: bool, pub doc_comment: DocComment, @@ -90,7 +92,7 @@ impl Symbol { references: Vec::new(), generic_instances: Vec::new(), imported: Vec::new(), - evaluated: Cell::new(None), + evaluated: RefCell::new(None), allow_unused: false, public, doc_comment, @@ -112,66 +114,115 @@ impl Symbol { } pub fn evaluate(&self) -> Evaluated { - if let Some(evaluated) = self.evaluated.get() { - evaluated + if self.evaluated.borrow().is_some() { + self.evaluated.borrow().clone().unwrap() } else { let evaluated = match &self.kind { SymbolKind::Variable(x) => { let mut evaluator = Evaluator::new(); - if x.r#type.kind.is_clock() | x.r#type.kind.is_reset() { - match x.r#type.kind { - TypeKind::Clock => Evaluated::Clock, - TypeKind::ClockPosedge => Evaluated::ClockPosedge, - TypeKind::ClockNegedge => Evaluated::ClockNegedge, - TypeKind::Reset => Evaluated::Reset, - TypeKind::ResetAsyncHigh => Evaluated::ResetAsyncHigh, - TypeKind::ResetAsyncLow => Evaluated::ResetAsyncLow, - TypeKind::ResetSyncHigh => Evaluated::ResetSyncHigh, - TypeKind::ResetSyncLow => Evaluated::ResetSyncLow, - _ => unreachable!(), - } - } else if let Some(width) = evaluator.type_width(x.r#type.clone()) { - if x.loop_variable { - Evaluated::UnknownStatic + let width = evaluator.type_width(x.r#type.clone()); + let array = evaluator.type_width(x.r#type.clone()); + + if let (Some(width), Some(array)) = (width, array) { + if x.r#type.kind.is_clock() { + let kind = match x.r#type.kind { + TypeKind::Clock => EvaluatedTypeClockKind::Implicit, + TypeKind::ClockPosedge => EvaluatedTypeClockKind::Posedge, + TypeKind::ClockNegedge => EvaluatedTypeClockKind::Negedge, + _ => unreachable!(), + }; + Evaluated::create_clock(kind, width, array) + } else if x.r#type.kind.is_reset() { + let kind = match x.r#type.kind { + TypeKind::Reset => EvaluatedTypeResetKind::Implicit, + TypeKind::ResetAsyncHigh => EvaluatedTypeResetKind::AsyncHigh, + TypeKind::ResetAsyncLow => EvaluatedTypeResetKind::AsyncLow, + TypeKind::ResetSyncHigh => EvaluatedTypeResetKind::SyncHigh, + TypeKind::ResetSyncLow => EvaluatedTypeResetKind::SyncLow, + _ => unreachable!(), + }; + Evaluated::create_reset(kind, width, array) + } else if x.loop_variable { + Evaluated::create_unknown_static() } else { - Evaluated::Variable { width } + let signed = x.r#type.modifier.contains(&TypeModifier::Signed); + Evaluated::create_variable(signed, width, array) } } else { - Evaluated::Unknown + Evaluated::create_unknown() } } SymbolKind::Port(x) => { if let Some(x) = &x.r#type { - match x.kind { - TypeKind::Clock => Evaluated::Clock, - TypeKind::ClockPosedge => Evaluated::ClockPosedge, - TypeKind::ClockNegedge => Evaluated::ClockNegedge, - TypeKind::Reset => Evaluated::Reset, - TypeKind::ResetAsyncHigh => Evaluated::ResetAsyncHigh, - TypeKind::ResetAsyncLow => Evaluated::ResetAsyncLow, - TypeKind::ResetSyncHigh => Evaluated::ResetSyncHigh, - TypeKind::ResetSyncLow => Evaluated::ResetSyncLow, - _ => Evaluated::Unknown, + let mut evaluator = Evaluator::new(); + let width = evaluator.type_width(x.clone()); + let array = evaluator.type_width(x.clone()); + + if let (Some(width), Some(array)) = (width, array) { + if x.kind.is_clock() { + let kind = match x.kind { + TypeKind::Clock => EvaluatedTypeClockKind::Implicit, + TypeKind::ClockPosedge => EvaluatedTypeClockKind::Posedge, + TypeKind::ClockNegedge => EvaluatedTypeClockKind::Negedge, + _ => unreachable!(), + }; + Evaluated::create_clock(kind, width, array) + } else if x.kind.is_reset() { + let kind = match x.kind { + TypeKind::Reset => EvaluatedTypeResetKind::Implicit, + TypeKind::ResetAsyncHigh => EvaluatedTypeResetKind::AsyncHigh, + TypeKind::ResetAsyncLow => EvaluatedTypeResetKind::AsyncLow, + TypeKind::ResetSyncHigh => EvaluatedTypeResetKind::SyncHigh, + TypeKind::ResetSyncLow => EvaluatedTypeResetKind::SyncLow, + _ => unreachable!(), + }; + Evaluated::create_reset(kind, width, array) + } else { + let signed = x.modifier.contains(&TypeModifier::Signed); + Evaluated::create_variable(signed, width, array) + } + } else { + Evaluated::create_unknown() } } else { - Evaluated::Unknown + Evaluated::create_unknown() } } SymbolKind::Parameter(x) => { let mut evaluator = Evaluator::new(); if let Some(width) = evaluator.type_width(x.r#type.clone()) { - evaluator.context_width.push(width); + evaluator.context_width = width; } evaluator.expression(&x.value) } SymbolKind::EnumMember(_) => { // TODO: Actually Evaluate its Width - Evaluated::UnknownStatic + Evaluated::create_unknown_static() } - SymbolKind::Genvar => Evaluated::UnknownStatic, - _ => Evaluated::Unknown, + SymbolKind::Genvar => Evaluated::create_unknown_static(), + SymbolKind::Module(_) + | SymbolKind::ProtoModule(_) + | SymbolKind::Interface(_) + | SymbolKind::Function(_) + | SymbolKind::Block + | SymbolKind::Package(_) + | SymbolKind::Modport(_) + | SymbolKind::ModportFunctionMember(_) + | SymbolKind::Namespace + | SymbolKind::SystemFunction + | SymbolKind::GenericInstance(_) + | SymbolKind::ClockDomain + | SymbolKind::Test(_) => { + let mut ret = Evaluated::create_unknown(); + ret.errors.push(EvaluatedError::InvalidFactor { + kind: self.kind.to_kind_name(), + token: self.token, + }); + ret + } + _ => Evaluated::create_unknown(), }; - self.evaluated.replace(Some(evaluated)); + self.evaluated.replace(Some(evaluated.clone())); evaluated } } @@ -427,6 +478,26 @@ impl SymbolKind { } } + pub fn is_function(&self) -> bool { + match self { + SymbolKind::Function(_) + | SymbolKind::SystemVerilog + | SymbolKind::ModportFunctionMember(..) + | SymbolKind::SystemFunction => true, + SymbolKind::GenericInstance(x) => { + let base = symbol_table::get(x.base).unwrap(); + matches!( + base.kind, + SymbolKind::Function(_) + | SymbolKind::SystemVerilog + | SymbolKind::ModportFunctionMember(..) + | SymbolKind::SystemFunction + ) + } + _ => false, + } + } + pub fn get_type(&self) -> Option<&Type> { match self { SymbolKind::Port(x) => x.r#type.as_ref(), diff --git a/crates/analyzer/src/symbol_path.rs b/crates/analyzer/src/symbol_path.rs index 763719d2..361d0532 100644 --- a/crates/analyzer/src/symbol_path.rs +++ b/crates/analyzer/src/symbol_path.rs @@ -109,6 +109,16 @@ impl From<&syntax_tree::ExpressionIdentifier> for SymbolPath { } } +impl From<&str> for SymbolPath { + fn from(value: &str) -> Self { + let mut path = Vec::new(); + for x in value.split("::") { + path.push(x.into()); + } + SymbolPath(path) + } +} + #[derive(Clone, Default, Debug, PartialEq, Eq)] pub struct SymbolPathNamespace(pub SymbolPath, pub Namespace); diff --git a/crates/analyzer/src/symbol_table.rs b/crates/analyzer/src/symbol_table.rs index 38c58de8..b04e9251 100644 --- a/crates/analyzer/src/symbol_table.rs +++ b/crates/analyzer/src/symbol_table.rs @@ -1,4 +1,4 @@ -use crate::evaluator::Evaluated; +use crate::evaluator::EvaluatedValue; use crate::namespace::Namespace; use crate::symbol::{DocComment, GenericBoundKind, Symbol, SymbolId, SymbolKind, TypeKind}; use crate::symbol_path::{SymbolPath, SymbolPathNamespace}; @@ -537,9 +537,9 @@ impl fmt::Display for SymbolTable { for (k, v) in &vec { for id in *v { let symbol = self.symbol_table.get(id).unwrap(); - let evaluated = if let Some(evaluated) = symbol.evaluated.get() { - match evaluated { - Evaluated::Unknown => "".to_string(), + let evaluated = if let Some(evaluated) = symbol.evaluated.borrow().as_ref() { + match evaluated.value { + EvaluatedValue::Unknown => "".to_string(), _ => format!(" ( {evaluated:?} )"), } } else { diff --git a/crates/analyzer/src/tests.rs b/crates/analyzer/src/tests.rs index dc94737d..6d69c104 100644 --- a/crates/analyzer/src/tests.rs +++ b/crates/analyzer/src/tests.rs @@ -1,3 +1,5 @@ +use crate::namespace::Namespace; +use crate::symbol_path::SymbolPath; use crate::{symbol_table, Analyzer, AnalyzerError}; use veryl_metadata::Metadata; use veryl_parser::Parser; @@ -1198,7 +1200,7 @@ fn mismatch_type() { "#; let errors = analyze(code); - assert!(matches!(errors[0], AnalyzerError::MismatchType { .. })); + assert!(matches!(errors[0], AnalyzerError::InvalidFactor { .. })); let code = r#" interface InterfaceA { @@ -2602,25 +2604,34 @@ fn invalid_factor_kind() { assert!(matches!(errors[0], AnalyzerError::InvalidFactor { .. })); let code = r#" - interface InterfaceA { - var a: logic; - modport master { - a: input, - } - } - module ModuleA ( - b: modport InterfaceA::master, - ) { - var a: logic; - always_comb { - a = b; - } - } - "#; + module ModuleA { + let a: logic = $clog2; + }"#; let errors = analyze(code); assert!(matches!(errors[0], AnalyzerError::InvalidFactor { .. })); + //TODO this case should be detected as type mismatch + //let code = r#" + //interface InterfaceA { + // var a: logic; + // modport master { + // a: input, + // } + //} + //module ModuleA ( + // b: modport InterfaceA::master, + //) { + // var a: logic; + // always_comb { + // a = b; + // } + //} + //"#; + // + //let errors = analyze(code); + //assert!(matches!(errors[0], AnalyzerError::InvalidFactor { .. })); + let code = r#" module ModuleA #( param A: bit = 0 @@ -2632,6 +2643,25 @@ fn invalid_factor_kind() { let errors = analyze(code); assert!(matches!(errors[0], AnalyzerError::InvalidFactor { .. })); + let code = r#" + module ModuleA { + let a: logic = ModuleA; + } + "#; + + let errors = analyze(code); + assert!(matches!(errors[0], AnalyzerError::InvalidFactor { .. })); + + let code = r#" + module ModuleA ( + a: input logic, + b: input logic = a, + ) {} + "#; + + let errors = analyze(code); + assert!(matches!(errors[0], AnalyzerError::InvalidFactor { .. })); + let code = r#" package PackageA { const A: bit = 0; @@ -3308,3 +3338,62 @@ fn wrong_seperator() { let errors = analyze(code); assert!(matches!(errors[0], AnalyzerError::WrongSeparator { .. })); } + +#[test] +fn evaluator() { + let code = r#" + module ModuleA { + const A: u32 = 0; + const B: u32 = 1 + 2 - 3 + 4 * 3 / 2; + const C: u32 = 2 ** 2 + 5 % 2 + (1 << 3) + (16 >> 3); + const D: u32 = (1 >: 0) + (1 >= 1) + (3 <: 5) + (10 <= 10) + (3 == 3) + (5 != 2); + const E: u32 = (1 && 1) + (1 || 0) + (1 & 1) + (1 | 0) + (1 ^ 0) + ~(1 ^~ 0); + const F: u32 = &4'hf + |4'h1 + ~&4'h1 + ~|4'h0 + ^4'h8 + ~^4'h6; + const G: u32 = A + B + C + D + E + F; + const H: u32 = {1'b1, 2'h1, 2'd2 repeat 3}; + const I: u32 = if B == 6 { 10 } else { 20 }; + const J: u32 = $clog2(12); + const K: u32 = B[2:1]; + } + "#; + + let _ = analyze(code); + + let namespace: Namespace = "prj::ModuleA".into(); + + let a = symbol_table::resolve((&Into::::into("A"), &namespace)).unwrap(); + let b = symbol_table::resolve((&Into::::into("B"), &namespace)).unwrap(); + let c = symbol_table::resolve((&Into::::into("C"), &namespace)).unwrap(); + let d = symbol_table::resolve((&Into::::into("D"), &namespace)).unwrap(); + let e = symbol_table::resolve((&Into::::into("E"), &namespace)).unwrap(); + let f = symbol_table::resolve((&Into::::into("F"), &namespace)).unwrap(); + let g = symbol_table::resolve((&Into::::into("G"), &namespace)).unwrap(); + let h = symbol_table::resolve((&Into::::into("H"), &namespace)).unwrap(); + let i = symbol_table::resolve((&Into::::into("I"), &namespace)).unwrap(); + let j = symbol_table::resolve((&Into::::into("J"), &namespace)).unwrap(); + let k = symbol_table::resolve((&Into::::into("K"), &namespace)).unwrap(); + + let a = a.found.evaluate(); + let b = b.found.evaluate(); + let c = c.found.evaluate(); + let d = d.found.evaluate(); + let e = e.found.evaluate(); + let f = f.found.evaluate(); + let g = g.found.evaluate(); + let h = h.found.evaluate(); + let i = i.found.evaluate(); + let j = j.found.evaluate(); + let k = k.found.evaluate(); + + assert_eq!((a.get_value(), a.get_total_width()), (Some(0), Some(32))); + assert_eq!((b.get_value(), b.get_total_width()), (Some(6), Some(32))); + assert_eq!((c.get_value(), c.get_total_width()), (Some(15), Some(32))); + assert_eq!((d.get_value(), d.get_total_width()), (Some(6), Some(32))); + assert_eq!((e.get_value(), e.get_total_width()), (Some(6), Some(32))); + assert_eq!((f.get_value(), f.get_total_width()), (Some(6), Some(32))); + assert_eq!((g.get_value(), g.get_total_width()), (Some(39), Some(32))); + assert_eq!((h.get_value(), h.get_total_width()), (Some(362), Some(9))); + assert_eq!((i.get_value(), i.get_total_width()), (Some(10), Some(32))); + assert_eq!((j.get_value(), j.get_total_width()), (Some(4), Some(32))); + assert_eq!((k.get_value(), k.get_total_width()), (Some(3), Some(2))); +} diff --git a/crates/analyzer/src/var_ref.rs b/crates/analyzer/src/var_ref.rs index 4685fdba..da57d9aa 100644 --- a/crates/analyzer/src/var_ref.rs +++ b/crates/analyzer/src/var_ref.rs @@ -1,4 +1,4 @@ -use crate::evaluator::{Evaluated, Evaluator}; +use crate::evaluator::{Evaluated, EvaluatedValue, Evaluator}; use crate::namespace::Namespace; use crate::symbol::{ConnectTarget, SymbolId}; use crate::symbol_table; @@ -75,7 +75,7 @@ impl VarRefAffiliation { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Debug)] pub enum VarRefPathItem { Identifier { symbol_id: SymbolId, @@ -119,35 +119,32 @@ impl VarRefPathItem { fn select_range(&self, x: &VarRefPathItem) -> Option> { match x { - VarRefPathItem::SelectSingle { - index: Evaluated::Fixed { value: index, .. }, - } => Some(*index..=*index), - VarRefPathItem::SelectColon { msb, lsb } => match (msb, lsb) { - (Evaluated::Fixed { value: msb, .. }, Evaluated::Fixed { value: lsb, .. }) => { - Some(*lsb..=*msb) - } + VarRefPathItem::SelectSingle { index } => match index.value { + EvaluatedValue::Fixed(x) => Some(x..=x), _ => None, }, - VarRefPathItem::SelectPlusClon { position, width } => match (position, width) { - ( - Evaluated::Fixed { - value: position, .. - }, - Evaluated::Fixed { value: width, .. }, - ) => Some(*position..=position + width - 1), + VarRefPathItem::SelectColon { msb, lsb } => match (&msb.value, &lsb.value) { + (EvaluatedValue::Fixed(msb), EvaluatedValue::Fixed(lsb)) => Some(*lsb..=*msb), _ => None, }, - VarRefPathItem::SelectMinusColon { position, width } => match (position, width) { - ( - Evaluated::Fixed { - value: position, .. - }, - Evaluated::Fixed { value: width, .. }, - ) => Some(position - width + 1..=*position), - _ => None, - }, - VarRefPathItem::SelectStep { index, step } => match (index, step) { - (Evaluated::Fixed { value: index, .. }, Evaluated::Fixed { value: step, .. }) => { + VarRefPathItem::SelectPlusClon { position, width } => { + match (&position.value, &width.value) { + (EvaluatedValue::Fixed(position), EvaluatedValue::Fixed(width)) => { + Some(*position..=position + width - 1) + } + _ => None, + } + } + VarRefPathItem::SelectMinusColon { position, width } => { + match (&position.value, &width.value) { + (EvaluatedValue::Fixed(position), EvaluatedValue::Fixed(width)) => { + Some(position - width + 1..=*position) + } + _ => None, + } + } + VarRefPathItem::SelectStep { index, step } => match (&index.value, &step.value) { + (EvaluatedValue::Fixed(index), EvaluatedValue::Fixed(step)) => { Some(step * index..=step * (index + 1) - 1) } _ => None, @@ -212,42 +209,36 @@ impl fmt::Display for VarRefPathItem { } } VarRefPathItem::SelectSingle { index } => { - if let Evaluated::Fixed { value: index, .. } = index { + if let EvaluatedValue::Fixed(index) = index.value { format!("[{}]", index) } else { "[]".to_string() } } - VarRefPathItem::SelectColon { msb, lsb } => match (msb, lsb) { - (Evaluated::Fixed { value: msb, .. }, Evaluated::Fixed { value: lsb, .. }) => { + VarRefPathItem::SelectColon { msb, lsb } => match (&msb.value, &lsb.value) { + (EvaluatedValue::Fixed(msb), EvaluatedValue::Fixed(lsb)) => { format!("[{}:{}]", msb, lsb) } _ => "[]".to_string(), }, - VarRefPathItem::SelectPlusClon { position, width } => match (position, width) { - ( - Evaluated::Fixed { - value: position, .. - }, - Evaluated::Fixed { value: width, .. }, - ) => { - format!("[{}+:{}]", position, width) + VarRefPathItem::SelectPlusClon { position, width } => { + match (&position.value, &width.value) { + (EvaluatedValue::Fixed(position), EvaluatedValue::Fixed(width)) => { + format!("[{}+:{}]", position, width) + } + _ => "[]".to_string(), } - _ => "[]".to_string(), - }, - VarRefPathItem::SelectMinusColon { position, width } => match (position, width) { - ( - Evaluated::Fixed { - value: position, .. - }, - Evaluated::Fixed { value: width, .. }, - ) => { - format!("[{}-:{}]", position, width) + } + VarRefPathItem::SelectMinusColon { position, width } => { + match (&position.value, &width.value) { + (EvaluatedValue::Fixed(position), EvaluatedValue::Fixed(width)) => { + format!("[{}-:{}]", position, width) + } + _ => "[]".to_string(), } - _ => "[]".to_string(), - }, - VarRefPathItem::SelectStep { index, step } => match (index, step) { - (Evaluated::Fixed { value: index, .. }, Evaluated::Fixed { value: step, .. }) => { + } + VarRefPathItem::SelectStep { index, step } => match (&index.value, &step.value) { + (EvaluatedValue::Fixed(index), EvaluatedValue::Fixed(step)) => { format!("[{} step {}]", index, step) } _ => "[]".to_string(), diff --git a/crates/emitter/src/emitter.rs b/crates/emitter/src/emitter.rs index a25c2e5b..d176f186 100644 --- a/crates/emitter/src/emitter.rs +++ b/crates/emitter/src/emitter.rs @@ -4,7 +4,7 @@ use veryl_aligner::{align_kind, Aligner, Location}; use veryl_analyzer::attribute::Attribute as Attr; use veryl_analyzer::attribute::{AllowItem, CondTypeItem, EnumEncodingItem}; use veryl_analyzer::attribute_table; -use veryl_analyzer::evaluator::{Evaluated, Evaluator}; +use veryl_analyzer::evaluator::{EvaluatedTypeResetKind, Evaluator}; use veryl_analyzer::namespace::Namespace; use veryl_analyzer::symbol::TypeModifier as SymTypeModifier; use veryl_analyzer::symbol::{ @@ -1518,17 +1518,26 @@ impl VerylWalker for Emitter { let dst = x.casting_type.as_ref(); let reset_type = self.build_opt.reset_type; + let src_kind = &src.get_reset_kind(); + let src_is_high = - matches!((src, reset_type), (Evaluated::Reset, ResetType::AsyncHigh)) - | matches!((src, reset_type), (Evaluated::Reset, ResetType::SyncHigh)) - | matches!(src, Evaluated::ResetAsyncHigh) - | matches!(src, Evaluated::ResetSyncHigh); - - let src_is_low = - matches!((src, reset_type), (Evaluated::Reset, ResetType::AsyncLow)) - | matches!((src, reset_type), (Evaluated::Reset, ResetType::SyncLow)) - | matches!(src, Evaluated::ResetAsyncLow) - | matches!(src, Evaluated::ResetSyncLow); + matches!( + (src_kind, reset_type), + (Some(EvaluatedTypeResetKind::Implicit), ResetType::AsyncHigh) + ) | matches!( + (src_kind, reset_type), + (Some(EvaluatedTypeResetKind::Implicit), ResetType::SyncHigh) + ) | matches!(src_kind, Some(EvaluatedTypeResetKind::AsyncHigh)) + | matches!(src_kind, Some(EvaluatedTypeResetKind::SyncHigh)); + + let src_is_low = matches!( + (src_kind, reset_type), + (Some(EvaluatedTypeResetKind::Implicit), ResetType::AsyncLow) + ) | matches!( + (src_kind, reset_type), + (Some(EvaluatedTypeResetKind::Implicit), ResetType::SyncLow) + ) | matches!(src_kind, Some(EvaluatedTypeResetKind::AsyncLow)) + | matches!(src_kind, Some(EvaluatedTypeResetKind::SyncLow)); let dst_is_high = matches!( (dst, reset_type), diff --git a/crates/parser/src/veryl_grammar_trait.rs b/crates/parser/src/veryl_grammar_trait.rs index b914ce7a..71a75c3d 100644 --- a/crates/parser/src/veryl_grammar_trait.rs +++ b/crates/parser/src/veryl_grammar_trait.rs @@ -109,6 +109,32 @@ impl From<&ScopedIdentifier> for Vec> { } } +impl From<&CaseCondition> for Vec { + fn from(value: &CaseCondition) -> Self { + let mut ret = Vec::new(); + ret.push(value.range_item.as_ref().clone()); + + for x in &value.case_condition_list { + ret.push(x.range_item.as_ref().clone()); + } + + ret + } +} + +impl From<&SwitchCondition> for Vec { + fn from(value: &SwitchCondition) -> Self { + let mut ret = Vec::new(); + ret.push(value.expression.as_ref().clone()); + + for x in &value.switch_condition_list { + ret.push(x.expression.as_ref().clone()); + } + + ret + } +} + list_group_to_item!(Modport); list_group_to_item!(Enum); list_group_to_item!(StructUnion); @@ -119,6 +145,7 @@ list_group_to_item!(PortDeclaration); list_to_item!(WithGenericParameter); list_to_item!(WithGenericArgument); list_to_item!(Attribute); +list_to_item!(Argument); group_to_item!(Module); group_to_item!(Interface); group_to_item!(Generate); diff --git a/crates/std/veryl/src/counter/counter.veryl b/crates/std/veryl/src/counter/counter.veryl index cf094c22..49b46348 100644 --- a/crates/std/veryl/src/counter/counter.veryl +++ b/crates/std/veryl/src/counter/counter.veryl @@ -63,7 +63,7 @@ pub module counter #( down : input logic, current_count: input COUNT, ) -> COUNT { - case 1'b1 { + switch { clear : return INITIAL_COUNT; set : return set_value; (up && (!down)): return count_up(current_count);