Make LSP use a more general analysis structure
This commit is contained in:
parent
dae39bc9d2
commit
8595da0c30
294
reid-lsp/src/analysis.rs
Normal file
294
reid-lsp/src/analysis.rs
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use reid::{
|
||||||
|
ast::lexer::FullToken,
|
||||||
|
compile_module,
|
||||||
|
error_raporting::{ErrorModules, ReidError},
|
||||||
|
mir::{self, Context, FunctionCall, IfExpression, SourceModuleId, StructType, TypeKind, WhileStatement},
|
||||||
|
perform_all_passes,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::CompileResult;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct StaticAnalysis {
|
||||||
|
pub tokens: Vec<FullToken>,
|
||||||
|
pub token_analysis: HashMap<usize, SemanticAnalysis>,
|
||||||
|
pub error: Option<ReidError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SemanticAnalysis {
|
||||||
|
pub ty: Option<TypeKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn analyze(
|
||||||
|
module_id: SourceModuleId,
|
||||||
|
tokens: Vec<FullToken>,
|
||||||
|
path: PathBuf,
|
||||||
|
map: &mut ErrorModules,
|
||||||
|
) -> Result<Option<StaticAnalysis>, ReidError> {
|
||||||
|
let mut token_analysis = HashMap::new();
|
||||||
|
|
||||||
|
let (module, error) = match compile_module(module_id, tokens, map, Some(path.clone()), true)? {
|
||||||
|
Ok(module) => (module, None),
|
||||||
|
Err((m, err)) => (m.process(module_id), Some(err)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let module_id = module.module_id;
|
||||||
|
let mut context = Context::from(vec![module], path.parent().unwrap().to_owned());
|
||||||
|
perform_all_passes(&mut context, map)?;
|
||||||
|
|
||||||
|
for module in context.modules.into_values() {
|
||||||
|
if module.module_id != module_id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for idx in 0..module.tokens.len() {
|
||||||
|
token_analysis.insert(
|
||||||
|
idx,
|
||||||
|
SemanticAnalysis {
|
||||||
|
ty: find_type_in_context(&module, idx),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(Some(StaticAnalysis {
|
||||||
|
tokens: module.tokens,
|
||||||
|
token_analysis: token_analysis,
|
||||||
|
error,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_type_in_context(module: &mir::Module, token_idx: usize) -> Option<TypeKind> {
|
||||||
|
for import in &module.imports {
|
||||||
|
if import.1.contains(token_idx) {
|
||||||
|
return Some(TypeKind::CustomType(mir::CustomTypeKey(
|
||||||
|
"d".to_owned(),
|
||||||
|
SourceModuleId(1),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for typedef in &module.typedefs {
|
||||||
|
if !typedef.meta.contains(token_idx) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match &typedef.kind {
|
||||||
|
mir::TypeDefinitionKind::Struct(StructType(fields)) => {
|
||||||
|
for field in fields {
|
||||||
|
if field.2.contains(token_idx) {
|
||||||
|
return Some(field.1.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for binop in &module.binop_defs {
|
||||||
|
if let Some(meta) = binop.block_meta() {
|
||||||
|
if !meta.contains(token_idx) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return match &binop.fn_kind {
|
||||||
|
mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx),
|
||||||
|
mir::FunctionDefinitionKind::Extern(_) => None,
|
||||||
|
mir::FunctionDefinitionKind::Intrinsic(_) => None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, function) in &module.associated_functions {
|
||||||
|
if !(function.signature() + function.block_meta()).contains(token_idx) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for param in &function.parameters {
|
||||||
|
if param.meta.contains(token_idx) {
|
||||||
|
return Some(param.ty.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return match &function.kind {
|
||||||
|
mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx),
|
||||||
|
mir::FunctionDefinitionKind::Extern(_) => None,
|
||||||
|
mir::FunctionDefinitionKind::Intrinsic(_) => None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for function in &module.functions {
|
||||||
|
if !(function.signature() + function.block_meta()).contains(token_idx) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for param in &function.parameters {
|
||||||
|
if param.meta.contains(token_idx) {
|
||||||
|
return Some(param.ty.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return match &function.kind {
|
||||||
|
mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx),
|
||||||
|
mir::FunctionDefinitionKind::Extern(_) => None,
|
||||||
|
mir::FunctionDefinitionKind::Intrinsic(_) => None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_type_in_block(block: &mir::Block, module_id: SourceModuleId, token_idx: usize) -> Option<TypeKind> {
|
||||||
|
if !block.meta.contains(token_idx) {
|
||||||
|
return Some(TypeKind::Bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
for statement in &block.statements {
|
||||||
|
if !statement.1.contains(token_idx) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match &statement.0 {
|
||||||
|
mir::StmtKind::Let(named_variable_ref, _, expression) => {
|
||||||
|
if named_variable_ref.2.contains(token_idx) {
|
||||||
|
return expression
|
||||||
|
.return_type(&Default::default(), module_id)
|
||||||
|
.ok()
|
||||||
|
.map(|(_, ty)| ty);
|
||||||
|
} else {
|
||||||
|
return find_type_in_expr(&expression, module_id, token_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mir::StmtKind::Set(lhs, rhs) => {
|
||||||
|
return find_type_in_expr(lhs, module_id, token_idx).or(find_type_in_expr(rhs, module_id, token_idx));
|
||||||
|
}
|
||||||
|
mir::StmtKind::Import(_) => {}
|
||||||
|
mir::StmtKind::Expression(expression) => return find_type_in_expr(expression, module_id, token_idx),
|
||||||
|
mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
|
||||||
|
return find_type_in_expr(condition, module_id, token_idx)
|
||||||
|
.or(find_type_in_block(block, module_id, token_idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((_, Some(return_exp))) = &block.return_expression {
|
||||||
|
if let Some(ty) = find_type_in_expr(return_exp, module_id, token_idx) {
|
||||||
|
return Some(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_type_in_expr(expr: &mir::Expression, module_id: SourceModuleId, token_idx: usize) -> Option<TypeKind> {
|
||||||
|
if !expr.1.contains(token_idx) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
match &expr.0 {
|
||||||
|
mir::ExprKind::Variable(named_variable_ref) => Some(named_variable_ref.0.clone()),
|
||||||
|
mir::ExprKind::Indexed(value, type_kind, index_expr) => Some(
|
||||||
|
find_type_in_expr(&value, module_id, token_idx)
|
||||||
|
.or(find_type_in_expr(&index_expr, module_id, token_idx))
|
||||||
|
.unwrap_or(type_kind.clone()),
|
||||||
|
),
|
||||||
|
mir::ExprKind::Accessed(expression, type_kind, _, meta) => {
|
||||||
|
if meta.contains(token_idx) {
|
||||||
|
Some(type_kind.clone())
|
||||||
|
} else {
|
||||||
|
find_type_in_expr(&expression, module_id, token_idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mir::ExprKind::Array(expressions) => {
|
||||||
|
for expr in expressions {
|
||||||
|
if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) {
|
||||||
|
return Some(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
mir::ExprKind::Struct(name, items) => {
|
||||||
|
for (_, expr, meta) in items {
|
||||||
|
if meta.contains(token_idx) {
|
||||||
|
return expr.return_type(&Default::default(), module_id).map(|(_, t)| t).ok();
|
||||||
|
}
|
||||||
|
if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) {
|
||||||
|
return Some(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(TypeKind::CustomType(mir::CustomTypeKey(name.clone(), module_id)))
|
||||||
|
}
|
||||||
|
mir::ExprKind::Literal(literal) => Some(literal.as_type()),
|
||||||
|
mir::ExprKind::BinOp(_, lhs, rhs, type_kind) => {
|
||||||
|
if let Some(ty) = find_type_in_expr(lhs, module_id, token_idx) {
|
||||||
|
return Some(ty);
|
||||||
|
}
|
||||||
|
if let Some(ty) = find_type_in_expr(rhs, module_id, token_idx) {
|
||||||
|
return Some(ty);
|
||||||
|
}
|
||||||
|
Some(type_kind.clone())
|
||||||
|
}
|
||||||
|
mir::ExprKind::FunctionCall(FunctionCall {
|
||||||
|
return_type,
|
||||||
|
parameters,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
for expr in parameters {
|
||||||
|
if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) {
|
||||||
|
return Some(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(return_type.clone())
|
||||||
|
}
|
||||||
|
mir::ExprKind::AssociatedFunctionCall(
|
||||||
|
_,
|
||||||
|
FunctionCall {
|
||||||
|
return_type,
|
||||||
|
parameters,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
for expr in parameters {
|
||||||
|
if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) {
|
||||||
|
return Some(ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(return_type.clone())
|
||||||
|
}
|
||||||
|
mir::ExprKind::If(IfExpression(cond, then_e, else_e)) => find_type_in_expr(&cond, module_id, token_idx)
|
||||||
|
.or(find_type_in_expr(&then_e, module_id, token_idx))
|
||||||
|
.or(else_e.clone().and_then(|e| find_type_in_expr(&e, module_id, token_idx))),
|
||||||
|
mir::ExprKind::Block(block) => find_type_in_block(block, module_id, token_idx),
|
||||||
|
mir::ExprKind::Borrow(expression, mutable) => {
|
||||||
|
if let Some(ty) = find_type_in_expr(&expression, module_id, token_idx) {
|
||||||
|
return Some(ty);
|
||||||
|
}
|
||||||
|
if let Ok(inner) = expression.return_type(&Default::default(), module_id).map(|(_, ty)| ty) {
|
||||||
|
Some(TypeKind::Borrow(Box::new(inner.clone()), *mutable))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mir::ExprKind::Deref(expression) => {
|
||||||
|
if let Some(ty) = find_type_in_expr(&expression, module_id, token_idx) {
|
||||||
|
return Some(ty);
|
||||||
|
}
|
||||||
|
if let Ok(TypeKind::Borrow(inner, _)) =
|
||||||
|
expression.return_type(&Default::default(), module_id).map(|(_, ty)| ty)
|
||||||
|
{
|
||||||
|
Some(*inner.clone())
|
||||||
|
} else {
|
||||||
|
Some(TypeKind::CustomType(mir::CustomTypeKey(
|
||||||
|
"ä".to_owned(),
|
||||||
|
SourceModuleId(1),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mir::ExprKind::CastTo(expression, type_kind) => {
|
||||||
|
Some(find_type_in_expr(&expression, module_id, token_idx).unwrap_or(type_kind.clone()))
|
||||||
|
}
|
||||||
|
mir::ExprKind::GlobalRef(_, type_kind) => Some(type_kind.clone()),
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,28 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use reid::ast::lexer::{FullToken, Position};
|
use reid::ast::lexer::{FullToken, Position};
|
||||||
use reid::error_raporting::{ErrorModules, ReidError};
|
use reid::error_raporting::{self, ErrorModules, ReidError};
|
||||||
use reid::mir::{
|
use reid::mir::{SourceModuleId, TypeKind};
|
||||||
self, Context, FunctionCall, FunctionDefinition, FunctionParam, IfExpression, SourceModuleId, StructType, TypeKind,
|
use reid::parse_module;
|
||||||
WhileStatement,
|
|
||||||
};
|
|
||||||
use reid::{compile_module, parse_module, perform_all_passes};
|
|
||||||
use tower_lsp::lsp_types::{
|
use tower_lsp::lsp_types::{
|
||||||
self, CompletionItem, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic, DiagnosticSeverity,
|
self, CompletionItem, CompletionOptions, CompletionParams, CompletionResponse, Diagnostic, DiagnosticSeverity,
|
||||||
DidChangeTextDocumentParams, DidOpenTextDocumentParams, Hover, HoverContents, HoverParams, HoverProviderCapability,
|
DidChangeTextDocumentParams, DidOpenTextDocumentParams, Hover, HoverContents, HoverParams, HoverProviderCapability,
|
||||||
InitializeParams, InitializeResult, InitializedParams, MarkedString, MarkupContent, MarkupKind, MessageType, OneOf,
|
InitializeParams, InitializeResult, InitializedParams, MarkupContent, MarkupKind, MessageType, OneOf, Range,
|
||||||
Range, ServerCapabilities, TextDocumentItem, TextDocumentSyncCapability, TextDocumentSyncKind,
|
ServerCapabilities, TextDocumentItem, TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
|
||||||
TextDocumentSyncOptions, WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
|
WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
|
||||||
};
|
};
|
||||||
use tower_lsp::{Client, LanguageServer, LspService, Server, jsonrpc};
|
use tower_lsp::{Client, LanguageServer, LspService, Server, jsonrpc};
|
||||||
|
|
||||||
|
use crate::analysis::{StaticAnalysis, analyze};
|
||||||
|
|
||||||
|
mod analysis;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Backend {
|
struct Backend {
|
||||||
client: Client,
|
client: Client,
|
||||||
tokens: DashMap<String, Vec<FullToken>>,
|
analysis: DashMap<String, StaticAnalysis>,
|
||||||
ast: DashMap<String, reid::ast::Module>,
|
ast: DashMap<String, reid::ast::Module>,
|
||||||
types: DashMap<String, DashMap<FullToken, Option<TypeKind>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tower_lsp::async_trait]
|
#[tower_lsp::async_trait]
|
||||||
@ -78,11 +77,11 @@ impl LanguageServer for Backend {
|
|||||||
async fn hover(&self, params: HoverParams) -> jsonrpc::Result<Option<Hover>> {
|
async fn hover(&self, params: HoverParams) -> jsonrpc::Result<Option<Hover>> {
|
||||||
let path = PathBuf::from(params.text_document_position_params.text_document.uri.path());
|
let path = PathBuf::from(params.text_document_position_params.text_document.uri.path());
|
||||||
let file_name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
let file_name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
||||||
let tokens = self.tokens.get(&file_name);
|
let analysis = self.analysis.get(&file_name);
|
||||||
let position = params.text_document_position_params.position;
|
let position = params.text_document_position_params.position;
|
||||||
|
|
||||||
let token = if let Some(tokens) = &tokens {
|
let token = if let Some(analysis) = &analysis {
|
||||||
tokens.iter().find(|tok| {
|
analysis.tokens.iter().enumerate().find(|(_, tok)| {
|
||||||
tok.position.1 == position.line + 1
|
tok.position.1 == position.line + 1
|
||||||
&& (tok.position.0 <= position.character + 1
|
&& (tok.position.0 <= position.character + 1
|
||||||
&& (tok.position.0 + tok.token.len() as u32) > position.character + 1)
|
&& (tok.position.0 + tok.token.len() as u32) > position.character + 1)
|
||||||
@ -91,8 +90,8 @@ impl LanguageServer for Backend {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let (range, ty) = if let Some(token) = token {
|
let (range, ty) = if let Some((idx, token)) = token {
|
||||||
if let Some(possible_ty) = self.types.get(&file_name).unwrap().get(token) {
|
if let Some(possible_ty) = self.analysis.get(&file_name).unwrap().token_analysis.get(&idx) {
|
||||||
let start = token.position;
|
let start = token.position;
|
||||||
let end = token.position.add(token.token.len() as u32);
|
let end = token.position.add(token.token.len() as u32);
|
||||||
let range = Range {
|
let range = Range {
|
||||||
@ -105,7 +104,7 @@ impl LanguageServer for Backend {
|
|||||||
character: (end.0 as i32 - 1).max(0) as u32,
|
character: (end.0 as i32 - 1).max(0) as u32,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if let Some(ty) = possible_ty.clone() {
|
if let Some(ty) = possible_ty.ty.clone() {
|
||||||
(Some(range), format!("{}", ty))
|
(Some(range), format!("{}", ty))
|
||||||
} else {
|
} else {
|
||||||
(Some(range), String::from("None type"))
|
(Some(range), String::from("None type"))
|
||||||
@ -154,50 +153,33 @@ impl Backend {
|
|||||||
let mut map = Default::default();
|
let mut map = Default::default();
|
||||||
let parse_res = parse(¶ms.text, path.clone(), &mut map);
|
let parse_res = parse(¶ms.text, path.clone(), &mut map);
|
||||||
let (tokens, result) = match parse_res {
|
let (tokens, result) = match parse_res {
|
||||||
Ok((module_id, tokens)) => (tokens.clone(), compile(module_id, tokens, path, &mut map)),
|
Ok((module_id, tokens)) => (tokens.clone(), analyze(module_id, tokens, path, &mut map)),
|
||||||
Err(e) => (Vec::new(), Err(e)),
|
Err(e) => (Vec::new(), Err(e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut diagnostics = Vec::new();
|
let mut diagnostics = Vec::new();
|
||||||
match result {
|
match result {
|
||||||
Ok(Some(result)) => {
|
Ok(Some(mut analysis)) => {
|
||||||
self.tokens.insert(file_name.clone(), result.tokens);
|
if let Some(reid_error) = &mut analysis.error {
|
||||||
self.types.insert(file_name.clone(), result.types);
|
self.client
|
||||||
|
.log_message(
|
||||||
|
MessageType::INFO,
|
||||||
|
format!("Successfully compiled despite parsing errors!"),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
reid_error.errors.dedup();
|
||||||
|
for error in &reid_error.errors {
|
||||||
|
diagnostics.push(reid_error_into_diagnostic(error, &tokens));
|
||||||
|
self.client.log_message(MessageType::INFO, format!("{}", error)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.analysis.insert(file_name.clone(), analysis);
|
||||||
}
|
}
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(mut reid_error) => {
|
Err(mut reid_error) => {
|
||||||
reid_error.errors.dedup();
|
reid_error.errors.dedup();
|
||||||
for error in reid_error.errors {
|
for error in &reid_error.errors {
|
||||||
let meta = error.get_meta();
|
diagnostics.push(reid_error_into_diagnostic(error, &tokens));
|
||||||
let positions = meta
|
|
||||||
.range
|
|
||||||
.into_position(&tokens)
|
|
||||||
.unwrap_or((Position(0, 0), Position(0, 0)));
|
|
||||||
self.client.log_message(MessageType::INFO, format!("{:?}", &meta)).await;
|
|
||||||
self.client
|
|
||||||
.log_message(MessageType::INFO, format!("{:?}", &positions))
|
|
||||||
.await;
|
|
||||||
|
|
||||||
diagnostics.push(Diagnostic {
|
|
||||||
range: Range {
|
|
||||||
start: lsp_types::Position {
|
|
||||||
line: ((positions.0.1 as i32) - 1).max(0) as u32,
|
|
||||||
character: ((positions.0.0 as i32) - 1).max(0) as u32,
|
|
||||||
},
|
|
||||||
end: lsp_types::Position {
|
|
||||||
line: ((positions.1.1 as i32) - 1).max(0) as u32,
|
|
||||||
character: ((positions.1.0 as i32) - 1).max(0) as u32,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
severity: Some(DiagnosticSeverity::ERROR),
|
|
||||||
code: None,
|
|
||||||
code_description: None,
|
|
||||||
source: Some(error.get_type_str().to_owned()),
|
|
||||||
message: format!("{}", error),
|
|
||||||
related_information: None,
|
|
||||||
tags: None,
|
|
||||||
data: None,
|
|
||||||
});
|
|
||||||
self.client.log_message(MessageType::INFO, format!("{}", error)).await;
|
self.client.log_message(MessageType::INFO, format!("{}", error)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,6 +191,35 @@ impl Backend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reid_error_into_diagnostic(error: &error_raporting::ErrorKind, tokens: &Vec<FullToken>) -> Diagnostic {
|
||||||
|
let meta = error.get_meta();
|
||||||
|
let positions = meta
|
||||||
|
.range
|
||||||
|
.into_position(&tokens)
|
||||||
|
.unwrap_or((Position(0, 0), Position(0, 0)));
|
||||||
|
|
||||||
|
Diagnostic {
|
||||||
|
range: Range {
|
||||||
|
start: lsp_types::Position {
|
||||||
|
line: ((positions.0.1 as i32) - 1).max(0) as u32,
|
||||||
|
character: ((positions.0.0 as i32) - 1).max(0) as u32,
|
||||||
|
},
|
||||||
|
end: lsp_types::Position {
|
||||||
|
line: ((positions.1.1 as i32) - 1).max(0) as u32,
|
||||||
|
character: ((positions.1.0 as i32) - 1).max(0) as u32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
severity: Some(DiagnosticSeverity::ERROR),
|
||||||
|
code: None,
|
||||||
|
code_description: None,
|
||||||
|
source: Some(error.get_type_str().to_owned()),
|
||||||
|
message: format!("{}", error),
|
||||||
|
related_information: None,
|
||||||
|
tags: None,
|
||||||
|
data: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct CompileResult {
|
struct CompileResult {
|
||||||
tokens: Vec<FullToken>,
|
tokens: Vec<FullToken>,
|
||||||
types: DashMap<FullToken, Option<TypeKind>>,
|
types: DashMap<FullToken, Option<TypeKind>>,
|
||||||
@ -220,36 +231,6 @@ fn parse(source: &str, path: PathBuf, map: &mut ErrorModules) -> Result<(SourceM
|
|||||||
Ok(parse_module(source, file_name.clone(), map)?)
|
Ok(parse_module(source, file_name.clone(), map)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(
|
|
||||||
module_id: SourceModuleId,
|
|
||||||
tokens: Vec<FullToken>,
|
|
||||||
path: PathBuf,
|
|
||||||
map: &mut ErrorModules,
|
|
||||||
) -> Result<Option<CompileResult>, ReidError> {
|
|
||||||
let token_types = DashMap::new();
|
|
||||||
|
|
||||||
let module = compile_module(module_id, tokens, map, Some(path.clone()), true)?;
|
|
||||||
|
|
||||||
let module_id = module.module_id;
|
|
||||||
let mut context = Context::from(vec![module], path.parent().unwrap().to_owned());
|
|
||||||
perform_all_passes(&mut context, map)?;
|
|
||||||
|
|
||||||
for module in context.modules.into_values() {
|
|
||||||
if module.module_id != module_id {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (idx, token) in module.tokens.iter().enumerate() {
|
|
||||||
token_types.insert(token.clone(), find_type_in_context(&module, idx));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(Some(CompileResult {
|
|
||||||
tokens: module.tokens,
|
|
||||||
types: token_types,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let stdin = tokio::io::stdin();
|
let stdin = tokio::io::stdin();
|
||||||
@ -258,239 +239,7 @@ async fn main() {
|
|||||||
let (service, socket) = LspService::new(|client| Backend {
|
let (service, socket) = LspService::new(|client| Backend {
|
||||||
client,
|
client,
|
||||||
ast: DashMap::new(),
|
ast: DashMap::new(),
|
||||||
tokens: DashMap::new(),
|
analysis: DashMap::new(),
|
||||||
types: DashMap::new(),
|
|
||||||
});
|
});
|
||||||
Server::new(stdin, stdout, socket).serve(service).await;
|
Server::new(stdin, stdout, socket).serve(service).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_type_in_context(module: &mir::Module, token_idx: usize) -> Option<TypeKind> {
|
|
||||||
for import in &module.imports {
|
|
||||||
if import.1.contains(token_idx) {
|
|
||||||
return Some(TypeKind::CustomType(mir::CustomTypeKey(
|
|
||||||
"d".to_owned(),
|
|
||||||
SourceModuleId(1),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for typedef in &module.typedefs {
|
|
||||||
if !typedef.meta.contains(token_idx) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
match &typedef.kind {
|
|
||||||
mir::TypeDefinitionKind::Struct(StructType(fields)) => {
|
|
||||||
for field in fields {
|
|
||||||
if field.2.contains(token_idx) {
|
|
||||||
return Some(field.1.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for binop in &module.binop_defs {
|
|
||||||
if let Some(meta) = binop.block_meta() {
|
|
||||||
if !meta.contains(token_idx) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return match &binop.fn_kind {
|
|
||||||
mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx),
|
|
||||||
mir::FunctionDefinitionKind::Extern(_) => None,
|
|
||||||
mir::FunctionDefinitionKind::Intrinsic(_) => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (_, function) in &module.associated_functions {
|
|
||||||
if !(function.signature() + function.block_meta()).contains(token_idx) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for param in &function.parameters {
|
|
||||||
if param.meta.contains(token_idx) {
|
|
||||||
return Some(param.ty.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return match &function.kind {
|
|
||||||
mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx),
|
|
||||||
mir::FunctionDefinitionKind::Extern(_) => None,
|
|
||||||
mir::FunctionDefinitionKind::Intrinsic(_) => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for function in &module.functions {
|
|
||||||
if !(function.signature() + function.block_meta()).contains(token_idx) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for param in &function.parameters {
|
|
||||||
if param.meta.contains(token_idx) {
|
|
||||||
return Some(param.ty.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return match &function.kind {
|
|
||||||
mir::FunctionDefinitionKind::Local(block, _) => find_type_in_block(&block, module.module_id, token_idx),
|
|
||||||
mir::FunctionDefinitionKind::Extern(_) => None,
|
|
||||||
mir::FunctionDefinitionKind::Intrinsic(_) => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_type_in_block(block: &mir::Block, module_id: SourceModuleId, token_idx: usize) -> Option<TypeKind> {
|
|
||||||
if !block.meta.contains(token_idx) {
|
|
||||||
return Some(TypeKind::Bool);
|
|
||||||
}
|
|
||||||
|
|
||||||
for statement in &block.statements {
|
|
||||||
if !statement.1.contains(token_idx) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
match &statement.0 {
|
|
||||||
mir::StmtKind::Let(named_variable_ref, _, expression) => {
|
|
||||||
if named_variable_ref.2.contains(token_idx) {
|
|
||||||
return expression
|
|
||||||
.return_type(&Default::default(), module_id)
|
|
||||||
.ok()
|
|
||||||
.map(|(_, ty)| ty);
|
|
||||||
} else {
|
|
||||||
return find_type_in_expr(&expression, module_id, token_idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mir::StmtKind::Set(lhs, rhs) => {
|
|
||||||
return find_type_in_expr(lhs, module_id, token_idx).or(find_type_in_expr(rhs, module_id, token_idx));
|
|
||||||
}
|
|
||||||
mir::StmtKind::Import(_) => {}
|
|
||||||
mir::StmtKind::Expression(expression) => return find_type_in_expr(expression, module_id, token_idx),
|
|
||||||
mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
|
|
||||||
return find_type_in_expr(condition, module_id, token_idx)
|
|
||||||
.or(find_type_in_block(block, module_id, token_idx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((_, Some(return_exp))) = &block.return_expression {
|
|
||||||
if let Some(ty) = find_type_in_expr(return_exp, module_id, token_idx) {
|
|
||||||
return Some(ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_type_in_expr(expr: &mir::Expression, module_id: SourceModuleId, token_idx: usize) -> Option<TypeKind> {
|
|
||||||
if !expr.1.contains(token_idx) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
match &expr.0 {
|
|
||||||
mir::ExprKind::Variable(named_variable_ref) => Some(named_variable_ref.0.clone()),
|
|
||||||
mir::ExprKind::Indexed(value, type_kind, index_expr) => Some(
|
|
||||||
find_type_in_expr(&value, module_id, token_idx)
|
|
||||||
.or(find_type_in_expr(&index_expr, module_id, token_idx))
|
|
||||||
.unwrap_or(type_kind.clone()),
|
|
||||||
),
|
|
||||||
mir::ExprKind::Accessed(expression, type_kind, _, meta) => {
|
|
||||||
if meta.contains(token_idx) {
|
|
||||||
Some(type_kind.clone())
|
|
||||||
} else {
|
|
||||||
find_type_in_expr(&expression, module_id, token_idx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mir::ExprKind::Array(expressions) => {
|
|
||||||
for expr in expressions {
|
|
||||||
if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) {
|
|
||||||
return Some(ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
mir::ExprKind::Struct(name, items) => {
|
|
||||||
for (_, expr, meta) in items {
|
|
||||||
if meta.contains(token_idx) {
|
|
||||||
return expr.return_type(&Default::default(), module_id).map(|(_, t)| t).ok();
|
|
||||||
}
|
|
||||||
if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) {
|
|
||||||
return Some(ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(TypeKind::CustomType(mir::CustomTypeKey(name.clone(), module_id)))
|
|
||||||
}
|
|
||||||
mir::ExprKind::Literal(literal) => Some(literal.as_type()),
|
|
||||||
mir::ExprKind::BinOp(_, lhs, rhs, type_kind) => {
|
|
||||||
if let Some(ty) = find_type_in_expr(lhs, module_id, token_idx) {
|
|
||||||
return Some(ty);
|
|
||||||
}
|
|
||||||
if let Some(ty) = find_type_in_expr(rhs, module_id, token_idx) {
|
|
||||||
return Some(ty);
|
|
||||||
}
|
|
||||||
Some(type_kind.clone())
|
|
||||||
}
|
|
||||||
mir::ExprKind::FunctionCall(FunctionCall {
|
|
||||||
return_type,
|
|
||||||
parameters,
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
for expr in parameters {
|
|
||||||
if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) {
|
|
||||||
return Some(ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(return_type.clone())
|
|
||||||
}
|
|
||||||
mir::ExprKind::AssociatedFunctionCall(
|
|
||||||
_,
|
|
||||||
FunctionCall {
|
|
||||||
return_type,
|
|
||||||
parameters,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
) => {
|
|
||||||
for expr in parameters {
|
|
||||||
if let Some(ty) = find_type_in_expr(expr, module_id, token_idx) {
|
|
||||||
return Some(ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(return_type.clone())
|
|
||||||
}
|
|
||||||
mir::ExprKind::If(IfExpression(cond, then_e, else_e)) => find_type_in_expr(&cond, module_id, token_idx)
|
|
||||||
.or(find_type_in_expr(&then_e, module_id, token_idx))
|
|
||||||
.or(else_e.clone().and_then(|e| find_type_in_expr(&e, module_id, token_idx))),
|
|
||||||
mir::ExprKind::Block(block) => find_type_in_block(block, module_id, token_idx),
|
|
||||||
mir::ExprKind::Borrow(expression, mutable) => {
|
|
||||||
if let Some(ty) = find_type_in_expr(&expression, module_id, token_idx) {
|
|
||||||
return Some(ty);
|
|
||||||
}
|
|
||||||
if let Ok(inner) = expression.return_type(&Default::default(), module_id).map(|(_, ty)| ty) {
|
|
||||||
Some(TypeKind::Borrow(Box::new(inner.clone()), *mutable))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mir::ExprKind::Deref(expression) => {
|
|
||||||
if let Some(ty) = find_type_in_expr(&expression, module_id, token_idx) {
|
|
||||||
return Some(ty);
|
|
||||||
}
|
|
||||||
if let Ok(TypeKind::Borrow(inner, _)) =
|
|
||||||
expression.return_type(&Default::default(), module_id).map(|(_, ty)| ty)
|
|
||||||
{
|
|
||||||
Some(*inner.clone())
|
|
||||||
} else {
|
|
||||||
Some(TypeKind::CustomType(mir::CustomTypeKey(
|
|
||||||
"ä".to_owned(),
|
|
||||||
SourceModuleId(1),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mir::ExprKind::CastTo(expression, type_kind) => {
|
|
||||||
Some(find_type_in_expr(&expression, module_id, token_idx).unwrap_or(type_kind.clone()))
|
|
||||||
}
|
|
||||||
mir::ExprKind::GlobalRef(_, type_kind) => Some(type_kind.clone()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -610,7 +610,7 @@ impl Parse for LetStatement {
|
|||||||
stream.expect(Token::Equals)?;
|
stream.expect(Token::Equals)?;
|
||||||
|
|
||||||
let expression = stream.parse()?;
|
let expression = stream.parse()?;
|
||||||
stream.expect(Token::Semi)?;
|
stream.expect_nonfatal(Token::Semi);
|
||||||
Ok(LetStatement {
|
Ok(LetStatement {
|
||||||
name: variable,
|
name: variable,
|
||||||
ty,
|
ty,
|
||||||
@ -643,7 +643,7 @@ impl Parse for ImportStatement {
|
|||||||
Err(stream.expected_err("identifier")?)?
|
Err(stream.expected_err("identifier")?)?
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.expect(Token::Semi)?;
|
stream.expect_nonfatal(Token::Semi);
|
||||||
|
|
||||||
Ok(ImportStatement(import_list, stream.get_range().unwrap()))
|
Ok(ImportStatement(import_list, stream.get_range().unwrap()))
|
||||||
}
|
}
|
||||||
@ -788,7 +788,7 @@ impl Parse for Block {
|
|||||||
// if semicolon is missing.
|
// if semicolon is missing.
|
||||||
if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) {
|
if !matches!(e, Expression(ExpressionKind::IfExpr(_), _)) {
|
||||||
// In theory could ignore the missing semicolon..
|
// In theory could ignore the missing semicolon..
|
||||||
return Err(stream.expected_err("semicolon to complete statement")?);
|
stream.expected_err_nonfatal("semicolon to complete statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
statements.push(BlockLevelStatement::Expression(e));
|
statements.push(BlockLevelStatement::Expression(e));
|
||||||
@ -997,7 +997,7 @@ impl Parse for SetStatement {
|
|||||||
let var_ref = stream.parse()?;
|
let var_ref = stream.parse()?;
|
||||||
stream.expect(Token::Equals)?;
|
stream.expect(Token::Equals)?;
|
||||||
let expr = stream.parse()?;
|
let expr = stream.parse()?;
|
||||||
stream.expect(Token::Semi)?;
|
stream.expect_nonfatal(Token::Semi);
|
||||||
Ok(SetStatement(var_ref, expr, stream.get_range().unwrap()))
|
Ok(SetStatement(var_ref, expr, stream.get_range().unwrap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1038,7 +1038,7 @@ impl Parse for TopLevelStatement {
|
|||||||
stream.next(); // Consume Extern
|
stream.next(); // Consume Extern
|
||||||
stream.expect(Token::FnKeyword)?;
|
stream.expect(Token::FnKeyword)?;
|
||||||
let extern_fn = Stmt::ExternFunction(stream.parse()?);
|
let extern_fn = Stmt::ExternFunction(stream.parse()?);
|
||||||
stream.expect(Token::Semi)?;
|
stream.expect_nonfatal(Token::Semi);
|
||||||
extern_fn
|
extern_fn
|
||||||
}
|
}
|
||||||
Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?),
|
Some(Token::FnKeyword) | Some(Token::PubKeyword) => Stmt::FunctionDefinition(stream.parse()?),
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
//! Contains relevant code for parsing tokens received from
|
//! Contains relevant code for parsing tokens received from
|
||||||
//! Lexing/Tokenizing-stage.
|
//! Lexing/Tokenizing-stage.
|
||||||
|
|
||||||
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::parse::Parse,
|
ast::parse::Parse,
|
||||||
lexer::{FullToken, Token},
|
lexer::{FullToken, Token},
|
||||||
@ -12,6 +14,7 @@ use crate::{
|
|||||||
pub struct TokenStream<'a, 'b> {
|
pub struct TokenStream<'a, 'b> {
|
||||||
ref_position: Option<&'b mut usize>,
|
ref_position: Option<&'b mut usize>,
|
||||||
tokens: &'a [FullToken],
|
tokens: &'a [FullToken],
|
||||||
|
errors: Rc<RefCell<Vec<Error>>>,
|
||||||
pub position: usize,
|
pub position: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,6 +23,7 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
TokenStream {
|
TokenStream {
|
||||||
ref_position: None,
|
ref_position: None,
|
||||||
tokens,
|
tokens,
|
||||||
|
errors: Rc::new(RefCell::new(Vec::new())),
|
||||||
position: 0,
|
position: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,6 +42,16 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns expected-error for the next token in-line. Useful in conjunction
|
||||||
|
/// with [`TokenStream::peek`]
|
||||||
|
pub fn expected_err_nonfatal<T: Into<String>>(&mut self, expected: T) {
|
||||||
|
let err = match self.expected_err(expected) {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(e) => e,
|
||||||
|
};
|
||||||
|
self.errors.borrow_mut().push(err);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns expected-error for the previous token that was already consumed.
|
/// Returns expected-error for the previous token that was already consumed.
|
||||||
/// Useful in conjunction with [`TokenStream::next`]
|
/// Useful in conjunction with [`TokenStream::next`]
|
||||||
pub fn expecting_err<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> {
|
pub fn expecting_err<T: Into<String>>(&mut self, expected: T) -> Result<Error, Error> {
|
||||||
@ -50,6 +64,16 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns expected-error for the previous token that was already consumed.
|
||||||
|
/// Useful in conjunction with [`TokenStream::next`]
|
||||||
|
pub fn expecting_err_nonfatal<T: Into<String>>(&mut self, expected: T) {
|
||||||
|
let err = match self.expecting_err(expected) {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(e) => e,
|
||||||
|
};
|
||||||
|
self.errors.borrow_mut().push(err);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expect(&mut self, token: Token) -> Result<(), Error> {
|
pub fn expect(&mut self, token: Token) -> Result<(), Error> {
|
||||||
if let (pos, Some(peeked)) = self.next_token(self.position) {
|
if let (pos, Some(peeked)) = self.next_token(self.position) {
|
||||||
if token == peeked.token {
|
if token == peeked.token {
|
||||||
@ -63,6 +87,18 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expect_nonfatal(&mut self, token: Token) {
|
||||||
|
if let (pos, Some(peeked)) = self.next_token(self.position) {
|
||||||
|
if token == peeked.token {
|
||||||
|
self.position = pos + 1;
|
||||||
|
} else {
|
||||||
|
self.expecting_err_nonfatal(token);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.expecting_err_nonfatal(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) -> Option<Token> {
|
pub fn next(&mut self) -> Option<Token> {
|
||||||
let (position, token) = self.next_token(self.position);
|
let (position, token) = self.next_token(self.position);
|
||||||
self.position = position + 1;
|
self.position = position + 1;
|
||||||
@ -147,6 +183,7 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
let clone = TokenStream {
|
let clone = TokenStream {
|
||||||
ref_position: Some(&mut ref_pos),
|
ref_position: Some(&mut ref_pos),
|
||||||
tokens: self.tokens,
|
tokens: self.tokens,
|
||||||
|
errors: self.errors.clone(),
|
||||||
position,
|
position,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -197,6 +234,10 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
}
|
}
|
||||||
(from, self.tokens.get(from))
|
(from, self.tokens.get(from))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn errors(&self) -> Vec<Error> {
|
||||||
|
self.errors.borrow().clone().clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TokenStream<'_, '_> {
|
impl Drop for TokenStream<'_, '_> {
|
||||||
|
@ -1326,8 +1326,6 @@ impl mir::Expression {
|
|||||||
(val.1.clone(), type_kind.clone())
|
(val.1.clone(), type_kind.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
dbg!(&ty, type_kind);
|
|
||||||
|
|
||||||
match (&ty, type_kind) {
|
match (&ty, type_kind) {
|
||||||
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Some(StackValue(
|
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Some(StackValue(
|
||||||
val.0.derive(
|
val.0.derive(
|
||||||
|
@ -105,7 +105,7 @@ pub fn compile_module<'map>(
|
|||||||
map: &'map mut ErrorModules,
|
map: &'map mut ErrorModules,
|
||||||
path: Option<PathBuf>,
|
path: Option<PathBuf>,
|
||||||
is_main: bool,
|
is_main: bool,
|
||||||
) -> Result<mir::Module, ReidError> {
|
) -> Result<Result<mir::Module, (ast::Module, ReidError)>, ReidError> {
|
||||||
let module = map.module(&module_id).cloned().unwrap();
|
let module = map.module(&module_id).cloned().unwrap();
|
||||||
|
|
||||||
let mut token_stream = TokenStream::from(&tokens);
|
let mut token_stream = TokenStream::from(&tokens);
|
||||||
@ -117,6 +117,8 @@ pub fn compile_module<'map>(
|
|||||||
statements.push(statement);
|
statements.push(statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let errors = token_stream.errors();
|
||||||
|
|
||||||
drop(token_stream);
|
drop(token_stream);
|
||||||
|
|
||||||
let ast_module = ast::Module {
|
let ast_module = ast::Module {
|
||||||
@ -127,11 +129,33 @@ pub fn compile_module<'map>(
|
|||||||
is_main,
|
is_main,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if errors.len() > 0 {
|
||||||
|
return Ok(Err((
|
||||||
|
ast_module,
|
||||||
|
ReidError::from_kind(
|
||||||
|
errors
|
||||||
|
.into_iter()
|
||||||
|
.map(|e| {
|
||||||
|
error_raporting::ErrorKind::from(mir::pass::Error {
|
||||||
|
metadata: mir::Metadata {
|
||||||
|
source_module_id: module_id,
|
||||||
|
range: *e.get_range().unwrap_or(&Default::default()),
|
||||||
|
position: None,
|
||||||
|
},
|
||||||
|
kind: e,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
map.clone(),
|
||||||
|
),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
#[cfg(feature = "log_output")]
|
#[cfg(feature = "log_output")]
|
||||||
dbg!(&ast_module);
|
dbg!(&ast_module);
|
||||||
|
|
||||||
Ok(ast_module.process(module_id))
|
Ok(Ok(ast_module.process(module_id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform_all_passes<'map>(
|
pub fn perform_all_passes<'map>(
|
||||||
@ -293,7 +317,7 @@ pub fn compile_and_pass<'map>(
|
|||||||
let name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
let name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
||||||
|
|
||||||
let (id, tokens) = parse_module(source, name, module_map)?;
|
let (id, tokens) = parse_module(source, name, module_map)?;
|
||||||
let module = compile_module(id, tokens, module_map, Some(path.clone()), true)?;
|
let module = compile_module(id, tokens, module_map, Some(path.clone()), true)?.map_err(|(_, e)| e)?;
|
||||||
|
|
||||||
let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned());
|
let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned());
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ pub enum ErrorKind {
|
|||||||
|
|
||||||
pub fn compile_std(module_map: &mut ErrorModules) -> Result<Module, ReidError> {
|
pub fn compile_std(module_map: &mut ErrorModules) -> Result<Module, ReidError> {
|
||||||
let (id, tokens) = parse_module(STD_SOURCE, STD_NAME, module_map)?;
|
let (id, tokens) = parse_module(STD_SOURCE, STD_NAME, module_map)?;
|
||||||
let module = compile_module(id, tokens, module_map, None, false)?;
|
let module = compile_module(id, tokens, module_map, None, false)?.map_err(|(_, e)| e)?;
|
||||||
|
|
||||||
let module_id = module.module_id;
|
let module_id = module.module_id;
|
||||||
let mut mir_context = super::Context::from(vec![module], Default::default());
|
let mut mir_context = super::Context::from(vec![module], Default::default());
|
||||||
@ -156,21 +156,33 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match compile_module(id, tokens, &mut self.module_map, Some(file_path), false) {
|
match compile_module(id, tokens, &mut self.module_map, Some(file_path), false) {
|
||||||
Ok(imported_module) => {
|
Ok(res) => match res {
|
||||||
if imported_module.is_main {
|
Ok(imported_module) => {
|
||||||
|
if imported_module.is_main {
|
||||||
|
state.ok::<_, Infallible>(
|
||||||
|
Err(ErrorKind::TriedLinkingMain(module_name.clone())),
|
||||||
|
import.1,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let module_id = imported_module.module_id;
|
||||||
|
module_ids.insert(imported_module.name.clone(), imported_module.module_id);
|
||||||
|
modules.insert(module_id, Rc::new(RefCell::new(imported_module)));
|
||||||
|
let imported = modules.get_mut(&module_id).unwrap();
|
||||||
|
modules_to_process.push(imported.clone());
|
||||||
|
imported
|
||||||
|
}
|
||||||
|
Err((_, err)) => {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::TriedLinkingMain(module_name.clone())),
|
Err(ErrorKind::ModuleCompilationError(
|
||||||
|
module_name.clone(),
|
||||||
|
format!("{}", err),
|
||||||
|
)),
|
||||||
import.1,
|
import.1,
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let module_id = imported_module.module_id;
|
},
|
||||||
module_ids.insert(imported_module.name.clone(), imported_module.module_id);
|
|
||||||
modules.insert(module_id, Rc::new(RefCell::new(imported_module)));
|
|
||||||
let imported = modules.get_mut(&module_id).unwrap();
|
|
||||||
modules_to_process.push(imported.clone());
|
|
||||||
imported
|
|
||||||
}
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
state.ok::<_, Infallible>(
|
state.ok::<_, Infallible>(
|
||||||
Err(ErrorKind::ModuleCompilationError(
|
Err(ErrorKind::ModuleCompilationError(
|
||||||
|
@ -16,7 +16,7 @@ fn test_compile(source: &str, name: &str) -> CompileOutput {
|
|||||||
let mut map = Default::default();
|
let mut map = Default::default();
|
||||||
let (id, tokens) = assert_err(parse_module(source, name, &mut map));
|
let (id, tokens) = assert_err(parse_module(source, name, &mut map));
|
||||||
|
|
||||||
let module = assert_err(compile_module(id, tokens, &mut map, None, true));
|
let module = assert_err(assert_err(compile_module(id, tokens, &mut map, None, true)).map_err(|(_, e)| e));
|
||||||
let mut mir_context = mir::Context::from(vec![module], Default::default());
|
let mut mir_context = mir::Context::from(vec![module], Default::default());
|
||||||
assert_err(perform_all_passes(&mut mir_context, &mut map));
|
assert_err(perform_all_passes(&mut mir_context, &mut map));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user