diff --git a/checker/examples/run_checker.rs b/checker/examples/run_checker.rs index eee0dc63..a9e9a22a 100644 --- a/checker/examples/run_checker.rs +++ b/checker/examples/run_checker.rs @@ -56,6 +56,13 @@ fn main() { None, ); + if args.iter().any(|arg| arg == "--emit-dts") && !result.diagnostics.has_error() { + eprintln!("dts:"); + let mut buf = String::new(); + synthesis::definition_files::build_definition_file(&result, &mut buf); + eprintln!("{buf}"); + } + if args.iter().any(|arg| arg == "--types") { eprintln!("Types:"); let types = result.types.into_vec_temp(); diff --git a/checker/src/context/root.rs b/checker/src/context/root.rs index 4c6bf909..6c2eef7a 100644 --- a/checker/src/context/root.rs +++ b/checker/src/context/root.rs @@ -114,12 +114,12 @@ impl RootContext { } } - pub fn new_module_context<'a, T: crate::ReadFromFS, A: crate::ASTImplementation>( + pub fn synthesise_module( &self, source: SourceId, module: A::Module<'static>, - checking_data: &'a mut CheckingData, - ) -> &'a SynthesisedModule { + checking_data: &mut CheckingData, + ) { let module_scope = crate::Scope::Module { source, exported: Exported::default() }; let mut environment = self.new_lexical_environment(module_scope); A::synthesise_module(&module, source, &mut environment, checking_data); @@ -138,7 +138,6 @@ impl RootContext { // TODO better way to do this? checking_data.modules.synthesised_modules.insert(source, module); - checking_data.modules.synthesised_modules.get(&source).unwrap() } /// TODO working things out: diff --git a/checker/src/features/modules.rs b/checker/src/features/modules.rs index a0b8e048..a76f6085 100644 --- a/checker/src/features/modules.rs +++ b/checker/src/features/modules.rs @@ -85,6 +85,65 @@ impl Exported { pub fn keys(&self) -> impl Iterator { self.named.keys().chain(self.named_types.keys()).map(AsRef::as_ref) } + + /// For tree shaking + pub(crate) fn evaluate_generally( + &self, + root: &crate::RootContext, + types: &mut crate::types::TypeStore, + ) { + use crate::context::invocation::InvocationContext; + use crate::source_map::{Nullable, SpanWithSource}; + use crate::types::{ + calling::{CallingInput, SynthesisedArgument}, + SpecialObject, Type, + }; + + // TODO might need special + let mut environment = root.new_lexical_environment(Scope::Block {}); + + if let Some(default) = &self.default { + match types.get_type_by_id(*default) { + Type::SpecialObject(SpecialObject::Function(func, this_value)) => { + let func = types.get_function_from_id(*func); + let mut arguments = Vec::new(); + for parameter in &func.parameters.parameters { + arguments.push(SynthesisedArgument { + // TODO get_constraint + open + value: parameter.ty, + spread: false, + position: SpanWithSource::NULL, + }); + } + let input = CallingInput { + called_with_new: crate::types::calling::CalledWithNew::None, + call_site: SpanWithSource::NULL, + max_inline: 0, + }; + + let this_value = *this_value; + let _result = func.clone().call( + (this_value, &arguments, None, None), + input, + &mut environment, + (&mut InvocationContext::new_empty(), &mut Default::default()), + types, + ); + + crate::utilities::notify!("Call result as well"); + } + Type::Object(_d) => { + todo!() + } + ty => { + crate::utilities::notify!("Cannot call {:?}", ty); + } + } + } + for (_name, (_variable_id, _)) in self.named.iter() { + todo!("call like type") + } + } } /// After a syntax error @@ -351,9 +410,11 @@ pub fn import_file( match module { Ok(module) => { let root = &environment.get_root(); - let new_module_context = - root.new_module_context(source, module, checking_data); - Some(Ok(new_module_context)) + root.synthesise_module(source, module, checking_data); + + let module = + checking_data.modules.synthesised_modules.get(&source).unwrap(); + Some(Ok(module)) } Err(err) => Some(Err(err)), } diff --git a/checker/src/lib.rs b/checker/src/lib.rs index 91780ee7..1ce92e3c 100644 --- a/checker/src/lib.rs +++ b/checker/src/lib.rs @@ -509,10 +509,17 @@ pub fn check_project( let current = checking_data.options.measure_time.then(std::time::Instant::now); match module { Ok(module) => { - let _module = root.new_module_context(source, module, &mut checking_data); + root.synthesise_module(source, module, &mut checking_data); if let Some(current) = current { checking_data.chronometer.check += current.elapsed(); } + + let evaluate_exports = checking_data.options.evaluate_exports; + if evaluate_exports { + let module = + checking_data.modules.synthesised_modules.get(&source).unwrap(); + module.exported.clone().evaluate_generally(&root, &mut checking_data.types); + } } Err(err) => { checking_data.diagnostics_container.add_error(err); diff --git a/checker/src/synthesis/mod.rs b/checker/src/synthesis/mod.rs index a29560a5..dd33204b 100644 --- a/checker/src/synthesis/mod.rs +++ b/checker/src/synthesis/mod.rs @@ -396,3 +396,107 @@ pub mod interactive { } } } + +pub mod definition_files { + use iterator_endiate::EndiateIteratorExt; + use parser::ExpressionOrStatementPosition; + + use crate::{ + types::{printing, GenericChain}, + FunctionId, + }; + + pub fn build_definition_file(result: &crate::CheckOutput, buf: &mut String) { + for (source_id, module) in &result.modules { + for item in &module.content.items { + match item { + parser::StatementOrDeclaration::Declaration(parser::Declaration::Export( + decorated, + )) => match &decorated.on { + parser::ast::ExportDeclaration::Variable { exported, position: _ } => { + match exported { + parser::ast::export::Exportable::Class(_) => todo!(), + parser::ast::export::Exportable::Function(func) => { + let expected = result.types.get_function_from_id(FunctionId( + *source_id, + parser::ASTNode::get_position(func).start, + )); + buf.push_str("export function "); + buf.push_str(func.name.as_option_str().unwrap_or_default()); + buf.push('('); + for (not_at_end, param) in + expected.parameters.parameters.iter().nendiate() + { + buf.push_str(¶m.name); + buf.push_str(": "); + printing::print_type_into_buf( + param.ty, + buf, + &mut Default::default(), + GenericChain::None, + &result.types, + &module.info, + false, + ); + if not_at_end { + buf.push_str(", "); + } + } + buf.push(')'); + buf.push_str(": "); + printing::print_type_into_buf( + expected.return_type, + buf, + &mut Default::default(), + GenericChain::None, + &result.types, + &module.info, + false, + ); + buf.push_str(";\n"); + } + parser::ast::export::Exportable::Variable(_) => todo!(), + parser::ast::export::Exportable::Interface(item) => { + buf.push_str("export "); + todo!("{item:?}"); + // item.to_string_from_buffer(buf, &ToStringOptions::typescript(), LocalToStringInformation { under: }) + } + parser::ast::export::Exportable::TypeAlias(item) => { + buf.push_str("export "); + todo!("{item:?}"); + // item.to_string_from_buffer(buf, &ToStringOptions::typescript(), LocalToStringInformation { under: }) + } + parser::ast::export::Exportable::Parts(_) => todo!(), + parser::ast::export::Exportable::ImportAll { .. } => { + todo!() + } + parser::ast::export::Exportable::ImportParts { .. } => todo!(), + } + } + parser::ast::ExportDeclaration::Default { .. } => todo!(), + parser::ast::ExportDeclaration::DefaultFunction { .. } => todo!(), + }, + parser::StatementOrDeclaration::Declaration( + parser::Declaration::Interface(_), + ) => { + todo!() + } + parser::StatementOrDeclaration::Declaration( + parser::Declaration::TypeAlias(_), + ) => { + todo!() + } + parser::StatementOrDeclaration::Declaration( + parser::Declaration::DeclareVariable(..), + ) => {} + parser::StatementOrDeclaration::Declaration(parser::Declaration::Class(..)) => { + } + parser::StatementOrDeclaration::Statement( + parser::Statement::MultiLineComment(..), + ) => {} + _ => {} + } + } + } + } +}