From 8d77b76def7a908b4ad2d50df3f3ce9407acae2b Mon Sep 17 00:00:00 2001 From: VonTum Date: Fri, 22 Sep 2023 00:53:02 +0200 Subject: [PATCH] Got Linking errors back --- src/ast.rs | 11 +-- src/dev_aid/lsp.rs | 7 +- src/dev_aid/syntax_highlighting.rs | 10 +- src/errors.rs | 3 + src/linker.rs | 143 ++++++++++++++++++++++------- src/parser.rs | 20 ++-- src/tokenizer.rs | 4 +- 7 files changed, 138 insertions(+), 60 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index f57d57f..93f8dff 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -37,13 +37,6 @@ pub enum LocalOrGlobal { } -#[derive(Debug, Clone)] -pub struct TokenContent { - pub position : usize, - pub text : Range // File position -} - - #[derive(Debug, Clone)] pub enum TypeExpression { Named(usize), // position in referenced globals list @@ -107,6 +100,7 @@ pub enum Statement { #[derive(Debug)] pub struct Location { pub file : FileUUID, + pub name_token : usize, pub span : Span } @@ -119,7 +113,6 @@ pub struct Dependencies { #[derive(Debug)] pub struct Module { - pub name : TokenContent, pub declarations : Vec, pub code : Vec, @@ -127,7 +120,7 @@ pub struct Module { pub dependencies : Dependencies } -pub type GlobalReference = Vec; // token index, and name span +pub type GlobalReference = Vec; // token index, and name span #[derive(Debug)] pub struct ASTRoot { diff --git a/src/dev_aid/lsp.rs b/src/dev_aid/lsp.rs index b5d862d..21cb740 100644 --- a/src/dev_aid/lsp.rs +++ b/src/dev_aid/lsp.rs @@ -343,7 +343,7 @@ fn main_loop( let mut prelink = PreLinker::new(); let uuid = prelink.reserve_file(); - let (full_parse, errors) = perform_full_semantic_parse(&file_data.file_text, uuid); + let (full_parse, parsing_errors) = perform_full_semantic_parse(&file_data.file_text, uuid); let (syntax_highlight, token_positions) = do_syntax_highlight(&file_data, &full_parse); @@ -352,8 +352,13 @@ fn main_loop( id: req.id, result: Some(result), error: None }))?; + prelink.add_reserved_file(uuid, path, file_data.file_text.clone(), full_parse, parsing_errors); + let linker = prelink.link(); + let mut errors = linker.files[uuid].parsing_errors.clone(); + linker.get_linking_errors(uuid, &mut errors); + send_errors_warnings(&connection, errors, params.text_document.uri, &token_positions, &linker)?; }, // TODO ... diff --git a/src/dev_aid/syntax_highlighting.rs b/src/dev_aid/syntax_highlighting.rs index 9858990..cd72db1 100644 --- a/src/dev_aid/syntax_highlighting.rs +++ b/src/dev_aid/syntax_highlighting.rs @@ -105,12 +105,12 @@ fn walk_name_color(ast : &ASTRoot, result : &mut [IDEToken]) { IDEIdentifierType::Unknown }); }); - result[module.name.position].typ = IDETokenType::Identifier(IDEIdentifierType::Interface); + result[module.location.name_token].typ = IDETokenType::Identifier(IDEIdentifierType::Interface); for part_vec in &module.dependencies.global_references { for part_tok in part_vec { - result[part_tok.position].typ = IDETokenType::Identifier(IDEIdentifierType::Type); + result[*part_tok].typ = IDETokenType::Identifier(IDEIdentifierType::Type); } } } @@ -210,10 +210,12 @@ pub fn syntax_highlight_file(file_paths : Vec) { let mut file_cache : FileCache = Default::default(); - for (_file_name, f) in &linker.files { + for (file_uuid, f) in &linker.files { let token_offsets = generate_character_offsets(&f.file_text, &f.tokens); - for err in &f.parsing_errors.errors { + let mut errors = f.parsing_errors.clone(); + linker.get_linking_errors(file_uuid, &mut errors); + for err in errors.errors { err.pretty_print_error(f.parsing_errors.file, &token_offsets, &linker, &mut file_cache); } } diff --git a/src/errors.rs b/src/errors.rs index e24bf08..5c5924c 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -8,12 +8,14 @@ use ariadne::*; use crate::tokenizer::{TokenTypeIdx, get_token_type_name}; +#[derive(Debug,Clone)] pub struct ErrorInfo { pub position : Span, pub file : FileUUID, pub info : String } +#[derive(Debug,Clone)] pub struct ParsingError { pub position : Span, pub reason : String, @@ -92,6 +94,7 @@ pub fn join_expected_list(expected : &[TokenTypeIdx]) -> String { } // Class that collects and manages errors and warnings +#[derive(Clone)] pub struct ErrorCollector { pub errors : Vec, pub file : FileUUID diff --git a/src/linker.rs b/src/linker.rs index 851d2a2..a302fab 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -1,12 +1,12 @@ use std::{collections::HashMap, ops::{IndexMut, Index}, path::PathBuf}; -use crate::{ast::{Module, Location, Dependencies, GlobalReference}, arena_alloc::{ArenaAllocator, UUID}, parser::{FullParseResult, TokenTreeNode}, tokenizer::Token, errors::ErrorCollector}; +use crate::{ast::{Module, Location, Dependencies, GlobalReference, Span}, arena_alloc::{ArenaAllocator, UUID}, parser::{FullParseResult, TokenTreeNode}, tokenizer::Token, errors::{ErrorCollector, error_info}}; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct NamedUUIDMarker; pub type ValueUUID = UUID; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct FileUUIDMarker; pub type FileUUID = UUID; @@ -15,10 +15,32 @@ const BUILTIN_TYPES : [&'static str; 2] = [ "int" ]; +const BUILTIN_VALUES : [&'static str; 2] = [ + "true", + "false" +]; + pub trait Linkable { + fn get_name<'a>(&self, linker : &'a Linker) -> &'a str; + fn get_full_name(&self, linker : &Linker) -> String { + let mut full_name = match self.get_file() { + FileUUID::INVALID => "".to_owned(), + f => linker.files[f].file_path.to_string_lossy().into_owned() + }; + full_name += "::"; + full_name += self.get_name(linker); + full_name + } fn get_location(&self) -> Option<&Location>; fn get_dependencies(&self) -> &Dependencies; fn get_dependencies_mut(&mut self) -> &mut Dependencies; + fn get_file(&self) -> FileUUID { + if let Some(loc) = self.get_location() { + loc.file + } else { + FileUUID::INVALID + } + } } #[derive(Debug)] @@ -39,6 +61,15 @@ pub enum Named { } impl Linkable for NamedValue { + fn get_name<'a>(&self, linker : &'a Linker) -> &'a str { + match self { + NamedValue::Builtin(name) => name, + NamedValue::Module(md) => { + let file = &linker.files[md.location.file]; + file.get_token_text(md.location.name_token) + }, + } + } fn get_dependencies(&self) -> &Dependencies { match self { NamedValue::Builtin(_) => unreachable!(), @@ -66,6 +97,11 @@ impl Linkable for NamedValue { } impl Linkable for NamedType { + fn get_name<'a>(&self, _linker : &'a Linker) -> &'a str { + match self { + NamedType::Builtin(name) => name, + } + } fn get_dependencies(&self) -> &Dependencies { match self { NamedType::Builtin(_) => unreachable!(), @@ -84,6 +120,12 @@ impl Linkable for NamedType { } impl Linkable for Named { + fn get_name<'a>(&self, linker : &'a Linker) -> &'a str { + match self { + Named::Value(v) => v.get_name(linker), + Named::Type(t) => t.get_name(linker), + } + } fn get_dependencies(&self) -> &Dependencies { match self { Named::Value(v) => v.get_dependencies(), @@ -113,6 +155,15 @@ pub struct FileData { pub associated_values : Vec } +impl FileData { + fn get_token_text(&self, token_idx : usize) -> &str { + &self.file_text[self.tokens[token_idx].get_range()] + } + fn get_span_text(&self, token_span : Span) -> &str { + &self.file_text[self.tokens[token_span.0].get_range().start .. self.tokens[token_span.1].get_range().end] + } +} + // All modules in the workspace pub struct Links { globals : ArenaAllocator, @@ -137,13 +188,18 @@ impl Links { let already_exisits = global_namespace.insert(name.to_owned(), id); assert!(already_exisits.is_none()); } + for name in BUILTIN_VALUES { + let id = globals.alloc(Named::Value(NamedValue::Builtin(name))); + let already_exisits = global_namespace.insert(name.to_owned(), id); + assert!(already_exisits.is_none()); + } Links{globals, name_colissions : Vec::new(), global_namespace} } - fn resolve_dependencies(&self, file_text : &str, deps : &[GlobalReference]) -> Vec { + fn resolve_dependencies(&self, file : &FileData, deps : &[GlobalReference]) -> Vec { deps.iter().map(|reference| { - let reference_name_str = &file_text[reference[0].text.clone()]; + let reference_name_str = file.get_token_text(reference[0]); if let Some(found) = self.global_namespace.get(reference_name_str) { *found @@ -184,10 +240,17 @@ impl PreLinker { pub fn add_reserved_file(&mut self, file : FileUUID, file_path : PathBuf, file_text : String, parse_result : FullParseResult, parsing_errors : ErrorCollector) { let mut associated_values = Vec::new(); for md in parse_result.ast.modules { - let module_name = &file_text[md.name.text.clone()]; + let module_name = &file_text[parse_result.tokens[md.location.name_token].get_range()]; let new_module_uuid = self.links.globals.alloc(Named::Value(NamedValue::Module(md))); associated_values.push(new_module_uuid); - self.links.global_namespace.insert(module_name.to_owned(), new_module_uuid); + match self.links.global_namespace.entry(module_name.to_owned()) { + std::collections::hash_map::Entry::Occupied(occ) => { + self.links.name_colissions.push((new_module_uuid, *occ.get())); + }, + std::collections::hash_map::Entry::Vacant(vac) => { + vac.insert(new_module_uuid); + }, + } } self.files.alloc_reservation(file, FileData { file_text, file_path, tokens: parse_result.tokens, token_hierarchy: parse_result.token_hierarchy, parsing_errors, associated_values}); } @@ -197,7 +260,7 @@ impl PreLinker { for (_file_uuid, file) in &mut self.files { for idx in &file.associated_values { let deps = self.links.globals[*idx].get_dependencies(); - let vals_this_refers_to = self.links.resolve_dependencies(&file.file_text, &deps.global_references); + let vals_this_refers_to = self.links.resolve_dependencies(&file, &deps.global_references); let deps_mut = self.links.globals[*idx].get_dependencies_mut(); deps_mut.resolved_globals = vals_this_refers_to; } @@ -205,39 +268,53 @@ impl PreLinker { Linker{links: self.links, files : self.files} } } -/* + impl Linker { - pub fn get_linking_errors(&self, file : FileUUID) -> ErrorCollector { + pub fn get_linking_errors(&self, file_uuid : FileUUID, errors : &mut ErrorCollector) { + let file = &self.files[file_uuid]; + + // Conflicting Declarations for colission in &self.links.name_colissions { - if let Some(location) = self.links.globals[*uuid1].get_location() { - errors.error_with_info(Span::from(md.name.position), format!("Conflicting Module Declaration for the name '{module_name}'"), vec![ - error_info(location.span, location.file_name.clone(), "Conflicting Declaration") + let file_0 = self.links.globals[colission.0].get_file(); + let file_1 = self.links.globals[colission.1].get_file(); + + let (main_object, other_object) = if file_0 == file_uuid { + (colission.0, colission.1) + } else if file_1 == file_uuid { + (colission.1, colission.0) + } else { + continue; + }; + let main_location = self.links.globals[main_object].get_location().unwrap(); // This is always valid, because we're getting the location of an object in the current file + let this_object_name = file.get_token_text(main_location.name_token); + if let Some(other_location) = self.links.globals[other_object].get_location() { + errors.error_with_info(Span::from(main_location.name_token), format!("Conflicting Declaration for the name '{this_object_name}'"), vec![ + error_info(Span::from(other_location.name_token), other_location.file, "Conflicting Declaration") ]); } else { - errors.error_basic(Span::from(md.name.position), format!("Cannot redeclare the builtin '{module_name}'")); + errors.error_basic(Span::from(main_location.name_token), format!("Cannot redeclare the builtin '{this_object_name}'")); } } - - Some(GlobalNamespaceNode::Type(TypeUUID(t))) => { - let found_instead = &self.types[*t]; - let found_full_name = found_instead.get_full_name(); - let infos = if let Some(loc) = found_instead.get_location() { - vec![error_info(loc.span, loc.file_name.clone(), "Defined here")] - } else { - vec![] - }; - errors.error_with_info(reference_span, format!("No {VALUE_NAMES} of the name '{reference_name_str}' was found. Found Type '{found_full_name}'"), infos); - ValueUUID(INVALID_UUID) - } - None => { - errors.error_basic(reference_span, format!("No {VALUE_NAMES} of the name '{reference_name_str}' was found. Did you forget to import it?")); - ValueUUID(INVALID_UUID) + + // References not found + + for val_uuid in &self.files[file_uuid].associated_values { + let object = &self.links.globals[*val_uuid]; + let object_dependencies = object.get_dependencies(); + for (pos, ref_uuid) in object_dependencies.resolved_globals.iter().enumerate() { + if *ref_uuid == ValueUUID::INVALID { + let unresolved_reference = &object_dependencies.global_references[pos]; + let reference_span = Span(unresolved_reference[0], *unresolved_reference.last().unwrap()); + let reference_text = file.get_span_text(reference_span); + errors.error_basic(reference_span, format!("No Value or Type of the name '{reference_text}' was found. Did you forget to import it?")); + } + } } } - pub fn remove(&mut self, file_name : FileName) { + /*pub fn remove(&mut self, file : FileUUID) { } - pub fn relink(&mut self, file_name : FileName, file_text : String, ast : ASTRoot, mut errors : ErrorCollector) { + pub fn relink(&mut self, file : FileUUID, file_text : String, ast : ASTRoot, mut errors : ErrorCollector) { match self.files.entry(file_name) { Entry::Occupied(mut exists) => { let existing_entry = exists.get_mut(); @@ -250,5 +327,5 @@ impl Linker { }, } - } -}*/ + }*/ +} diff --git a/src/parser.rs b/src/parser.rs index 0519446..0072bad 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3,11 +3,17 @@ use num_bigint::BigUint; use crate::{tokenizer::*, errors::*, ast::*, linker::FileUUID}; -use std::{iter::Peekable, str::FromStr}; +use std::{iter::Peekable, str::FromStr, ops::Range}; use core::slice::Iter; use std::mem::replace; +#[derive(Clone)] +struct TokenContent { + position : usize, + text : Range // File position +} + pub enum TokenTreeNode { PlainToken(Token, usize), // Has the index of the given token to the global Token array // Code between '{' and '}', '(' and ')', or '[' and ']' exclusive. Contains sublist of tokens, index of open, index of close bracket @@ -334,7 +340,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { LocalOrGlobal::Local(local_idx) } else { // todo namespacing and shit - let global_ident = vec![TokenContent{position : *pos, text : tok.get_range()}]; + let global_ident = vec![*pos]; LocalOrGlobal::Global(self.add_global_reference(global_ident)) }; (Expression::Named(ident_ref), Span::from(*pos)) @@ -343,12 +349,6 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { let value = &self.file_text[tok.get_range()]; (Expression::Constant(Value::Integer(BigUint::from_str(value).unwrap())), Span::from(*pos)) }, - Some(TokenTreeNode::PlainToken(tok, pos)) if tok.get_type() == kw("true") => { - (Expression::Constant(Value::Bool(true)), Span::from(*pos)) - }, - Some(TokenTreeNode::PlainToken(tok, pos)) if tok.get_type() == kw("false") => { - (Expression::Constant(Value::Bool(false)), Span::from(*pos)) - }, Some(TokenTreeNode::Block(typ, contents, span)) if *typ == kw("(") => { let mut content_token_stream = TokenStream::new(contents, span.0, span.1); if let Some(result) = self.parse_expression(&mut content_token_stream, scope) { @@ -442,7 +442,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { fn try_parse_type(&mut self, token_stream : &mut TokenStream, scope : &LocalVariableContext) -> Option { let first_token = token_stream.eat_is_plain(TOKEN_IDENTIFIER)?; // todo namespacing and shit - let global_ident = vec![first_token.clone()]; + let global_ident = vec![first_token.position]; let mut cur_type = (TypeExpression::Named(self.add_global_reference(global_ident)), Span::from(first_token.position)); // TODO add more type info while let Some((content, block_span)) = token_stream.eat_is_block(kw("[")) { let mut array_index_token_stream = TokenStream::new(content, block_span.0, block_span.1); @@ -663,7 +663,7 @@ impl<'g, 'file> ASTParserContext<'g, 'file> { global_references : replace(&mut self.global_references, Vec::new()), ..Default::default() }; - Some(Module{name, declarations, code, location : Location{span, file : self.errors.file}, dependencies}) + Some(Module{declarations, code, location : Location{file : self.errors.file, name_token : name.position, span}, dependencies}) } fn parse_ast(mut self, outer_token_iter : &mut TokenStream) -> ASTRoot { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index e9174da..6feb0de 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -25,7 +25,7 @@ impl Token { } } -pub const ALL_KEYWORDS : [(&'static str, u8); 17] = [ +pub const ALL_KEYWORDS : [(&'static str, u8); 15] = [ ("template", 0), ("module", 0), ("pipeline", 0), @@ -36,8 +36,6 @@ pub const ALL_KEYWORDS : [(&'static str, u8); 17] = [ ("state", 0), ("if", 0), ("else", 0), - ("true", 0), - ("false", 0), ("while", 0), ("for", 0), ("struct", 0),