use std::{
collections::{HashMap, HashSet},
path::PathBuf,
};
use typescript_ir::{Program, TypeAnnotation, TypedProgram};
use typescript_types::TsError;
use num_cpus;
#[derive(Debug, Clone)]
pub struct CompilationOptions {
pub strict: bool,
pub incremental: bool,
pub parallel: bool,
pub parallel_threads: usize,
pub source_map: bool,
pub target: String,
pub module: String,
pub out_dir: Option<PathBuf>,
}
impl Default for CompilationOptions {
fn default() -> Self {
Self {
strict: false,
incremental: true,
parallel: true,
parallel_threads: num_cpus::get(),
source_map: true,
target: "es2020".to_string(),
module: "esnext".to_string(),
out_dir: None,
}
}
}
#[derive(Debug, Clone)]
pub struct Symbol {
pub name: String,
pub ty: TypeAnnotation,
pub is_const: bool,
pub is_exported: bool,
pub definition: Option<(String, usize, usize)>,
}
#[derive(Debug, Clone)]
pub struct SymbolTable {
symbols: HashMap<String, Symbol>,
}
impl SymbolTable {
pub fn new() -> Self {
Self { symbols: HashMap::new() }
}
pub fn add_symbol(&mut self, symbol: Symbol) {
self.symbols.insert(symbol.name.clone(), symbol);
}
pub fn get_symbol(&self, name: &str) -> Option<&Symbol> {
self.symbols.get(name)
}
pub fn has_symbol(&self, name: &str) -> bool {
self.symbols.contains_key(name)
}
pub fn remove_symbol(&mut self, name: &str) {
self.symbols.remove(name);
}
pub fn merge(&mut self, other: &SymbolTable) {
for (name, symbol) in &other.symbols {
self.symbols.insert(name.clone(), symbol.clone());
}
}
}
#[derive(Debug, Clone)]
pub struct CompilationContext {
pub options: CompilationOptions,
pub global_symbols: SymbolTable,
pub local_symbols: Vec<SymbolTable>,
pub type_env: HashMap<String, TypeAnnotation>,
pub function_env: HashMap<String, (Vec<TypeAnnotation>, Option<TypeAnnotation>)>,
pub type_aliases: HashMap<String, TypeAnnotation>,
pub interfaces: HashMap<String, Vec<(String, TypeAnnotation, bool)>>,
pub dependencies: HashSet<String>,
pub current_file: Option<PathBuf>,
pub current_stage: crate::compiler::CompilationStage,
pub errors: Vec<TsError>,
}
impl CompilationContext {
pub fn new(options: CompilationOptions) -> Self {
Self {
options,
global_symbols: SymbolTable::new(),
local_symbols: vec![SymbolTable::new()],
type_env: HashMap::new(),
function_env: HashMap::new(),
type_aliases: HashMap::new(),
interfaces: HashMap::new(),
dependencies: HashSet::new(),
current_file: None,
current_stage: crate::compiler::CompilationStage::LexicalAnalysis,
errors: Vec::new(),
}
}
pub fn enter_scope(&mut self) {
self.local_symbols.push(SymbolTable::new());
}
pub fn exit_scope(&mut self) {
if !self.local_symbols.is_empty() {
self.local_symbols.pop();
}
}
pub fn add_symbol(&mut self, symbol: Symbol) {
if let Some(last) = self.local_symbols.last_mut() {
last.add_symbol(symbol);
}
}
pub fn find_symbol(&self, name: &str) -> Option<&Symbol> {
for symbols in self.local_symbols.iter().rev() {
if let Some(symbol) = symbols.get_symbol(name) {
return Some(symbol);
}
}
self.global_symbols.get_symbol(name)
}
pub fn add_error(&mut self, error: TsError) {
self.errors.push(error);
}
pub fn has_errors(&self) -> bool {
!self.errors.is_empty()
}
pub fn get_errors(&self) -> &[TsError] {
&self.errors
}
pub fn set_stage(&mut self, stage: crate::compiler::CompilationStage) {
self.current_stage = stage;
}
pub fn add_dependency(&mut self, dependency: String) {
self.dependencies.insert(dependency);
}
pub fn get_dependencies(&self) -> &HashSet<String> {
&self.dependencies
}
}
impl Default for CompilationContext {
fn default() -> Self {
Self::new(CompilationOptions::default())
}
}