Add debug information compilation for subprograms and their parameters
This commit is contained in:
		
							parent
							
								
									9bb4f97e6b
								
							
						
					
					
						commit
						0c6d9885ec
					
				| @ -4,9 +4,9 @@ fn main() { | ||||
|     use ConstValue::*; | ||||
|     use Instr::*; | ||||
| 
 | ||||
|     let context = Context::new(); | ||||
|     let context = Context::new("libtest"); | ||||
| 
 | ||||
|     let mut module = context.module("test", true); | ||||
|     let module = context.module("test", true); | ||||
| 
 | ||||
|     let main = module.function("main", Type::I32, Vec::new(), FunctionFlags::default()); | ||||
|     let mut m_entry = main.block("entry"); | ||||
|  | ||||
| @ -8,6 +8,7 @@ use crate::{ | ||||
|     TerminatorKind, Type, TypeData, | ||||
|     debug_information::{ | ||||
|         DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue, | ||||
|         DebugSubprogramValue, | ||||
|     }, | ||||
|     util::match_types, | ||||
| }; | ||||
| @ -65,12 +66,14 @@ pub struct InstructionHolder { | ||||
| #[derive(Clone)] | ||||
| pub(crate) struct Builder { | ||||
|     modules: Rc<RefCell<Vec<ModuleHolder>>>, | ||||
|     pub(crate) producer: String, | ||||
| } | ||||
| 
 | ||||
| impl Builder { | ||||
|     pub fn new() -> Builder { | ||||
|     pub fn new(producer: String) -> Builder { | ||||
|         Builder { | ||||
|             modules: Rc::new(RefCell::new(Vec::new())), | ||||
|             producer, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -193,16 +196,16 @@ impl Builder { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) unsafe fn add_function_metadata( | ||||
|     pub(crate) unsafe fn set_debug_subprogram( | ||||
|         &self, | ||||
|         value: &FunctionValue, | ||||
|         metadata: DebugMetadataValue, | ||||
|         subprogram: DebugSubprogramValue, | ||||
|     ) { | ||||
|         unsafe { | ||||
|             let mut modules = self.modules.borrow_mut(); | ||||
|             let module = modules.get_unchecked_mut(value.0.0); | ||||
|             let function = module.functions.get_unchecked_mut(value.1); | ||||
|             function.data.meta = Some(metadata) | ||||
|             function.data.debug = Some(subprogram) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -8,6 +8,7 @@ use llvm_sys::{ | ||||
|     LLVMIntPredicate, LLVMLinkage, | ||||
|     analysis::LLVMVerifyModule, | ||||
|     core::*, | ||||
|     debuginfo::*, | ||||
|     linker::LLVMLinkModules2, | ||||
|     prelude::*, | ||||
|     target::{ | ||||
| @ -23,6 +24,7 @@ use llvm_sys::{ | ||||
| use crate::{ | ||||
|     CustomTypeKind, | ||||
|     builder::{TypeHolder, TypeValue}, | ||||
|     debug_information::*, | ||||
|     util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring}, | ||||
| }; | ||||
| 
 | ||||
| @ -180,12 +182,34 @@ pub struct LLVMModule<'a> { | ||||
|     blocks: HashMap<BlockValue, LLVMBasicBlockRef>, | ||||
|     values: HashMap<InstructionValue, LLVMValue>, | ||||
|     types: HashMap<TypeValue, LLVMTypeRef>, | ||||
|     debug: Option<LLVMDebugInformation<'a>>, | ||||
| } | ||||
| 
 | ||||
| impl<'a> Drop for LLVMModule<'a> { | ||||
|     fn drop(&mut self) { | ||||
|         if let Some(LLVMDebugInformation { builder, .. }) = self.debug { | ||||
|             unsafe { | ||||
|                 LLVMDisposeDIBuilder(builder); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct LLVMDebugInformation<'a> { | ||||
|     debug: &'a DebugInformation, | ||||
|     builder: LLVMDIBuilderRef, | ||||
|     file_ref: LLVMMetadataRef, | ||||
|     scopes: &'a HashMap<DebugScopeValue, LLVMMetadataRef>, | ||||
|     types: &'a mut HashMap<DebugTypeValue, LLVMMetadataRef>, | ||||
|     subprograms: &'a mut HashMap<DebugSubprogramValue, LLVMMetadataRef>, | ||||
|     metadata: &'a mut HashMap<DebugMetadataValue, LLVMMetadataRef>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy)] | ||||
| pub struct LLVMFunction { | ||||
|     type_ref: LLVMTypeRef, | ||||
|     value_ref: LLVMValueRef, | ||||
|     metadata: Option<LLVMMetadataRef>, | ||||
| } | ||||
| 
 | ||||
| pub struct LLVMValue { | ||||
| @ -203,6 +227,80 @@ impl ModuleHolder { | ||||
| 
 | ||||
|             // Compile the contents
 | ||||
| 
 | ||||
|             let mut scopes = HashMap::new(); | ||||
|             let mut types = HashMap::new(); | ||||
|             let mut metadata = HashMap::new(); | ||||
|             let mut subprograms = HashMap::new(); | ||||
| 
 | ||||
|             let mut debug = if let Some(debug) = &self.debug_information { | ||||
|                 let di_builder = LLVMCreateDIBuilder(module_ref); | ||||
| 
 | ||||
|                 let file_ref = LLVMDIBuilderCreateFile( | ||||
|                     di_builder, | ||||
|                     into_cstring(debug.file.name.clone()).as_ptr(), | ||||
|                     debug.file.name.len(), | ||||
|                     into_cstring(debug.file.directory.clone()).as_ptr(), | ||||
|                     debug.file.directory.len(), | ||||
|                 ); | ||||
| 
 | ||||
|                 let flags = String::new(); | ||||
| 
 | ||||
|                 let compile_unit = LLVMDIBuilderCreateCompileUnit( | ||||
|                     di_builder, | ||||
|                     LLVMDWARFSourceLanguage::LLVMDWARFSourceLanguageC, | ||||
|                     file_ref, | ||||
|                     into_cstring(builder.producer.clone()).as_ptr(), | ||||
|                     builder.producer.len(), | ||||
|                     // is optimized
 | ||||
|                     0, | ||||
|                     into_cstring(flags.clone()).as_ptr(), | ||||
|                     flags.len(), | ||||
|                     // Runtime version
 | ||||
|                     0, | ||||
|                     // Split filename
 | ||||
|                     into_cstring(debug.file.name.clone()).as_ptr(), | ||||
|                     debug.file.name.len(), | ||||
|                     LLVMDWARFEmissionKind::LLVMDWARFEmissionKindFull, | ||||
|                     // The DWOId if this is a split skeleton compile unit.
 | ||||
|                     0, | ||||
|                     // Whether to emit inline debug info.
 | ||||
|                     true as i32, | ||||
|                     // Whether to emit extra debug info for
 | ||||
|                     // profile collection.
 | ||||
|                     false as i32, | ||||
|                     // The clang system root (value of -isysroot).
 | ||||
|                     c"".as_ptr(), | ||||
|                     0, | ||||
|                     // The SDK name. On Darwin, this is the last component of
 | ||||
|                     // the sysroot.
 | ||||
|                     c"".as_ptr(), | ||||
|                     0, | ||||
|                 ); | ||||
| 
 | ||||
|                 let scope = debug.get_scopes(); | ||||
|                 scope | ||||
|                     .borrow() | ||||
|                     .compile_scope(compile_unit, file_ref, &mut scopes, di_builder); | ||||
| 
 | ||||
|                 let debug = LLVMDebugInformation { | ||||
|                     builder: di_builder, | ||||
|                     debug: debug, | ||||
|                     file_ref, | ||||
|                     types: &mut types, | ||||
|                     metadata: &mut metadata, | ||||
|                     subprograms: &mut subprograms, | ||||
|                     scopes: &scopes, | ||||
|                 }; | ||||
| 
 | ||||
|                 for ty in debug.debug.get_types().borrow().iter() { | ||||
|                     let meta_ref = ty.compile_debug(&debug); | ||||
|                     debug.types.insert(ty.value.clone(), meta_ref); | ||||
|                 } | ||||
|                 Some(debug) | ||||
|             } else { | ||||
|                 None | ||||
|             }; | ||||
| 
 | ||||
|             let mut types = HashMap::new(); | ||||
|             for ty in &self.types { | ||||
|                 types.insert(ty.value, ty.compile_type(context, &types)); | ||||
| @ -212,10 +310,17 @@ impl ModuleHolder { | ||||
|             for function in &self.functions { | ||||
|                 functions.insert( | ||||
|                     function.value, | ||||
|                     function.compile_signature(context, module_ref, &types), | ||||
|                     function.compile_signature(context, module_ref, &types, &debug), | ||||
|                 ); | ||||
|             } | ||||
| 
 | ||||
|             // if let Some(debug) = &mut debug {
 | ||||
|             //     for subprogram in debug.debug.get_subprograms().borrow().iter() {
 | ||||
|             //         let meta_ref = subprogram.compile_debug(&functions, &debug);
 | ||||
|             //         debug.subprograms.insert(subprogram.value.clone(), meta_ref);
 | ||||
|             //     }
 | ||||
|             // }
 | ||||
| 
 | ||||
|             let mut module = LLVMModule { | ||||
|                 builder, | ||||
|                 context_ref: context.context_ref, | ||||
| @ -225,17 +330,111 @@ impl ModuleHolder { | ||||
|                 types, | ||||
|                 blocks: HashMap::new(), | ||||
|                 values: HashMap::new(), | ||||
|                 debug, | ||||
|             }; | ||||
| 
 | ||||
|             for function in &self.functions { | ||||
|                 function.compile(&mut module, self.data.is_main); | ||||
|             } | ||||
| 
 | ||||
|             if let Some(debug) = &module.debug { | ||||
|                 LLVMDIBuilderFinalize(debug.builder); | ||||
|             } | ||||
| 
 | ||||
|             module_ref | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl DebugScopeHolder { | ||||
|     unsafe fn compile_scope( | ||||
|         &self, | ||||
|         parent: LLVMMetadataRef, | ||||
|         file: LLVMMetadataRef, | ||||
|         map: &mut HashMap<DebugScopeValue, LLVMMetadataRef>, | ||||
|         di_builder: LLVMDIBuilderRef, | ||||
|     ) { | ||||
|         unsafe { | ||||
|             let scope = if let Some(location) = &self.location { | ||||
|                 LLVMDIBuilderCreateLexicalBlock( | ||||
|                     di_builder, | ||||
|                     parent, | ||||
|                     file, | ||||
|                     location.line, | ||||
|                     location.column, | ||||
|                 ) | ||||
|             } else { | ||||
|                 LLVMDIBuilderCreateLexicalBlockFile(di_builder, parent, file, 0) | ||||
|             }; | ||||
| 
 | ||||
|             for inner in &self.inner_scopes { | ||||
|                 inner.compile_scope(scope, file, map, di_builder); | ||||
|             } | ||||
| 
 | ||||
|             map.insert(self.value.clone(), scope); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl DebugMetadataHolder { | ||||
|     unsafe fn compile_meta(&self, debug: &LLVMDebugInformation) -> LLVMMetadataRef { | ||||
|         unsafe { | ||||
|             match &self.data { | ||||
|                 DebugMetadata::ParamVar(param) => LLVMDIBuilderCreateParameterVariable( | ||||
|                     debug.builder, | ||||
|                     *debug.scopes.get(&self.scope).unwrap(), | ||||
|                     into_cstring(param.name.clone()).as_ptr(), | ||||
|                     param.name.len(), | ||||
|                     param.arg_idx, | ||||
|                     debug.file_ref, | ||||
|                     param.location.line, | ||||
|                     *debug.types.get(¶m.ty).unwrap(), | ||||
|                     param.always_preserve as i32, | ||||
|                     param.flags.as_llvm(), | ||||
|                 ), | ||||
|                 DebugMetadata::LocalVar(debug_local_variable) => todo!(), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl DebugTypeHolder { | ||||
|     unsafe fn compile_debug(&self, debug: &LLVMDebugInformation) -> LLVMMetadataRef { | ||||
|         unsafe { | ||||
|             match &self.data { | ||||
|                 DebugTypeData::Basic(ty) => LLVMDIBuilderCreateBasicType( | ||||
|                     debug.builder, | ||||
|                     into_cstring(ty.name.clone()).as_ptr(), | ||||
|                     ty.name.len(), | ||||
|                     ty.size_bits as u64, | ||||
|                     ty.encoding as u32, | ||||
|                     ty.flags.as_llvm(), | ||||
|                 ), | ||||
|                 DebugTypeData::Subprogram(subprogram) => { | ||||
|                     let mut params = subprogram | ||||
|                         .parameters | ||||
|                         .iter() | ||||
|                         .map(|p| *debug.types.get(p).unwrap()) | ||||
|                         .collect::<Vec<_>>(); | ||||
|                     LLVMDIBuilderCreateSubroutineType( | ||||
|                         debug.builder, | ||||
|                         debug.file_ref, | ||||
|                         params.as_mut_ptr(), | ||||
|                         params.len() as u32, | ||||
|                         subprogram.flags.as_llvm(), | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl DwarfFlags { | ||||
|     pub fn as_llvm(&self) -> i32 { | ||||
|         0 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TypeHolder { | ||||
|     unsafe fn compile_type( | ||||
|         &self, | ||||
| @ -268,6 +467,7 @@ impl FunctionHolder { | ||||
|         context: &LLVMContext, | ||||
|         module_ref: LLVMModuleRef, | ||||
|         types: &HashMap<TypeValue, LLVMTypeRef>, | ||||
|         debug: &Option<LLVMDebugInformation>, | ||||
|     ) -> LLVMFunction { | ||||
|         unsafe { | ||||
|             let ret_type = self.data.ret.as_llvm(context.context_ref, types); | ||||
| @ -285,9 +485,41 @@ impl FunctionHolder { | ||||
|             let function_ref = | ||||
|                 LLVMAddFunction(module_ref, into_cstring(&self.data.name).as_ptr(), fn_type); | ||||
| 
 | ||||
|             let metadata = if let Some(debug) = debug { | ||||
|                 if let Some(value) = &self.data.debug { | ||||
|                     let subprogram = debug.debug.get_subprogram_data(&value); | ||||
| 
 | ||||
|                     let mangled_length_ptr = &mut 0; | ||||
|                     let mangled_name = LLVMGetValueName2(function_ref, mangled_length_ptr); | ||||
|                     let mangled_length = *mangled_length_ptr; | ||||
| 
 | ||||
|                     Some(LLVMDIBuilderCreateFunction( | ||||
|                         debug.builder, | ||||
|                         *debug.scopes.get(&subprogram.scope).unwrap(), | ||||
|                         into_cstring(subprogram.name.clone()).as_ptr(), | ||||
|                         subprogram.name.clone().len(), | ||||
|                         mangled_name, | ||||
|                         mangled_length, | ||||
|                         debug.file_ref, | ||||
|                         subprogram.location.line, | ||||
|                         *debug.types.get(&subprogram.ty).unwrap(), | ||||
|                         subprogram.opts.is_local as i32, | ||||
|                         subprogram.opts.is_definition as i32, | ||||
|                         subprogram.opts.scope_line, | ||||
|                         subprogram.opts.flags.as_llvm(), | ||||
|                         subprogram.opts.is_optimized as i32, | ||||
|                     )) | ||||
|                 } else { | ||||
|                     None | ||||
|                 } | ||||
|             } else { | ||||
|                 None | ||||
|             }; | ||||
| 
 | ||||
|             LLVMFunction { | ||||
|                 type_ref: fn_type, | ||||
|                 value_ref: function_ref, | ||||
|                 metadata, | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -9,9 +9,15 @@ pub struct DebugScopeValue(pub Vec<usize>); | ||||
| #[derive(Debug, Clone, Hash, PartialEq, Eq)] | ||||
| pub struct DebugLocationValue(pub DebugScopeValue, pub usize); | ||||
| 
 | ||||
| #[derive(Debug, Clone, Hash, PartialEq, Eq)] | ||||
| #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] | ||||
| pub struct DebugTypeValue(pub usize); | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] | ||||
| pub struct DebugMetadataValue(pub usize); | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] | ||||
| pub struct DebugSubprogramValue(pub usize); | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugFileData { | ||||
|     pub name: String, | ||||
| @ -20,17 +26,29 @@ pub struct DebugFileData { | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub(crate) struct DebugScopeHolder { | ||||
|     value: DebugScopeValue, | ||||
|     location: Option<DebugLocation>, | ||||
|     inner_scopes: Vec<DebugScopeHolder>, | ||||
|     locations: Vec<DebugLocationHolder>, | ||||
|     pub(crate) value: DebugScopeValue, | ||||
|     pub(crate) location: Option<DebugLocation>, | ||||
|     pub(crate) inner_scopes: Vec<DebugScopeHolder>, | ||||
|     pub(crate) locations: Vec<DebugLocationHolder>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugMetadataHolder { | ||||
|     scope: DebugScopeValue, | ||||
|     value: DebugMetadataValue, | ||||
|     data: DebugMetadata, | ||||
|     pub(crate) scope: DebugScopeValue, | ||||
|     pub(crate) value: DebugMetadataValue, | ||||
|     pub(crate) data: DebugMetadata, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugTypeHolder { | ||||
|     pub(crate) value: DebugTypeValue, | ||||
|     pub(crate) data: DebugTypeData, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugSubprogramHolder { | ||||
|     pub(crate) value: DebugSubprogramValue, | ||||
|     pub(crate) data: DebugSubprogramData, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| @ -39,17 +57,13 @@ pub(crate) struct DebugLocationHolder { | ||||
|     location: DebugLocation, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugLocation { | ||||
|     pub line: u32, | ||||
|     pub column: u32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugInformation { | ||||
|     file: DebugFileData, | ||||
|     pub file: DebugFileData, | ||||
|     scope: Rc<RefCell<DebugScopeHolder>>, | ||||
|     subprograms: Rc<RefCell<Vec<DebugSubprogramHolder>>>, | ||||
|     metadata: Rc<RefCell<Vec<DebugMetadataHolder>>>, | ||||
|     types: Rc<RefCell<Vec<DebugTypeHolder>>>, | ||||
| } | ||||
| 
 | ||||
| impl DebugInformation { | ||||
| @ -65,6 +79,8 @@ impl DebugInformation { | ||||
|                     location: None, | ||||
|                 })), | ||||
|                 metadata: Rc::new(RefCell::new(Vec::new())), | ||||
|                 subprograms: Rc::new(RefCell::new(Vec::new())), | ||||
|                 types: Rc::new(RefCell::new(Vec::new())), | ||||
|             }, | ||||
|             scope_value, | ||||
|         ) | ||||
| @ -120,6 +136,16 @@ impl DebugInformation { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn debug_type(&self, kind: DebugTypeData) -> DebugTypeValue { | ||||
|         let mut types = self.types.borrow_mut(); | ||||
|         let value = DebugTypeValue(types.len()); | ||||
|         types.push(DebugTypeHolder { | ||||
|             value: value.clone(), | ||||
|             data: kind, | ||||
|         }); | ||||
|         value | ||||
|     } | ||||
| 
 | ||||
|     pub fn metadata(&self, scope: &DebugScopeValue, kind: DebugMetadata) -> DebugMetadataValue { | ||||
|         let mut metadata = self.metadata.borrow_mut(); | ||||
|         let value = DebugMetadataValue(metadata.len()); | ||||
| @ -130,25 +156,133 @@ impl DebugInformation { | ||||
|         }); | ||||
|         value | ||||
|     } | ||||
| 
 | ||||
|     fn check_metadata(&self, scope: &DebugScopeValue, metadata: &DebugMetadata) { | ||||
|         match &metadata { | ||||
|             DebugMetadata::ParamVar(debug_param_variable) => todo!(), | ||||
|             DebugMetadata::LocalVar(debug_local_variable) => todo!(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn subprogram(&self, kind: DebugSubprogramData) -> DebugSubprogramValue { | ||||
|         let mut subprogram = self.subprograms.borrow_mut(); | ||||
|         let value = DebugSubprogramValue(subprogram.len()); | ||||
|         subprogram.push(DebugSubprogramHolder { | ||||
|             value: value.clone(), | ||||
|             data: kind, | ||||
|         }); | ||||
|         value | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_metadata(&self) -> Rc<RefCell<Vec<DebugMetadataHolder>>> { | ||||
|         self.metadata.clone() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_scopes(&self) -> Rc<RefCell<DebugScopeHolder>> { | ||||
|         self.scope.clone() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_subprograms(&self) -> Rc<RefCell<Vec<DebugSubprogramHolder>>> { | ||||
|         self.subprograms.clone() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_types(&self) -> Rc<RefCell<Vec<DebugTypeHolder>>> { | ||||
|         self.types.clone() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_subprogram_data(&self, value: &DebugSubprogramValue) -> DebugSubprogramData { | ||||
|         unsafe { | ||||
|             self.subprograms | ||||
|                 .borrow() | ||||
|                 .get_unchecked(value.0) | ||||
|                 .data | ||||
|                 .clone() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, Default)] | ||||
| pub struct DebugLocation { | ||||
|     pub line: u32, | ||||
|     pub column: u32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum DebugMetadata { | ||||
|     Function(DebugFunction), | ||||
|     BasicType(DebugBasicType), | ||||
|     ParamVar(DebugParamVariable), | ||||
|     LocalVar(DebugLocalVariable), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugBasicType { | ||||
| pub struct DebugParamVariable { | ||||
|     pub name: String, | ||||
|     pub size_bits: u32, | ||||
|     pub encoding: AteEncoding, | ||||
|     /// the index (starting from 1) of this variable in the subprogram
 | ||||
|     /// parameters. arg_idx should not conflict with other parameters of the
 | ||||
|     /// same subprogram.
 | ||||
|     pub arg_idx: u32, | ||||
|     /// Used for line number
 | ||||
|     pub location: DebugLocation, | ||||
|     pub ty: DebugTypeValue, | ||||
|     /// If this variable will be referenced from its containing subprogram, and
 | ||||
|     /// will survive some optimizations.
 | ||||
|     pub always_preserve: bool, | ||||
|     pub flags: DwarfFlags, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum AteEncoding { | ||||
| pub struct DebugLocalVariable { | ||||
|     pub name: String, | ||||
|     pub location: DebugLocation, | ||||
|     pub ty: DebugMetadataValue, | ||||
|     pub always_preserve: bool, | ||||
|     pub alignment: u32, | ||||
| } | ||||
| 
 | ||||
| impl Default for DebugSubprogramOptionals { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             scope_line: 0, | ||||
|             is_local: false, | ||||
|             is_definition: true, | ||||
|             is_optimized: false, | ||||
|             flags: DwarfFlags, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DwarfFlags; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub enum DebugTypeData { | ||||
|     Basic(DebugBasicType), | ||||
|     Subprogram(DebugSubprogramTypeData), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugBasicType { | ||||
|     pub name: String, | ||||
|     /// Size of the type.
 | ||||
|     pub size_bits: u64, | ||||
|     /// DWARF encoding code, e.g., dwarf::DW_ATE_float.
 | ||||
|     pub encoding: DwarfEncoding, | ||||
|     /// Optional DWARF attributes, e.g., DW_AT_endianity.
 | ||||
|     pub flags: DwarfFlags, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugSubprogramTypeData { | ||||
|     pub parameters: Vec<DebugTypeValue>, | ||||
|     pub flags: DwarfFlags, | ||||
| } | ||||
| 
 | ||||
| pub struct DebugSubprogramType { | ||||
|     pub params: Vec<DebugSubprogramValue>, | ||||
|     pub flags: DwarfFlags, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| pub enum DwarfEncoding { | ||||
|     Address = 1, | ||||
|     Boolean = 2, | ||||
|     Float = 4, | ||||
| @ -159,34 +293,25 @@ pub enum AteEncoding { | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugFunction { | ||||
|     pub scope: DebugScopeValue, | ||||
| pub struct DebugSubprogramData { | ||||
|     /// Function name.
 | ||||
|     pub name: String, | ||||
|     pub linkage_name: String, | ||||
|     pub scope: DebugScopeValue, | ||||
|     /// Used for line number.
 | ||||
|     pub location: DebugLocation, | ||||
|     pub return_ty: DebugMetadataValue, | ||||
|     /// Function type.
 | ||||
|     pub ty: DebugTypeValue, | ||||
|     pub opts: DebugSubprogramOptionals, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugSubprogramOptionals { | ||||
|     /// Set to the beginning of the scope this starts
 | ||||
|     pub scope_line: u32, | ||||
|     pub is_local: bool, | ||||
|     pub is_definition: bool, | ||||
|     pub is_optimized: bool, | ||||
|     pub scope_line: u32, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugParamVariable { | ||||
|     pub scope: DebugScopeValue, | ||||
|     pub name: String, | ||||
|     pub arg_idx: u32, | ||||
|     pub location: DebugLocation, | ||||
|     pub ty: DebugMetadataValue, | ||||
|     pub always_preserve: bool, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct DebugLocalVariable { | ||||
|     pub scope: DebugScopeValue, | ||||
|     pub name: String, | ||||
|     pub location: DebugLocation, | ||||
|     pub ty: DebugMetadataValue, | ||||
|     pub always_preserve: bool, | ||||
|     pub alignment: u32, | ||||
|     /// These flags are used to emit dwarf attributes. e.g. is this function
 | ||||
|     /// prototyped or not.
 | ||||
|     pub flags: DwarfFlags, | ||||
| } | ||||
|  | ||||
| @ -8,7 +8,7 @@ use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue, | ||||
| use debug::PrintableModule; | ||||
| use debug_information::{ | ||||
|     DebugFileData, DebugInformation, DebugLocation, DebugLocationValue, DebugMetadataValue, | ||||
|     DebugScopeValue, | ||||
|     DebugScopeValue, DebugSubprogramValue, | ||||
| }; | ||||
| use util::match_types; | ||||
| 
 | ||||
| @ -24,9 +24,9 @@ pub struct Context { | ||||
| } | ||||
| 
 | ||||
| impl Context { | ||||
|     pub fn new() -> Context { | ||||
|     pub fn new<T: Into<String>>(producer: T) -> Context { | ||||
|         Context { | ||||
|             builder: Builder::new(), | ||||
|             builder: Builder::new(producer.into()), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -76,7 +76,7 @@ impl<'ctx> Module<'ctx> { | ||||
|                         ret, | ||||
|                         params, | ||||
|                         flags, | ||||
|                         meta: None, | ||||
|                         debug: None, | ||||
|                     }, | ||||
|                 ), | ||||
|             } | ||||
| @ -131,7 +131,7 @@ pub struct FunctionData { | ||||
|     ret: Type, | ||||
|     params: Vec<Type>, | ||||
|     flags: FunctionFlags, | ||||
|     meta: Option<DebugMetadataValue>, | ||||
|     debug: Option<DebugSubprogramValue>, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, Hash)] | ||||
| @ -177,9 +177,9 @@ impl<'ctx> Function<'ctx> { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_metadata(&self, metadata: DebugMetadataValue) { | ||||
|     pub fn set_debug(&self, subprogram: DebugSubprogramValue) { | ||||
|         unsafe { | ||||
|             self.builder.add_function_metadata(&self.value, metadata); | ||||
|             self.builder.set_debug_subprogram(&self.value, subprogram); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -172,7 +172,7 @@ fn main() { | ||||
|     }; | ||||
|     println!("test1"); | ||||
| 
 | ||||
|     let context = Context::new(); | ||||
|     let context = Context::new("testcodegen"); | ||||
|     let codegen = mir_context.codegen(&context); | ||||
|     println!("test2"); | ||||
| 
 | ||||
|  | ||||
| @ -4,15 +4,22 @@ use reid_lib::{ | ||||
|     builder::{InstructionValue, TypeValue}, | ||||
|     compile::CompiledModule, | ||||
|     debug_information::{ | ||||
|         AteEncoding, DebugBasicType, DebugFileData, DebugFunction, DebugInformation, DebugLocation, | ||||
|         DebugMetadata, DebugMetadataValue, DebugScopeValue, | ||||
|         DebugBasicType, DebugFileData, DebugInformation, DebugLocation, DebugMetadata, | ||||
|         DebugMetadataValue, DebugParamVariable, DebugScopeValue, DebugSubprogramData, | ||||
|         DebugSubprogramOptionals, DebugSubprogramTypeData, DebugSubprogramValue, DebugTypeData, | ||||
|         DebugTypeValue, DwarfEncoding, DwarfFlags, | ||||
|     }, | ||||
|     Block, CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, | ||||
|     Module, NamedStruct, TerminatorKind as Term, Type, | ||||
| }; | ||||
| 
 | ||||
| use crate::mir::{ | ||||
|     self, NamedVariableRef, StructField, StructType, TypeDefinitionKind, TypeKind, VagueLiteral, | ||||
| use crate::{ | ||||
|     error_raporting::ModuleMap, | ||||
|     lexer::{FullToken, Position}, | ||||
|     mir::{ | ||||
|         self, Metadata, NamedVariableRef, StructField, StructType, TypeDefinitionKind, TypeKind, | ||||
|         VagueLiteral, | ||||
|     }, | ||||
| }; | ||||
| 
 | ||||
| /// Context that contains all of the given modules as complete codegenerated
 | ||||
| @ -32,10 +39,24 @@ impl<'ctx> CodegenContext<'ctx> { | ||||
| 
 | ||||
| impl mir::Context { | ||||
|     /// Compile MIR [`Context`] into [`CodegenContext`] containing LLIR.
 | ||||
|     pub fn codegen<'ctx>(&self, context: &'ctx Context) -> CodegenContext<'ctx> { | ||||
|     pub fn codegen<'ctx>( | ||||
|         &self, | ||||
|         context: &'ctx Context, | ||||
|         mod_map: &ModuleMap, | ||||
|     ) -> CodegenContext<'ctx> { | ||||
|         let mut modules = Vec::new(); | ||||
|         for module in &self.modules { | ||||
|             modules.push(module.codegen(context)); | ||||
|             modules.push( | ||||
|                 module.codegen( | ||||
|                     context, | ||||
|                     mod_map | ||||
|                         .module(&module.module_id) | ||||
|                         .unwrap() | ||||
|                         .tokens | ||||
|                         .as_ref() | ||||
|                         .unwrap(), | ||||
|                 ), | ||||
|             ); | ||||
|         } | ||||
|         CodegenContext { context } | ||||
|     } | ||||
| @ -53,16 +74,22 @@ impl<'ctx> std::fmt::Debug for ModuleCodegen<'ctx> { | ||||
| 
 | ||||
| pub struct Scope<'ctx, 'a> { | ||||
|     context: &'ctx Context, | ||||
|     tokens: &'ctx Vec<FullToken>, | ||||
|     module: &'ctx Module<'ctx>, | ||||
|     function: &'ctx Function<'ctx>, | ||||
|     function: &'ctx StackFunction<'ctx>, | ||||
|     block: Block<'ctx>, | ||||
|     types: &'a HashMap<TypeValue, TypeDefinitionKind>, | ||||
|     type_values: &'a HashMap<String, TypeValue>, | ||||
|     functions: &'a HashMap<String, Function<'ctx>>, | ||||
|     functions: &'a HashMap<String, StackFunction<'ctx>>, | ||||
|     stack_values: HashMap<String, StackValue>, | ||||
|     debug: &'ctx DebugInformation, | ||||
|     debug_scope: DebugScopeValue, | ||||
|     debug_const_tys: &'a HashMap<TypeKind, DebugMetadataValue>, | ||||
|     debug_const_tys: &'a HashMap<TypeKind, DebugTypeValue>, | ||||
| } | ||||
| 
 | ||||
| pub struct StackFunction<'ctx> { | ||||
|     ir: Function<'ctx>, | ||||
|     debug: DebugSubprogramValue, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| @ -79,6 +106,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> { | ||||
|     fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> { | ||||
|         Scope { | ||||
|             block, | ||||
|             tokens: self.tokens, | ||||
|             function: self.function, | ||||
|             context: self.context, | ||||
|             module: self.module, | ||||
| @ -126,7 +154,11 @@ impl Default for State { | ||||
| } | ||||
| 
 | ||||
| impl mir::Module { | ||||
|     fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> { | ||||
|     fn codegen<'ctx>( | ||||
|         &self, | ||||
|         context: &'ctx Context, | ||||
|         tokens: &Vec<FullToken>, | ||||
|     ) -> ModuleCodegen<'ctx> { | ||||
|         let mut module = context.module(&self.name, self.is_main); | ||||
| 
 | ||||
|         let (debug, debug_scope) = if let Some(path) = &self.path { | ||||
| @ -147,14 +179,12 @@ impl mir::Module { | ||||
| 
 | ||||
|         debug_const_types.insert( | ||||
|             TypeKind::U32, | ||||
|             debug.metadata( | ||||
|                 &debug_scope, | ||||
|                 DebugMetadata::BasicType(DebugBasicType { | ||||
|                     name: String::from("u32"), | ||||
|                     size_bits: 32, | ||||
|                     encoding: AteEncoding::Unsigned, | ||||
|                 }), | ||||
|             ), | ||||
|             debug.debug_type(DebugTypeData::Basic(DebugBasicType { | ||||
|                 name: String::from("u32"), | ||||
|                 size_bits: 32, | ||||
|                 encoding: DwarfEncoding::Unsigned, | ||||
|                 flags: DwarfFlags, | ||||
|             })), | ||||
|         ); | ||||
| 
 | ||||
|         for typedef in &self.typedefs { | ||||
| @ -209,15 +239,69 @@ impl mir::Module { | ||||
|                     }, | ||||
|                 ), | ||||
|             }; | ||||
|             functions.insert(function.name.clone(), func); | ||||
| 
 | ||||
|             let fn_return_ty = debug_const_types.get(&TypeKind::U32).unwrap(); | ||||
| 
 | ||||
|             let debug_ty = debug.debug_type(DebugTypeData::Subprogram(DebugSubprogramTypeData { | ||||
|                 parameters: vec![*fn_return_ty], | ||||
|                 flags: DwarfFlags, | ||||
|             })); | ||||
| 
 | ||||
|             let subprogram = debug.subprogram(DebugSubprogramData { | ||||
|                 name: function.name.clone(), | ||||
|                 scope: debug_scope.clone(), | ||||
|                 location: DebugLocation { line: 0, column: 0 }, | ||||
|                 ty: debug_ty, | ||||
|                 opts: DebugSubprogramOptionals { | ||||
|                     is_local: !function.is_pub, | ||||
|                     is_definition: true, | ||||
|                     ..DebugSubprogramOptionals::default() | ||||
|                 }, | ||||
|             }); | ||||
| 
 | ||||
|             func.set_debug(subprogram); | ||||
| 
 | ||||
|             functions.insert( | ||||
|                 function.name.clone(), | ||||
|                 StackFunction { | ||||
|                     ir: func, | ||||
|                     debug: subprogram, | ||||
|                 }, | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         for mir_function in &self.functions { | ||||
|             let function = functions.get(&mir_function.name).unwrap(); | ||||
|             let mut entry = function.block("entry"); | ||||
|             let mut entry = function.ir.block("entry"); | ||||
| 
 | ||||
|             let location = match &mir_function.kind { | ||||
|                 mir::FunctionDefinitionKind::Local(_, metadata) => { | ||||
|                     metadata.into_debug(tokens).unwrap() | ||||
|                 } | ||||
|                 mir::FunctionDefinitionKind::Extern(_) => { | ||||
|                     // TODO extern should probably still have a meta
 | ||||
|                     DebugLocation { | ||||
|                         ..Default::default() | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
| 
 | ||||
|             let debug_scope = debug.inner_scope(&debug_scope, location); | ||||
| 
 | ||||
|             let mut stack_values = HashMap::new(); | ||||
|             for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() { | ||||
|                 debug.metadata( | ||||
|                     &debug_scope, | ||||
|                     DebugMetadata::ParamVar(DebugParamVariable { | ||||
|                         name: p_name.clone(), | ||||
|                         arg_idx: i as u32, | ||||
|                         location, | ||||
|                         ty: *debug_const_types.get(&TypeKind::U32).unwrap(), | ||||
|                         always_preserve: true, | ||||
|                         flags: DwarfFlags, | ||||
|                     }), | ||||
|                 ); | ||||
| 
 | ||||
|                 stack_values.insert( | ||||
|                     p_name.clone(), | ||||
|                     StackValue( | ||||
| @ -229,6 +313,7 @@ impl mir::Module { | ||||
| 
 | ||||
|             let mut scope = Scope { | ||||
|                 context, | ||||
|                 tokens, | ||||
|                 module: &module, | ||||
|                 function, | ||||
|                 block: entry, | ||||
| @ -237,9 +322,10 @@ impl mir::Module { | ||||
|                 type_values: &type_values, | ||||
|                 stack_values, | ||||
|                 debug: &debug, | ||||
|                 debug_scope: debug_scope.clone(), | ||||
|                 debug_scope: debug_scope, | ||||
|                 debug_const_tys: &debug_const_types, | ||||
|             }; | ||||
| 
 | ||||
|             match &mir_function.kind { | ||||
|                 mir::FunctionDefinitionKind::Local(block, _) => { | ||||
|                     let state = State::default(); | ||||
| @ -252,23 +338,6 @@ impl mir::Module { | ||||
|                             scope.block.terminate(Term::RetVoid).ok(); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     let fn_return_ty = debug_const_types.get(&TypeKind::U32).unwrap(); | ||||
| 
 | ||||
|                     scope.function.set_metadata(scope.debug.metadata( | ||||
|                         &scope.debug_scope, | ||||
|                         DebugMetadata::Function(DebugFunction { | ||||
|                             scope: scope.debug_scope.clone(), | ||||
|                             name: mir_function.name.clone(), | ||||
|                             linkage_name: String::new(), | ||||
|                             location: DebugLocation { line: 0, column: 0 }, | ||||
|                             return_ty: fn_return_ty.clone(), | ||||
|                             is_local: true, | ||||
|                             is_definition: true, | ||||
|                             is_optimized: false, | ||||
|                             scope_line: 0, | ||||
|                         }), | ||||
|                     )); | ||||
|                 } | ||||
|                 mir::FunctionDefinitionKind::Extern(_) => {} | ||||
|             } | ||||
| @ -444,13 +513,13 @@ impl mir::Expression { | ||||
|                 Some( | ||||
|                     scope | ||||
|                         .block | ||||
|                         .build(Instr::FunctionCall(callee.value(), params)) | ||||
|                         .build(Instr::FunctionCall(callee.ir.value(), params)) | ||||
|                         .unwrap(), | ||||
|                 ) | ||||
|             } | ||||
|             mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state), | ||||
|             mir::ExprKind::Block(block) => { | ||||
|                 let mut inner_scope = scope.with_block(scope.function.block("inner")); | ||||
|                 let mut inner_scope = scope.with_block(scope.function.ir.block("inner")); | ||||
|                 if let Some(ret) = block.codegen(&mut inner_scope, state) { | ||||
|                     inner_scope | ||||
|                         .block | ||||
| @ -587,9 +656,9 @@ impl mir::IfExpression { | ||||
|         let condition = self.0.codegen(scope, state).unwrap(); | ||||
| 
 | ||||
|         // Create blocks
 | ||||
|         let then_b = scope.function.block("then"); | ||||
|         let mut else_b = scope.function.block("else"); | ||||
|         let after_b = scope.function.block("after"); | ||||
|         let then_b = scope.function.ir.block("then"); | ||||
|         let mut else_b = scope.function.ir.block("else"); | ||||
|         let after_b = scope.function.ir.block("after"); | ||||
| 
 | ||||
|         // Store for convenience
 | ||||
|         let then_bb = then_b.value(); | ||||
| @ -709,3 +778,22 @@ impl TypeKind { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Metadata { | ||||
|     pub fn into_debug(&self, tokens: &Vec<FullToken>) -> Option<DebugLocation> { | ||||
|         if let Some((start, _)) = self.into_positions(tokens) { | ||||
|             Some(start.into()) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Into<DebugLocation> for Position { | ||||
|     fn into(self) -> DebugLocation { | ||||
|         DebugLocation { | ||||
|             line: self.1, | ||||
|             column: self.0, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -69,7 +69,7 @@ impl Ord for ErrorKind { | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||
| pub struct ErrModule { | ||||
| pub struct Module { | ||||
|     pub name: String, | ||||
|     pub tokens: Option<Vec<FullToken>>, | ||||
|     pub source: Option<String>, | ||||
| @ -77,7 +77,7 @@ pub struct ErrModule { | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Default)] | ||||
| pub struct ModuleMap { | ||||
|     module_map: HashMap<mir::SourceModuleId, ErrModule>, | ||||
|     module_map: HashMap<mir::SourceModuleId, Module>, | ||||
|     module_counter: mir::SourceModuleId, | ||||
| } | ||||
| 
 | ||||
| @ -86,7 +86,7 @@ impl ModuleMap { | ||||
|         let id = self.module_counter.increment(); | ||||
|         self.module_map.insert( | ||||
|             id, | ||||
|             ErrModule { | ||||
|             Module { | ||||
|                 name: name.into(), | ||||
|                 tokens: None, | ||||
|                 source: None, | ||||
| @ -107,7 +107,7 @@ impl ModuleMap { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_module(&self, id: &mir::SourceModuleId) -> Option<&ErrModule> { | ||||
|     pub fn module(&self, id: &mir::SourceModuleId) -> Option<&Module> { | ||||
|         self.module_map.get(id) | ||||
|     } | ||||
| } | ||||
| @ -177,7 +177,7 @@ impl std::fmt::Display for ReidError { | ||||
|         let mut curr_module = None; | ||||
|         for error in sorted_errors { | ||||
|             let meta = error.get_meta(); | ||||
|             let module = self.map.get_module(&meta.source_module_id).unwrap(); | ||||
|             let module = self.map.module(&meta.source_module_id).unwrap(); | ||||
|             let position = if let Some(tokens) = &module.tokens { | ||||
|                 let range_tokens = meta.range.into_tokens(&tokens); | ||||
| 
 | ||||
|  | ||||
| @ -86,7 +86,7 @@ pub fn compile_module<'map>( | ||||
|     path: Option<PathBuf>, | ||||
|     is_main: bool, | ||||
| ) -> Result<mir::Module, ReidError> { | ||||
|     let module = map.get_module(&module_id).cloned().unwrap(); | ||||
|     let module = map.module(&module_id).cloned().unwrap(); | ||||
| 
 | ||||
|     let mut token_stream = TokenStream::from(&tokens); | ||||
| 
 | ||||
| @ -196,8 +196,8 @@ pub fn compile_and_pass<'map>( | ||||
| 
 | ||||
|     perform_all_passes(&mut mir_context, module_map)?; | ||||
| 
 | ||||
|     let mut context = Context::new(); | ||||
|     let codegen_modules = mir_context.codegen(&mut context); | ||||
|     let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION"))); | ||||
|     let codegen_modules = mir_context.codegen(&mut context, &module_map); | ||||
| 
 | ||||
|     #[cfg(debug_assertions)] | ||||
|     dbg!(&codegen_modules); | ||||
|  | ||||
| @ -87,7 +87,7 @@ impl<'map> Pass for LinkerPass<'map> { | ||||
|         for module in context.modules.drain(..) { | ||||
|             let tokens = self | ||||
|                 .module_map | ||||
|                 .get_module(&module.module_id) | ||||
|                 .module(&module.module_id) | ||||
|                 .unwrap() | ||||
|                 .tokens | ||||
|                 .clone() | ||||
|  | ||||
| @ -4,7 +4,10 @@ | ||||
| 
 | ||||
| use std::{collections::HashMap, path::PathBuf}; | ||||
| 
 | ||||
| use crate::{lexer::Position, token_stream::TokenRange}; | ||||
| use crate::{ | ||||
|     lexer::{FullToken, Position}, | ||||
|     token_stream::TokenRange, | ||||
| }; | ||||
| 
 | ||||
| mod display; | ||||
| pub mod r#impl; | ||||
| @ -36,6 +39,19 @@ impl Metadata { | ||||
|         (self.range.start >= other.range.start && self.range.end <= other.range.end) | ||||
|             || (other.range.start >= self.range.start && other.range.end <= self.range.end) | ||||
|     } | ||||
| 
 | ||||
|     pub fn into_positions(&self, tokens: &Vec<FullToken>) -> Option<(Position, Position)> { | ||||
|         let mut iter = tokens | ||||
|             .iter() | ||||
|             .skip(self.range.start) | ||||
|             .take(self.range.end - self.range.start); | ||||
|         if let Some(first) = iter.next() { | ||||
|             let last = iter.last().unwrap(); | ||||
|             Some((first.position, last.position.add(last.token.len() as u32))) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl std::ops::Add for Metadata { | ||||
| @ -248,7 +264,9 @@ pub struct FunctionCall { | ||||
| #[derive(Debug)] | ||||
| pub struct FunctionDefinition { | ||||
|     pub name: String, | ||||
|     /// Whether this function is visible to outside modules
 | ||||
|     pub is_pub: bool, | ||||
|     /// Whether this module is from an external module, and has been imported
 | ||||
|     pub is_imported: bool, | ||||
|     pub return_type: TypeKind, | ||||
|     pub parameters: Vec<(String, TypeKind)>, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user