Skip to content

Commit

Permalink
Got Linking errors back
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Sep 21, 2023
1 parent bb0fe69 commit 8d77b76
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 60 deletions.
11 changes: 2 additions & 9 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,6 @@ pub enum LocalOrGlobal {
}


#[derive(Debug, Clone)]
pub struct TokenContent {
pub position : usize,
pub text : Range<usize> // File position
}


#[derive(Debug, Clone)]
pub enum TypeExpression {
Named(usize), // position in referenced globals list
Expand Down Expand Up @@ -107,6 +100,7 @@ pub enum Statement {
#[derive(Debug)]
pub struct Location {
pub file : FileUUID,
pub name_token : usize,
pub span : Span
}

Expand All @@ -119,15 +113,14 @@ pub struct Dependencies {

#[derive(Debug)]
pub struct Module {
pub name : TokenContent,
pub declarations : Vec<SignalDeclaration>,
pub code : Vec<SpanStatement>,

pub location : Location,
pub dependencies : Dependencies
}

pub type GlobalReference = Vec<TokenContent>; // token index, and name span
pub type GlobalReference = Vec<usize>; // token index, and name span

#[derive(Debug)]
pub struct ASTRoot {
Expand Down
7 changes: 6 additions & 1 deletion src/dev_aid/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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 ...
Expand Down
10 changes: 6 additions & 4 deletions src/dev_aid/syntax_highlighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -210,10 +210,12 @@ pub fn syntax_highlight_file(file_paths : Vec<PathBuf>) {

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);
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<ParsingError>,
pub file : FileUUID
Expand Down
143 changes: 110 additions & 33 deletions src/linker.rs
Original file line number Diff line number Diff line change
@@ -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<NamedUUIDMarker>;

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FileUUIDMarker;
pub type FileUUID = UUID<FileUUIDMarker>;

Expand All @@ -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 => "<builtin>".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)]
Expand All @@ -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!(),
Expand Down Expand Up @@ -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!(),
Expand All @@ -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(),
Expand Down Expand Up @@ -113,6 +155,15 @@ pub struct FileData {
pub associated_values : Vec<ValueUUID>
}

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<Named, NamedUUIDMarker>,
Expand All @@ -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<ValueUUID> {
fn resolve_dependencies(&self, file : &FileData, deps : &[GlobalReference]) -> Vec<ValueUUID> {
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
Expand Down Expand Up @@ -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});
}
Expand All @@ -197,47 +260,61 @@ 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;
}
}
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();
Expand All @@ -250,5 +327,5 @@ impl Linker {
},
}
}
}*/
}*/
}
Loading

0 comments on commit 8d77b76

Please sign in to comment.