feat: publish errors as lsp diagnostic messages
This commit is contained in:
parent
f089eff97d
commit
bff99b0cf2
|
@ -98,6 +98,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -77,6 +77,7 @@ pub enum ErrorKind {
|
||||||
#[error("unclosed {start}")]
|
#[error("unclosed {start}")]
|
||||||
Unclosed {
|
Unclosed {
|
||||||
start: Pattern,
|
start: Pattern,
|
||||||
|
#[label]
|
||||||
before_span: Span,
|
before_span: Span,
|
||||||
before: Option<Pattern>,
|
before: Option<Pattern>,
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,7 +55,9 @@ pub enum Error {
|
||||||
|
|
||||||
#[error("duplicate type name {name}")]
|
#[error("duplicate type name {name}")]
|
||||||
DuplicateTypeName {
|
DuplicateTypeName {
|
||||||
|
#[label]
|
||||||
location: Span,
|
location: Span,
|
||||||
|
#[label]
|
||||||
previous_location: Span,
|
previous_location: Span,
|
||||||
name: String,
|
name: String,
|
||||||
},
|
},
|
||||||
|
@ -79,6 +81,7 @@ pub enum Error {
|
||||||
|
|
||||||
#[error("{name} has incorrect type arity expected {expected} but given {given}")]
|
#[error("{name} has incorrect type arity expected {expected} but given {given}")]
|
||||||
IncorrectTypeArity {
|
IncorrectTypeArity {
|
||||||
|
#[label]
|
||||||
location: Span,
|
location: Span,
|
||||||
name: String,
|
name: String,
|
||||||
expected: usize,
|
expected: usize,
|
||||||
|
|
|
@ -20,3 +20,4 @@ serde = "1.0.147"
|
||||||
serde_json = "1.0.87"
|
serde_json = "1.0.87"
|
||||||
thiserror = "1.0.37"
|
thiserror = "1.0.37"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
|
url = "2.3.1"
|
||||||
|
|
|
@ -26,4 +26,7 @@ pub enum Error {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
#[diagnostic(code(aiken::lsp::send))]
|
#[diagnostic(code(aiken::lsp::send))]
|
||||||
Send(#[from] SendError<Message>),
|
Send(#[from] SendError<Message>),
|
||||||
|
#[error(transparent)]
|
||||||
|
#[diagnostic(code(aiken::lsp::send))]
|
||||||
|
PathToUri(#[from] url::ParseError),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ use lsp_types::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
mod line_numbers;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
@ -48,7 +49,7 @@ fn capabilities() -> ServerCapabilities {
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
definition_provider: Some(OneOf::Left(true)),
|
// definition_provider: Some(OneOf::Left(true)),
|
||||||
document_formatting_provider: Some(OneOf::Left(true)),
|
document_formatting_provider: Some(OneOf::Left(true)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LineNumbers {
|
||||||
|
line_starts: Vec<usize>,
|
||||||
|
length: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LineNumbers {
|
||||||
|
pub fn new(src: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
length: src.len() as usize,
|
||||||
|
line_starts: std::iter::once(0)
|
||||||
|
.chain(src.match_indices('\n').map(|(i, _)| i + 1))
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the line number for a byte index
|
||||||
|
pub fn line_number(&self, byte_index: usize) -> usize {
|
||||||
|
self.line_starts
|
||||||
|
.binary_search(&byte_index)
|
||||||
|
.unwrap_or_else(|next_line| next_line - 1) as usize
|
||||||
|
+ 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle unicode characters that may be more than 1 byte in width
|
||||||
|
pub fn line_and_column_number(&self, byte_index: usize) -> LineColumn {
|
||||||
|
let line = self.line_number(byte_index);
|
||||||
|
let column = byte_index
|
||||||
|
- self
|
||||||
|
.line_starts
|
||||||
|
.get(line as usize - 1)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or_default()
|
||||||
|
+ 1;
|
||||||
|
LineColumn { line, column }
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle unicode characters that may be more than 1 byte in width
|
||||||
|
/// 0 indexed line and character to byte index
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn byte_index(&self, line: usize, character: usize) -> usize {
|
||||||
|
match self.line_starts.get((line) as usize) {
|
||||||
|
Some(line_index) => *line_index + character,
|
||||||
|
None => self.length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct LineColumn {
|
||||||
|
pub line: usize,
|
||||||
|
pub column: usize,
|
||||||
|
}
|
|
@ -1,15 +1,21 @@
|
||||||
use std::{collections::HashMap, fs, path::Path};
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
error::Error,
|
||||||
|
fs,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
use aiken_lang::{ast::ModuleKind, parser};
|
use aiken_lang::{ast::ModuleKind, parser};
|
||||||
use aiken_project::config;
|
use aiken_project::{config, error::Error as ProjectError};
|
||||||
use lsp_server::{Connection, Message};
|
use lsp_server::{Connection, Message};
|
||||||
use lsp_types::{
|
use lsp_types::{
|
||||||
notification::{DidChangeTextDocument, Notification},
|
notification::{DidChangeTextDocument, Notification, PublishDiagnostics, ShowMessage},
|
||||||
request::{Formatting, Request},
|
request::{Formatting, Request},
|
||||||
DocumentFormattingParams, InitializeParams, TextEdit,
|
DocumentFormattingParams, InitializeParams, TextEdit,
|
||||||
};
|
};
|
||||||
|
use miette::Diagnostic;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::{error::Error as ServerError, line_numbers::LineNumbers};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
|
@ -19,6 +25,18 @@ pub struct Server {
|
||||||
edited: HashMap<String, String>,
|
edited: HashMap<String, String>,
|
||||||
|
|
||||||
initialize_params: InitializeParams,
|
initialize_params: InitializeParams,
|
||||||
|
|
||||||
|
/// Files for which there are active diagnostics
|
||||||
|
published_diagnostics: HashSet<lsp_types::Url>,
|
||||||
|
|
||||||
|
/// Diagnostics that have been emitted by the compiler but not yet published
|
||||||
|
/// to the client
|
||||||
|
stored_diagnostics: HashMap<PathBuf, Vec<lsp_types::Diagnostic>>,
|
||||||
|
|
||||||
|
/// Diagnostics that have been emitted by the compiler but not yet published
|
||||||
|
/// to the client. These are likely locationless Aiken diagnostics, as LSP
|
||||||
|
/// diagnostics always need a location.
|
||||||
|
stored_messages: Vec<lsp_types::ShowMessageParams>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
|
@ -27,10 +45,15 @@ impl Server {
|
||||||
config,
|
config,
|
||||||
edited: HashMap::new(),
|
edited: HashMap::new(),
|
||||||
initialize_params,
|
initialize_params,
|
||||||
|
published_diagnostics: HashSet::new(),
|
||||||
|
stored_diagnostics: HashMap::new(),
|
||||||
|
stored_messages: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn listen(&mut self, connection: Connection) -> Result<(), Error> {
|
pub fn listen(&mut self, connection: Connection) -> Result<(), ServerError> {
|
||||||
|
self.publish_stored_diagnostics(&connection)?;
|
||||||
|
|
||||||
for msg in &connection.receiver {
|
for msg in &connection.receiver {
|
||||||
tracing::debug!("Got message: {:#?}", msg);
|
tracing::debug!("Got message: {:#?}", msg);
|
||||||
|
|
||||||
|
@ -44,6 +67,8 @@ impl Server {
|
||||||
|
|
||||||
let response = self.handle_request(req)?;
|
let response = self.handle_request(req)?;
|
||||||
|
|
||||||
|
self.publish_stored_diagnostics(&connection)?;
|
||||||
|
|
||||||
connection.sender.send(Message::Response(response))?;
|
connection.sender.send(Message::Response(response))?;
|
||||||
}
|
}
|
||||||
Message::Response(_) => todo!(),
|
Message::Response(_) => todo!(),
|
||||||
|
@ -59,7 +84,7 @@ impl Server {
|
||||||
fn handle_request(
|
fn handle_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
request: lsp_server::Request,
|
request: lsp_server::Request,
|
||||||
) -> Result<lsp_server::Response, Error> {
|
) -> Result<lsp_server::Response, ServerError> {
|
||||||
let id = request.id.clone();
|
let id = request.id.clone();
|
||||||
|
|
||||||
match request.method.as_str() {
|
match request.method.as_str() {
|
||||||
|
@ -78,12 +103,45 @@ impl Server {
|
||||||
result: Some(result),
|
result: Some(result),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(err) => match err {
|
||||||
todo!("transform project errors in lsp diagnostic")
|
ProjectError::List(errors) => {
|
||||||
}
|
for error in errors {
|
||||||
|
if error.source_code().is_some() {
|
||||||
|
self.process_diagnostic(error)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(lsp_server::Response {
|
||||||
|
id,
|
||||||
|
error: None,
|
||||||
|
result: Some(serde_json::json!(null)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
error => {
|
||||||
|
if error.source_code().is_some() {
|
||||||
|
self.process_diagnostic(error)?;
|
||||||
|
|
||||||
|
Ok(lsp_server::Response {
|
||||||
|
id,
|
||||||
|
error: None,
|
||||||
|
result: Some(serde_json::json!(null)),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(lsp_server::Response {
|
||||||
|
id,
|
||||||
|
error: Some(lsp_server::ResponseError {
|
||||||
|
code: 1, // We should assign a code to each error.
|
||||||
|
message: format!("{:?}", error),
|
||||||
|
data: None,
|
||||||
|
}),
|
||||||
|
result: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsupported => Err(Error::UnsupportedLspRequest {
|
unsupported => Err(ServerError::UnsupportedLspRequest {
|
||||||
request: unsupported.to_string(),
|
request: unsupported.to_string(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -93,7 +151,7 @@ impl Server {
|
||||||
&mut self,
|
&mut self,
|
||||||
_connection: &lsp_server::Connection,
|
_connection: &lsp_server::Connection,
|
||||||
notification: lsp_server::Notification,
|
notification: lsp_server::Notification,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), ServerError> {
|
||||||
match notification.method.as_str() {
|
match notification.method.as_str() {
|
||||||
DidChangeTextDocument::METHOD => {
|
DidChangeTextDocument::METHOD => {
|
||||||
let params = cast_notification::<DidChangeTextDocument>(notification)?;
|
let params = cast_notification::<DidChangeTextDocument>(notification)?;
|
||||||
|
@ -102,7 +160,7 @@ impl Server {
|
||||||
let path = params.text_document.uri.path().to_string();
|
let path = params.text_document.uri.path().to_string();
|
||||||
|
|
||||||
if let Some(changes) = params.content_changes.into_iter().next() {
|
if let Some(changes) = params.content_changes.into_iter().next() {
|
||||||
let _ = self.edited.insert(path, changes.text);
|
self.edited.insert(path, changes.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -111,10 +169,7 @@ impl Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format(
|
fn format(&mut self, params: DocumentFormattingParams) -> Result<Vec<TextEdit>, ProjectError> {
|
||||||
&mut self,
|
|
||||||
params: DocumentFormattingParams,
|
|
||||||
) -> Result<Vec<TextEdit>, aiken_project::error::Error> {
|
|
||||||
let path = params.text_document.uri.path();
|
let path = params.text_document.uri.path();
|
||||||
let mut new_text = String::new();
|
let mut new_text = String::new();
|
||||||
|
|
||||||
|
@ -139,9 +194,182 @@ impl Server {
|
||||||
|
|
||||||
Ok(vec![text_edit_replace(new_text)])
|
Ok(vec![text_edit_replace(new_text)])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Publish all stored diagnostics to the client.
|
||||||
|
/// Any previously publish diagnostics are cleared before the new set are
|
||||||
|
/// published to the client.
|
||||||
|
fn publish_stored_diagnostics(&mut self, connection: &Connection) -> Result<(), ServerError> {
|
||||||
|
self.clear_all_diagnostics(connection)?;
|
||||||
|
|
||||||
|
for (path, diagnostics) in self.stored_diagnostics.drain() {
|
||||||
|
let uri = path_to_uri(path)?;
|
||||||
|
|
||||||
|
// Record that we have published diagnostics to this file so we can
|
||||||
|
// clear it later when they are outdated.
|
||||||
|
self.published_diagnostics.insert(uri.clone());
|
||||||
|
|
||||||
|
// Publish the diagnostics
|
||||||
|
let params = lsp_types::PublishDiagnosticsParams {
|
||||||
|
uri,
|
||||||
|
diagnostics,
|
||||||
|
version: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let notification = lsp_server::Notification {
|
||||||
|
method: PublishDiagnostics::METHOD.to_string(),
|
||||||
|
params: serde_json::to_value(params)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
connection
|
||||||
|
.sender
|
||||||
|
.send(lsp_server::Message::Notification(notification))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for message in self.stored_messages.drain(..) {
|
||||||
|
let notification = lsp_server::Notification {
|
||||||
|
method: ShowMessage::METHOD.to_string(),
|
||||||
|
params: serde_json::to_value(message)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
connection
|
||||||
|
.sender
|
||||||
|
.send(lsp_server::Message::Notification(notification))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear all diagnostics that have been previously published to the client
|
||||||
|
fn clear_all_diagnostics(&mut self, connection: &Connection) -> Result<(), ServerError> {
|
||||||
|
for file in self.published_diagnostics.drain() {
|
||||||
|
let params = lsp_types::PublishDiagnosticsParams {
|
||||||
|
uri: file,
|
||||||
|
diagnostics: vec![],
|
||||||
|
version: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let notification = lsp_server::Notification {
|
||||||
|
method: PublishDiagnostics::METHOD.to_string(),
|
||||||
|
params: serde_json::to_value(params)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
connection
|
||||||
|
.sender
|
||||||
|
.send(lsp_server::Message::Notification(notification))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert Aiken diagnostics into 1 or more LSP diagnostics and store them
|
||||||
|
/// so that they can later be published to the client with
|
||||||
|
/// `publish_stored_diagnostics`
|
||||||
|
///
|
||||||
|
/// If the Aiken diagnostic cannot be converted to LSP diagnostic (due to it
|
||||||
|
/// not having a location) it is stored as a message suitable for use with
|
||||||
|
/// the `showMessage` notification instead.
|
||||||
|
///
|
||||||
|
fn process_diagnostic(&mut self, error: ProjectError) -> Result<(), ServerError> {
|
||||||
|
let (severity, typ) = match error.severity() {
|
||||||
|
Some(severity) => match severity {
|
||||||
|
miette::Severity::Error => (
|
||||||
|
lsp_types::DiagnosticSeverity::ERROR,
|
||||||
|
lsp_types::MessageType::ERROR,
|
||||||
|
),
|
||||||
|
miette::Severity::Warning => (
|
||||||
|
lsp_types::DiagnosticSeverity::WARNING,
|
||||||
|
lsp_types::MessageType::WARNING,
|
||||||
|
),
|
||||||
|
miette::Severity::Advice => (
|
||||||
|
lsp_types::DiagnosticSeverity::HINT,
|
||||||
|
lsp_types::MessageType::INFO,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
None => (
|
||||||
|
lsp_types::DiagnosticSeverity::ERROR,
|
||||||
|
lsp_types::MessageType::ERROR,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut text = match error.source() {
|
||||||
|
Some(err) => err.to_string(),
|
||||||
|
None => error.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let (Some(mut labels), Some(path), Some(src)) =
|
||||||
|
(error.labels(), error.path(), error.src())
|
||||||
|
{
|
||||||
|
if let Some(labeled_span) = labels.next() {
|
||||||
|
if let Some(label) = labeled_span.label() {
|
||||||
|
text.push_str("\n\n");
|
||||||
|
text.push_str(label);
|
||||||
|
|
||||||
|
if !label.ends_with(['.', '?']) {
|
||||||
|
text.push('.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let line_numbers = LineNumbers::new(&src);
|
||||||
|
|
||||||
|
let start = line_numbers.line_and_column_number(labeled_span.inner().offset());
|
||||||
|
let end = line_numbers.line_and_column_number(
|
||||||
|
labeled_span.inner().offset() + labeled_span.inner().len(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let lsp_diagnostic = lsp_types::Diagnostic {
|
||||||
|
range: lsp_types::Range::new(
|
||||||
|
lsp_types::Position {
|
||||||
|
line: start.line as u32 - 1,
|
||||||
|
character: start.column as u32 - 1,
|
||||||
|
},
|
||||||
|
lsp_types::Position {
|
||||||
|
line: end.line as u32 - 1,
|
||||||
|
character: end.column as u32 - 1,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
severity: Some(severity),
|
||||||
|
code: error
|
||||||
|
.code()
|
||||||
|
.map(|c| lsp_types::NumberOrString::String(c.to_string())),
|
||||||
|
code_description: None,
|
||||||
|
source: None,
|
||||||
|
message: text.clone(),
|
||||||
|
related_information: None,
|
||||||
|
tags: None,
|
||||||
|
data: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = path.canonicalize()?;
|
||||||
|
|
||||||
|
self.push_diagnostic(path.clone(), lsp_diagnostic.clone());
|
||||||
|
|
||||||
|
if let Some(hint) = error.help() {
|
||||||
|
let lsp_hint = lsp_types::Diagnostic {
|
||||||
|
severity: Some(lsp_types::DiagnosticSeverity::HINT),
|
||||||
|
message: hint.to_string(),
|
||||||
|
..lsp_diagnostic
|
||||||
|
};
|
||||||
|
|
||||||
|
self.push_diagnostic(path, lsp_hint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.stored_messages
|
||||||
|
.push(lsp_types::ShowMessageParams { typ, message: text })
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_diagnostic(&mut self, path: PathBuf, diagnostic: lsp_types::Diagnostic) {
|
||||||
|
self.stored_diagnostics
|
||||||
|
.entry(path)
|
||||||
|
.or_default()
|
||||||
|
.push(diagnostic);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cast_request<R>(request: lsp_server::Request) -> Result<R::Params, Error>
|
fn cast_request<R>(request: lsp_server::Request) -> Result<R::Params, ServerError>
|
||||||
where
|
where
|
||||||
R: lsp_types::request::Request,
|
R: lsp_types::request::Request,
|
||||||
R::Params: serde::de::DeserializeOwned,
|
R::Params: serde::de::DeserializeOwned,
|
||||||
|
@ -151,7 +379,7 @@ where
|
||||||
Ok(params)
|
Ok(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cast_notification<N>(notification: lsp_server::Notification) -> Result<N::Params, Error>
|
fn cast_notification<N>(notification: lsp_server::Notification) -> Result<N::Params, ServerError>
|
||||||
where
|
where
|
||||||
N: lsp_types::notification::Notification,
|
N: lsp_types::notification::Notification,
|
||||||
N::Params: serde::de::DeserializeOwned,
|
N::Params: serde::de::DeserializeOwned,
|
||||||
|
@ -176,3 +404,13 @@ fn text_edit_replace(new_text: String) -> TextEdit {
|
||||||
new_text,
|
new_text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn path_to_uri(path: PathBuf) -> Result<lsp_types::Url, ServerError> {
|
||||||
|
let mut file: String = "file://".into();
|
||||||
|
|
||||||
|
file.push_str(&path.as_os_str().to_string_lossy());
|
||||||
|
|
||||||
|
let uri = lsp_types::Url::parse(&file)?;
|
||||||
|
|
||||||
|
Ok(uri)
|
||||||
|
}
|
||||||
|
|
|
@ -127,6 +127,36 @@ impl Error {
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
matches!(self, Error::List(errors) if errors.is_empty())
|
matches!(self, Error::List(errors) if errors.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn path(&self) -> Option<PathBuf> {
|
||||||
|
match self {
|
||||||
|
Error::DuplicateModule { second, .. } => Some(second.to_path_buf()),
|
||||||
|
Error::FileIo { .. } => None,
|
||||||
|
Error::Format { .. } => None,
|
||||||
|
Error::StandardIo(_) => None,
|
||||||
|
Error::ImportCycle { .. } => None,
|
||||||
|
Error::List(_) => None,
|
||||||
|
Error::Parse { path, .. } => Some(path.to_path_buf()),
|
||||||
|
Error::Type { path, .. } => Some(path.to_path_buf()),
|
||||||
|
Error::ValidatorMustReturnBool { path, .. } => Some(path.to_path_buf()),
|
||||||
|
Error::WrongValidatorArity { path, .. } => Some(path.to_path_buf()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn src(&self) -> Option<String> {
|
||||||
|
match self {
|
||||||
|
Error::DuplicateModule { .. } => None,
|
||||||
|
Error::FileIo { .. } => None,
|
||||||
|
Error::Format { .. } => None,
|
||||||
|
Error::StandardIo(_) => None,
|
||||||
|
Error::ImportCycle { .. } => None,
|
||||||
|
Error::List(_) => None,
|
||||||
|
Error::Parse { src, .. } => Some(src.to_string()),
|
||||||
|
Error::Type { src, .. } => Some(src.to_string()),
|
||||||
|
Error::ValidatorMustReturnBool { src, .. } => Some(src.to_string()),
|
||||||
|
Error::WrongValidatorArity { src, .. } => Some(src.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Error {
|
impl Debug for Error {
|
||||||
|
@ -149,6 +179,10 @@ impl Debug for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Diagnostic for Error {
|
impl Diagnostic for Error {
|
||||||
|
fn severity(&self) -> Option<miette::Severity> {
|
||||||
|
Some(miette::Severity::Error)
|
||||||
|
}
|
||||||
|
|
||||||
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
|
||||||
match self {
|
match self {
|
||||||
Error::DuplicateModule { .. } => Some(Box::new("aiken::module::duplicate")),
|
Error::DuplicateModule { .. } => Some(Box::new("aiken::module::duplicate")),
|
||||||
|
@ -233,6 +267,10 @@ pub enum Warning {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Diagnostic for Warning {
|
impl Diagnostic for Warning {
|
||||||
|
fn severity(&self) -> Option<miette::Severity> {
|
||||||
|
Some(miette::Severity::Warning)
|
||||||
|
}
|
||||||
|
|
||||||
fn source_code(&self) -> Option<&dyn SourceCode> {
|
fn source_code(&self) -> Option<&dyn SourceCode> {
|
||||||
match self {
|
match self {
|
||||||
Warning::Type { src, .. } => Some(src),
|
Warning::Type { src, .. } => Some(src),
|
||||||
|
|
|
@ -4,16 +4,12 @@ use sample/spend
|
||||||
|
|
||||||
pub type Redeemer {
|
pub type Redeemer {
|
||||||
signer: ByteArray,
|
signer: ByteArray,
|
||||||
amount: Int
|
amount: Int,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Reen {
|
pub type Reen {
|
||||||
Buy{
|
Buy { signer: ByteArray, amount: Int }
|
||||||
signer: ByteArray,
|
|
||||||
amount: Int
|
|
||||||
}
|
|
||||||
Sell
|
Sell
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn twice(f: fn(Int) -> Int, initial: Int) -> Int {
|
pub fn twice(f: fn(Int) -> Int, initial: Int) -> Int {
|
||||||
|
@ -28,7 +24,7 @@ pub fn add_two(x: Int) -> Int {
|
||||||
twice(add_one, x)
|
twice(add_one, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn final_check(z: Int){
|
pub fn final_check(z: Int) {
|
||||||
z < 4
|
z < 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,10 +33,8 @@ pub fn spend(
|
||||||
rdmr: Redeemer,
|
rdmr: Redeemer,
|
||||||
ctx: spend.ScriptContext,
|
ctx: spend.ScriptContext,
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
|
let a = datum.fin
|
||||||
let a = datum.fin
|
a
|
||||||
|
|> add_two
|
||||||
a
|
|> final_check
|
||||||
|> add_two
|
|
||||||
|> final_check
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue