use crate::namespace::Namespace;
use crate::symbol::{
Affiliation, ClockDomain, Direction, DocComment, FunctionProperty, GenericBoundKind,
GenericParameterProperty, Port, PortProperty, Symbol, SymbolKind, TbComponentKind,
TbComponentProperty, Type, TypeKind, UserDefinedType,
};
use crate::symbol_path::{GenericSymbol, GenericSymbolPath, GenericSymbolPathKind};
use crate::symbol_table::SymbolTable;
use veryl_parser::token_range::TokenRange;
use veryl_parser::veryl_token::{Token, VerylToken};
fn builtin_type(kind: TypeKind) -> Type {
Type {
modifier: vec![],
kind,
width: vec![],
array: vec![],
array_type: None,
is_const: false,
token: TokenRange::default(),
}
}
fn generic_param_type(base: Token) -> Type {
let range: TokenRange = base.into();
let path = GenericSymbolPath {
paths: vec![GenericSymbol {
base,
arguments: vec![],
}],
kind: GenericSymbolPathKind::Identifier,
range,
};
Type {
modifier: vec![],
kind: TypeKind::UserDefined(UserDefinedType { path, symbol: None }),
width: vec![],
array: vec![],
array_type: None,
is_const: false,
token: range,
}
}
fn insert_method(
symbol_table: &mut SymbolTable,
parent_ns: &Namespace,
name: &str,
port_defs: &[(&str, Direction)],
ret: Option<Type>,
) {
let func_token = Token::builtin_text(name);
let mut func_ns = parent_ns.clone();
func_ns.push(func_token.text);
let mut ports = Vec::new();
for (port_name, direction) in port_defs {
let port_token = Token::builtin_text(port_name);
let port_type = Type {
modifier: vec![],
kind: TypeKind::Any,
width: vec![],
array: vec![],
array_type: None,
is_const: false,
token: TokenRange::default(),
};
let port_prop = PortProperty {
token: port_token,
r#type: port_type,
direction: *direction,
prefix: None,
suffix: None,
clock_domain: ClockDomain::None,
default_value: None,
is_proto: false,
};
let port_symbol = Symbol::new(
&port_token,
SymbolKind::Port(port_prop),
&func_ns,
false,
DocComment::default(),
);
if let Some(id) = symbol_table.insert(&port_token, port_symbol) {
ports.push(Port {
token: VerylToken::new(port_token),
symbol: id,
});
}
}
let func_prop = FunctionProperty {
affiliation: Affiliation::Module,
is_proto: false,
range: TokenRange::default(),
generic_parameters: vec![],
generic_consts: vec![],
generic_references: vec![],
ports,
ret,
reference_paths: vec![],
constantable: None,
write_paths: vec![],
call_sites: vec![],
conditional_effects: Box::default(),
definition: None,
};
let func_symbol = Symbol::new(
&func_token,
SymbolKind::Function(func_prop),
parent_ns,
true,
DocComment::default(),
);
let _ = symbol_table.insert(&func_token, func_symbol);
}
pub fn insert_external_components(names: &[&str]) {
let mut ns = Namespace::new();
let component_token = Token::builtin_text("$comp");
ns.push(component_token.text);
for name in names {
let token = Token::builtin_text(name);
let symbol = Symbol::new(
&token,
SymbolKind::TbComponent(TbComponentProperty {
kind: TbComponentKind::External(token.text),
generic_parameters: vec![],
}),
&ns,
true,
DocComment::default(),
);
let _ = crate::symbol_table::insert(&token, symbol);
}
}
pub fn insert_dependency_components(project: &str, names: &[&str]) {
let mut ns = Namespace::new();
let component_token = Token::builtin_text("$comp");
ns.push(component_token.text);
let project_token = Token::builtin_text(project);
let project_symbol = Symbol::new(
&project_token,
SymbolKind::Namespace,
&ns,
true,
DocComment::default(),
);
let _ = crate::symbol_table::insert(&project_token, project_symbol);
ns.push(project_token.text);
for name in names {
let token = Token::builtin_text(name);
let key = veryl_parser::resource_table::insert_str(&format!("{project}::{name}"));
let symbol = Symbol::new(
&token,
SymbolKind::TbComponent(TbComponentProperty {
kind: TbComponentKind::External(key),
generic_parameters: vec![],
}),
&ns,
true,
DocComment::default(),
);
let _ = crate::symbol_table::insert(&token, symbol);
}
}
fn insert_component(
symbol_table: &mut SymbolTable,
tb_ns: &Namespace,
name: &str,
kind: TbComponentKind,
) -> Namespace {
let token = Token::builtin_text(name);
let symbol = Symbol::new(
&token,
SymbolKind::TbComponent(TbComponentProperty {
kind,
generic_parameters: vec![],
}),
tb_ns,
true,
DocComment::default(),
);
let _ = symbol_table.insert(&token, symbol);
let mut ns = tb_ns.clone();
ns.push(token.text);
ns
}
fn insert_clock_gen(symbol_table: &mut SymbolTable, tb_ns: &Namespace) {
let ns = insert_component(symbol_table, tb_ns, "clock_gen", TbComponentKind::ClockGen);
insert_method(
symbol_table,
&ns,
"next",
&[("count", Direction::Input)],
None,
);
}
fn insert_reset_gen(symbol_table: &mut SymbolTable, tb_ns: &Namespace) {
let ns = insert_component(symbol_table, tb_ns, "reset_gen", TbComponentKind::ResetGen);
insert_method(
symbol_table,
&ns,
"assert",
&[("count", Direction::Input)],
None,
);
}
fn insert_file(symbol_table: &mut SymbolTable, tb_ns: &Namespace) {
let ns = insert_component(symbol_table, tb_ns, "file", TbComponentKind::File);
insert_method(
symbol_table,
&ns,
"open",
&[("name", Direction::Input)],
None,
);
insert_method(
symbol_table,
&ns,
"append",
&[("name", Direction::Input)],
None,
);
insert_method(symbol_table, &ns, "write", &[], None);
insert_method(symbol_table, &ns, "close", &[], None);
insert_method(symbol_table, &ns, "flush", &[], None);
}
fn insert_random(symbol_table: &mut SymbolTable, tb_ns: &Namespace) {
let random_token = Token::builtin_text("random");
let mut ns = tb_ns.clone();
ns.push(random_token.text);
let t_token = Token::builtin_text("T");
let t_symbol = Symbol::new(
&t_token,
SymbolKind::GenericParameter(GenericParameterProperty {
bound: GenericBoundKind::Type,
default_value: None,
}),
&ns,
false,
DocComment::default(),
);
let Some(t_id) = symbol_table.insert(&t_token, t_symbol) else {
return;
};
let random_symbol = Symbol::new(
&random_token,
SymbolKind::TbComponent(TbComponentProperty {
kind: TbComponentKind::Random,
generic_parameters: vec![t_id],
}),
tb_ns,
true,
DocComment::default(),
);
let _ = symbol_table.insert(&random_token, random_symbol);
insert_method(
symbol_table,
&ns,
"seed",
&[("value", Direction::Input)],
None,
);
insert_method(
symbol_table,
&ns,
"get",
&[],
Some(generic_param_type(t_token)),
);
insert_method(
symbol_table,
&ns,
"get_range",
&[("min", Direction::Input), ("max", Direction::Input)],
Some(generic_param_type(t_token)),
);
insert_method(
symbol_table,
&ns,
"get_seed",
&[],
Some(builtin_type(TypeKind::U64)),
);
}
pub fn insert_symbols(symbol_table: &mut SymbolTable, namespace: &Namespace) {
let mut tb_ns = namespace.clone();
let tb_token = Token::builtin_text("$tb");
tb_ns.push(tb_token.text);
insert_clock_gen(symbol_table, &tb_ns);
insert_reset_gen(symbol_table, &tb_ns);
insert_file(symbol_table, &tb_ns);
insert_random(symbol_table, &tb_ns);
}