Skip to content

Commit

Permalink
Introduce new type checker
Browse files Browse the repository at this point in the history
  • Loading branch information
dalance committed Jan 31, 2025
1 parent 2392b37 commit a5aca8d
Show file tree
Hide file tree
Showing 14 changed files with 882 additions and 398 deletions.
884 changes: 626 additions & 258 deletions crates/analyzer/src/evaluator.rs

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions crates/analyzer/src/handlers/check_clock_reset.rs
Original file line number Diff line number Diff line change
@@ -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::*;
Expand Down Expand Up @@ -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(
Expand Down
50 changes: 27 additions & 23 deletions crates/analyzer/src/handlers/check_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
));
}
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions crates/analyzer/src/handlers/check_expression.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::analyzer_error::AnalyzerError;
use crate::evaluator::{Evaluated, Evaluator};
use crate::evaluator::{EvaluatedValue, Evaluator};
use crate::symbol::{Direction, GenericBoundKind, SymbolId, SymbolKind};
use crate::symbol_table;
use veryl_parser::veryl_grammar_trait::*;
Expand Down Expand Up @@ -66,7 +66,10 @@ impl VerylGrammarTrait for CheckExpression<'_> {
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 { .. });
let result = matches!(
self.evaluator.expression(arg).value,
EvaluatedValue::Unknown
);
if result {
self.errors
.push(AnalyzerError::invalid_case_condition_non_elaborative(
Expand Down
11 changes: 7 additions & 4 deletions crates/analyzer/src/handlers/create_symbol_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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)
};
Expand Down
10 changes: 10 additions & 0 deletions crates/analyzer/src/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
}
107 changes: 68 additions & 39 deletions crates/analyzer/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::attribute::EnumEncodingItem;
use crate::evaluator::{Evaluated, Evaluator};
use crate::evaluator::{Evaluated, 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};
Expand Down Expand Up @@ -68,7 +68,7 @@ pub struct Symbol {
pub references: Vec<Token>,
pub generic_instances: Vec<SymbolId>,
pub imported: Vec<Namespace>,
pub evaluated: Cell<Option<Evaluated>>,
pub evaluated: RefCell<Option<Evaluated>>,
pub allow_unused: bool,
pub public: bool,
pub doc_comment: DocComment,
Expand All @@ -90,7 +90,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,
Expand All @@ -112,66 +112,95 @@ 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(),
_ => Evaluated::create_unknown(),
};
self.evaluated.replace(Some(evaluated));
self.evaluated.replace(Some(evaluated.clone()));
evaluated
}
}
Expand Down
10 changes: 10 additions & 0 deletions crates/analyzer/src/symbol_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
8 changes: 4 additions & 4 deletions crates/analyzer/src/symbol_table.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit a5aca8d

Please sign in to comment.