mirror of
https://github.com/Dummi26/mers.git
synced 2025-03-10 14:13:52 +01:00
improved error messages
- some small bugs are now fixed - include comments in error messages (if this causes issues, use --hide-comments) - colors should make more sense now - error-related things moved to mers_lib/src/errors/
This commit is contained in:
parent
c39e784939
commit
12925fed67
@ -14,6 +14,9 @@ struct Args {
|
|||||||
/// perform checks to avoid runtime crashes
|
/// perform checks to avoid runtime crashes
|
||||||
#[arg(long, default_value_t = Check::Yes)]
|
#[arg(long, default_value_t = Check::Yes)]
|
||||||
check: Check,
|
check: Check,
|
||||||
|
/// in error messages, hide comments and only show actual code
|
||||||
|
#[arg(long)]
|
||||||
|
hide_comments: bool,
|
||||||
}
|
}
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
enum Command {
|
enum Command {
|
||||||
@ -81,7 +84,7 @@ fn main() {
|
|||||||
let parsed = match parse(&mut source) {
|
let parsed = match parse(&mut source) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{}", e.display(&source));
|
eprintln!("{}", e.display(&source).show_comments(!args.hide_comments));
|
||||||
exit(20);
|
exit(20);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -90,7 +93,7 @@ fn main() {
|
|||||||
let run = match parsed.compile(&mut info_parsed, Default::default()) {
|
let run = match parsed.compile(&mut info_parsed, Default::default()) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{}", e.display(&source));
|
eprintln!("{}", e.display(&source).show_comments(!args.hide_comments));
|
||||||
exit(24);
|
exit(24);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -104,7 +107,7 @@ fn main() {
|
|||||||
let return_type = match run.check(&mut info_check, None) {
|
let return_type = match run.check(&mut info_check, None) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprint!("{}", e.display(&source));
|
eprint!("{}", e.display(&source).show_comments(!args.hide_comments));
|
||||||
exit(28);
|
exit(28);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,10 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::program::run::{CheckError, CheckInfo, Info};
|
use crate::{
|
||||||
|
errors::CheckError,
|
||||||
|
program::run::{CheckInfo, Info},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{Data, MersData, MersType, Type};
|
use super::{Data, MersData, MersType, Type};
|
||||||
|
|
||||||
|
308
mers_lib/src/errors/mod.rs
Normal file
308
mers_lib/src/errors/mod.rs
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use colored::Colorize;
|
||||||
|
use line_span::LineSpans;
|
||||||
|
|
||||||
|
#[cfg(feature = "parse")]
|
||||||
|
use crate::parsing::Source;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct SourcePos(pub(crate) usize);
|
||||||
|
impl SourcePos {
|
||||||
|
pub fn pos(&self) -> usize {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct SourceRange {
|
||||||
|
start: SourcePos,
|
||||||
|
end: SourcePos,
|
||||||
|
}
|
||||||
|
impl From<(SourcePos, SourcePos)> for SourceRange {
|
||||||
|
fn from(value: (SourcePos, SourcePos)) -> Self {
|
||||||
|
SourceRange {
|
||||||
|
start: value.0,
|
||||||
|
end: value.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl SourceRange {
|
||||||
|
pub fn start(&self) -> SourcePos {
|
||||||
|
self.start
|
||||||
|
}
|
||||||
|
pub fn end(&self) -> SourcePos {
|
||||||
|
self.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct CheckError(Vec<CheckErrorComponent>);
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
pub mod error_colors {
|
||||||
|
use colored::Color;
|
||||||
|
|
||||||
|
pub const UnknownVariable: Color = Color::Red;
|
||||||
|
|
||||||
|
pub const WhitespaceAfterHashtag: Color = Color::Red;
|
||||||
|
pub const HashUnknown: Color = Color::Red;
|
||||||
|
pub const HashIncludeCantLoadFile: Color = Color::Red;
|
||||||
|
pub const HashIncludeNotAString: Color = Color::Red;
|
||||||
|
pub const HashIncludeErrorInIncludedFile: Color = Color::Red;
|
||||||
|
|
||||||
|
pub const BackslashEscapeUnknown: Color = Color::Red;
|
||||||
|
pub const BackslashEscapeEOF: Color = Color::Red;
|
||||||
|
pub const StringEOF: Color = Color::Red;
|
||||||
|
|
||||||
|
pub const IfConditionNotBool: Color = Color::Red;
|
||||||
|
pub const ChainWithNonFunction: Color = Color::Yellow;
|
||||||
|
|
||||||
|
pub const Function: Color = Color::BrightMagenta;
|
||||||
|
pub const FunctionArgument: Color = Color::BrightBlue;
|
||||||
|
|
||||||
|
pub const InitFrom: Color = Color::BrightCyan;
|
||||||
|
pub const InitTo: Color = Color::Green;
|
||||||
|
pub const AssignFrom: Color = InitFrom;
|
||||||
|
pub const AssignTo: Color = InitTo;
|
||||||
|
pub const AssignTargetNonReference: Color = Color::BrightYellow;
|
||||||
|
}
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum CheckErrorComponent {
|
||||||
|
Message(String),
|
||||||
|
Error(CheckError),
|
||||||
|
Source(Vec<(SourceRange, Option<colored::Color>)>),
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct CheckErrorHRConfig {
|
||||||
|
indent_start: String,
|
||||||
|
indent_default: String,
|
||||||
|
indent_end: String,
|
||||||
|
/// if true, shows "original" source code, if false, shows source with comments removed (this is what the parser uses internally)
|
||||||
|
show_comments: bool,
|
||||||
|
}
|
||||||
|
#[cfg(feature = "parse")]
|
||||||
|
pub struct CheckErrorDisplay<'a> {
|
||||||
|
e: &'a CheckError,
|
||||||
|
src: Option<&'a Source>,
|
||||||
|
pub show_comments: bool,
|
||||||
|
}
|
||||||
|
#[cfg(feature = "parse")]
|
||||||
|
impl<'a> CheckErrorDisplay<'a> {
|
||||||
|
pub fn show_comments(mut self, show_comments: bool) -> Self {
|
||||||
|
self.show_comments = show_comments;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "parse")]
|
||||||
|
impl Display for CheckErrorDisplay<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.e.human_readable(
|
||||||
|
f,
|
||||||
|
self.src,
|
||||||
|
&CheckErrorHRConfig {
|
||||||
|
indent_start: String::new(),
|
||||||
|
indent_default: String::new(),
|
||||||
|
indent_end: String::new(),
|
||||||
|
show_comments: self.show_comments,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl CheckError {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
CheckError(vec![])
|
||||||
|
}
|
||||||
|
fn add(mut self, v: CheckErrorComponent) -> Self {
|
||||||
|
self.0.push(v);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub(crate) fn msg(self, s: String) -> Self {
|
||||||
|
self.add(CheckErrorComponent::Message(s))
|
||||||
|
}
|
||||||
|
pub(crate) fn err(self, e: Self) -> Self {
|
||||||
|
self.add(CheckErrorComponent::Error(e))
|
||||||
|
}
|
||||||
|
pub(crate) fn src(self, s: Vec<(SourceRange, Option<colored::Color>)>) -> Self {
|
||||||
|
self.add(CheckErrorComponent::Source(s))
|
||||||
|
}
|
||||||
|
#[cfg(feature = "parse")]
|
||||||
|
pub fn display<'a>(&'a self, src: &'a Source) -> CheckErrorDisplay<'a> {
|
||||||
|
CheckErrorDisplay {
|
||||||
|
e: self,
|
||||||
|
src: Some(src),
|
||||||
|
show_comments: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "parse")]
|
||||||
|
pub fn display_no_src<'a>(&'a self) -> CheckErrorDisplay<'a> {
|
||||||
|
CheckErrorDisplay {
|
||||||
|
e: self,
|
||||||
|
src: None,
|
||||||
|
show_comments: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// will, unless empty, end in a newline
|
||||||
|
#[cfg(feature = "parse")]
|
||||||
|
fn human_readable(
|
||||||
|
&self,
|
||||||
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
|
src: Option<&Source>,
|
||||||
|
cfg: &CheckErrorHRConfig,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
let len = self.0.len();
|
||||||
|
for (i, component) in self.0.iter().enumerate() {
|
||||||
|
macro_rules! indent {
|
||||||
|
() => {
|
||||||
|
if i + 1 == len {
|
||||||
|
&cfg.indent_end
|
||||||
|
} else if i == 0 {
|
||||||
|
&cfg.indent_start
|
||||||
|
} else {
|
||||||
|
&cfg.indent_default
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
match component {
|
||||||
|
CheckErrorComponent::Message(msg) => writeln!(f, "{}{msg}", indent!())?,
|
||||||
|
CheckErrorComponent::Error(err) => {
|
||||||
|
let mut cfg = cfg.clone();
|
||||||
|
cfg.indent_start.push_str("│");
|
||||||
|
cfg.indent_default.push_str("│");
|
||||||
|
cfg.indent_end.push_str("└");
|
||||||
|
err.human_readable(f, src, &cfg)?;
|
||||||
|
}
|
||||||
|
CheckErrorComponent::Source(highlights) => {
|
||||||
|
if let Some(src) = src {
|
||||||
|
let start = highlights.iter().map(|v| v.0.start.pos()).min();
|
||||||
|
let end = highlights.iter().map(|v| v.0.end.pos()).max();
|
||||||
|
if let (Some(start_in_line), Some(end_in_line)) = (start, end) {
|
||||||
|
let start = src.get_line_start(start_in_line);
|
||||||
|
let end = src.get_line_end(end_in_line);
|
||||||
|
let (start_with_comments, end_with_comments) = (
|
||||||
|
src.pos_in_og(start_in_line, true),
|
||||||
|
src.pos_in_og(end_in_line, false),
|
||||||
|
);
|
||||||
|
let (mut start, mut end) = if cfg.show_comments {
|
||||||
|
(src.pos_in_og(start, true), src.pos_in_og(end, false))
|
||||||
|
} else {
|
||||||
|
(start, end)
|
||||||
|
};
|
||||||
|
let mut first_line_start = 0;
|
||||||
|
let first_line_nr = src
|
||||||
|
.src_og()
|
||||||
|
.line_spans()
|
||||||
|
.take_while(|l| {
|
||||||
|
if l.start() <= start_with_comments {
|
||||||
|
first_line_start = l.start();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
if cfg.show_comments && first_line_start < start {
|
||||||
|
start = first_line_start;
|
||||||
|
}
|
||||||
|
let mut last_line_start = 0;
|
||||||
|
let last_line_nr = src
|
||||||
|
.src_og()
|
||||||
|
.line_spans()
|
||||||
|
.take_while(|l| {
|
||||||
|
if l.start() <= end_with_comments {
|
||||||
|
last_line_start = l.start();
|
||||||
|
if cfg.show_comments && l.end() > end {
|
||||||
|
end = l.end();
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
if first_line_nr == last_line_nr {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"{}Line {first_line_nr} ({}..{})",
|
||||||
|
indent!(),
|
||||||
|
start_with_comments + 1 - first_line_start,
|
||||||
|
end_with_comments - last_line_start,
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"{}Lines {first_line_nr}-{last_line_nr} ({}..{})",
|
||||||
|
indent!(),
|
||||||
|
start_with_comments + 1 - first_line_start,
|
||||||
|
end_with_comments - last_line_start,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
let lines = if cfg.show_comments {
|
||||||
|
src.src_og()[start..end].line_spans().collect::<Vec<_>>()
|
||||||
|
} else {
|
||||||
|
src.src()[start..end].line_spans().collect::<Vec<_>>()
|
||||||
|
};
|
||||||
|
for line in lines {
|
||||||
|
let line_start = line.start();
|
||||||
|
let line_end = line.end();
|
||||||
|
let line = line.as_str();
|
||||||
|
writeln!(f, "{} {line}", indent!())?;
|
||||||
|
let mut right = 0;
|
||||||
|
for (pos, color) in highlights {
|
||||||
|
if let Some(color) = color {
|
||||||
|
let (highlight_start, highlight_end) = if cfg.show_comments
|
||||||
|
{
|
||||||
|
(
|
||||||
|
src.pos_in_og(pos.start.pos(), true),
|
||||||
|
src.pos_in_og(pos.end.pos(), false),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(pos.start.pos(), pos.end.pos())
|
||||||
|
};
|
||||||
|
let highlight_start = highlight_start - start;
|
||||||
|
let highlight_end = highlight_end - start;
|
||||||
|
if highlight_start < line_end && highlight_end > line_start
|
||||||
|
{
|
||||||
|
// where the highlight starts in this line
|
||||||
|
let hl_start =
|
||||||
|
highlight_start.saturating_sub(line_start);
|
||||||
|
// highlight would be further left than cursor, so we need a new line
|
||||||
|
if hl_start < right {
|
||||||
|
right = 0;
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
// length of the highlight
|
||||||
|
let hl_len = highlight_end
|
||||||
|
.saturating_sub(line_start)
|
||||||
|
.saturating_sub(hl_start);
|
||||||
|
let hl_space = hl_start - right;
|
||||||
|
let print_indent = right == 0;
|
||||||
|
let hl_len = hl_len.min(line.len() - right);
|
||||||
|
right += hl_space + hl_len;
|
||||||
|
if print_indent && right != 0 {
|
||||||
|
write!(f, "{} ", indent!())?;
|
||||||
|
}
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}{}",
|
||||||
|
" ".repeat(hl_space),
|
||||||
|
"~".repeat(hl_len).color(*color)
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if right != 0 {
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<String> for CheckError {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
Self::new().msg(value)
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
/// data and types in mers
|
/// data and types in mers
|
||||||
pub mod data;
|
pub mod data;
|
||||||
|
/// struct to represent errors the user may face
|
||||||
|
pub mod errors;
|
||||||
/// shared code handling scopes to guarantee that compiler and runtime scopes match
|
/// shared code handling scopes to guarantee that compiler and runtime scopes match
|
||||||
pub mod info;
|
pub mod info;
|
||||||
/// parser implementation.
|
/// parser implementation.
|
||||||
|
@ -1 +0,0 @@
|
|||||||
|
|
@ -1,8 +1,10 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::program::{self, parsed::block::Block, run::CheckError};
|
use crate::{
|
||||||
|
errors::{CheckError, SourcePos},
|
||||||
|
program::{self, parsed::block::Block},
|
||||||
|
};
|
||||||
|
|
||||||
pub mod errors;
|
|
||||||
pub mod statements;
|
pub mod statements;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
@ -20,7 +22,7 @@ pub struct Source {
|
|||||||
src_raw_len: usize,
|
src_raw_len: usize,
|
||||||
src_og: String,
|
src_og: String,
|
||||||
src: String,
|
src: String,
|
||||||
/// (start, content) of each comment, including start/end (//, \n, /* and */)
|
/// (start, content) of each comment, including start/end (//, /* and */), but NOT newline after //
|
||||||
comments: Vec<(usize, String)>,
|
comments: Vec<(usize, String)>,
|
||||||
i: usize,
|
i: usize,
|
||||||
sections: Vec<SectionMarker>,
|
sections: Vec<SectionMarker>,
|
||||||
@ -36,13 +38,15 @@ impl Source {
|
|||||||
if let Some((i, ch)) = chars.next() {
|
if let Some((i, ch)) = chars.next() {
|
||||||
match in_comment {
|
match in_comment {
|
||||||
Some(false) => {
|
Some(false) => {
|
||||||
comment.1.push(ch);
|
|
||||||
if ch == '\n' {
|
if ch == '\n' {
|
||||||
|
src.push('\n');
|
||||||
in_comment = None;
|
in_comment = None;
|
||||||
comments.push((
|
comments.push((
|
||||||
comment.0,
|
comment.0,
|
||||||
std::mem::replace(&mut comment.1, String::new()),
|
std::mem::replace(&mut comment.1, String::new()),
|
||||||
));
|
));
|
||||||
|
} else {
|
||||||
|
comment.1.push(ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(true) => {
|
Some(true) => {
|
||||||
@ -223,6 +227,20 @@ impl Source {
|
|||||||
}
|
}
|
||||||
o
|
o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pos_in_og(&self, mut pos: usize, inclusive: bool) -> usize {
|
||||||
|
for (start, comment) in &self.comments {
|
||||||
|
if *start < pos || (inclusive && *start == pos) {
|
||||||
|
pos += comment.len();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos
|
||||||
|
}
|
||||||
|
pub fn src_og(&self) -> &String {
|
||||||
|
&self.src_og
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Source {
|
impl Drop for Source {
|
||||||
@ -261,14 +279,3 @@ impl SectionMarker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct SourcePos(usize);
|
|
||||||
impl SourcePos {
|
|
||||||
pub fn pos(&self) -> usize {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
fn diff(&self, rhs: &Self) -> usize {
|
|
||||||
rhs.0 - self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -3,11 +3,8 @@ use std::fs;
|
|||||||
use super::{Source, SourcePos};
|
use super::{Source, SourcePos};
|
||||||
use crate::{
|
use crate::{
|
||||||
data::Data,
|
data::Data,
|
||||||
program::{
|
errors::{error_colors, CheckError},
|
||||||
self,
|
program::{self, parsed::MersStatement},
|
||||||
parsed::MersStatement,
|
|
||||||
run::{error_colors, CheckError},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse(
|
pub fn parse(
|
||||||
@ -19,6 +16,7 @@ pub fn parse(
|
|||||||
} else {
|
} else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
let mut pos_after_first = src.get_pos();
|
||||||
src.skip_whitespace();
|
src.skip_whitespace();
|
||||||
match src.peek_word() {
|
match src.peek_word() {
|
||||||
":=" => {
|
":=" => {
|
||||||
@ -68,15 +66,15 @@ pub fn parse(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => loop {
|
_ => loop {
|
||||||
let pos_in_src = src.get_pos();
|
|
||||||
src.skip_whitespace();
|
src.skip_whitespace();
|
||||||
|
let dot_in_src = src.get_pos();
|
||||||
if let Some('.') = src.peek_char() {
|
if let Some('.') = src.peek_char() {
|
||||||
src.next_char();
|
src.next_char();
|
||||||
let chained = match parse_no_chain(src) {
|
let chained = match parse_no_chain(src) {
|
||||||
Ok(Some(v)) => v,
|
Ok(Some(v)) => v,
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
return Err(CheckError::new()
|
return Err(CheckError::new()
|
||||||
.src(vec![((pos_in_src, src.get_pos()).into(), None)])
|
.src(vec![((dot_in_src, src.get_pos()).into(), None)])
|
||||||
.msg(format!("EOF after `.`")))
|
.msg(format!("EOF after `.`")))
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
@ -91,11 +89,13 @@ pub fn parse(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
first = Box::new(program::parsed::chain::Chain {
|
first = Box::new(program::parsed::chain::Chain {
|
||||||
pos_in_src: (pos_in_src, src.get_pos()).into(),
|
pos_in_src: (first.source_range().start(), src.get_pos()).into(),
|
||||||
first,
|
first,
|
||||||
chained,
|
chained,
|
||||||
});
|
});
|
||||||
|
pos_after_first = src.get_pos();
|
||||||
} else {
|
} else {
|
||||||
|
src.set_pos(pos_after_first);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5,7 +5,8 @@ use std::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, MersType, Type},
|
data::{self, Data, MersType, Type},
|
||||||
program::run::{CheckError, CheckInfo, Info},
|
errors::CheckError,
|
||||||
|
program::run::{CheckInfo, Info},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Config;
|
use super::Config;
|
||||||
|
@ -9,10 +9,8 @@ use crate::{
|
|||||||
function::{Function, FunctionT},
|
function::{Function, FunctionT},
|
||||||
Data, MersData, MersType, Type,
|
Data, MersData, MersType, Type,
|
||||||
},
|
},
|
||||||
program::{
|
errors::CheckError,
|
||||||
self,
|
program::{self, run::CheckInfo},
|
||||||
run::{CheckError, CheckInfo},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Config;
|
use super::Config;
|
||||||
@ -140,13 +138,6 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_out(
|
|
||||||
a: &Type,
|
|
||||||
name: &str,
|
|
||||||
func: impl Fn(&FunctionT) -> ItersT + Sync + Send,
|
|
||||||
) -> Result<Type, CheckError> {
|
|
||||||
iter_out_arg(a, name, func)
|
|
||||||
}
|
|
||||||
fn iter_out_arg<T: MersType>(
|
fn iter_out_arg<T: MersType>(
|
||||||
a: &Type,
|
a: &Type,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
@ -135,7 +135,7 @@ impl Config {
|
|||||||
Data::new(data::function::Function {
|
Data::new(data::function::Function {
|
||||||
info: Arc::new(program::run::Info::neverused()),
|
info: Arc::new(program::run::Info::neverused()),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Arc::new(|a, i| {
|
out: Arc::new(|a, _i| {
|
||||||
if let Some(v) = a.iterable() {
|
if let Some(v) = a.iterable() {
|
||||||
Ok(Type::new(ListT(v)))
|
Ok(Type::new(ListT(v)))
|
||||||
} else {
|
} else {
|
||||||
|
@ -2,10 +2,8 @@ use std::sync::{Arc, Mutex};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, MersType, Type},
|
data::{self, Data, MersType, Type},
|
||||||
program::{
|
errors::CheckError,
|
||||||
self,
|
program::{self, run::CheckInfo},
|
||||||
run::{CheckError, CheckInfo},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Config;
|
use super::Config;
|
||||||
|
@ -6,10 +6,8 @@ use std::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, MersData, MersType, Type},
|
data::{self, Data, MersData, MersType, Type},
|
||||||
program::{
|
errors::CheckError,
|
||||||
self,
|
program::{self, run::CheckInfo},
|
||||||
run::{CheckError, CheckInfo},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Config;
|
use super::Config;
|
||||||
|
@ -3,8 +3,11 @@ use std::{
|
|||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use colored::Colorize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, Type},
|
data::{self, Data, Type},
|
||||||
|
errors::error_colors,
|
||||||
program::{self, run::CheckInfo},
|
program::{self, run::CheckInfo},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -23,7 +26,17 @@ impl Config {
|
|||||||
Data::new(data::function::Function {
|
Data::new(data::function::Function {
|
||||||
info: Arc::new(program::run::Info::neverused()),
|
info: Arc::new(program::run::Info::neverused()),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Arc::new(|a, i| Ok(Type::new(data::string::StringT))),
|
out: Arc::new(|a, _i| {
|
||||||
|
if a.is_zero_tuple() {
|
||||||
|
Ok(Type::new(data::string::StringT))
|
||||||
|
} else {
|
||||||
|
Err(format!(
|
||||||
|
"expected (), got {}",
|
||||||
|
a.to_string().color(error_colors::FunctionArgument)
|
||||||
|
)
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
}),
|
||||||
run: Arc::new(|_a, _i| {
|
run: Arc::new(|_a, _i| {
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
_ = std::io::stdin().read_line(&mut line);
|
_ = std::io::stdin().read_line(&mut line);
|
||||||
@ -36,7 +49,7 @@ impl Config {
|
|||||||
Data::new(data::function::Function {
|
Data::new(data::function::Function {
|
||||||
info: Arc::new(program::run::Info::neverused()),
|
info: Arc::new(program::run::Info::neverused()),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Arc::new(|a, i| Ok(Type::empty_tuple())),
|
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
eprintln!("{:#?}", a.get());
|
eprintln!("{:#?}", a.get());
|
||||||
Data::empty_tuple()
|
Data::empty_tuple()
|
||||||
@ -48,10 +61,10 @@ impl Config {
|
|||||||
Data::new(data::function::Function {
|
Data::new(data::function::Function {
|
||||||
info: Arc::new(program::run::Info::neverused()),
|
info: Arc::new(program::run::Info::neverused()),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Arc::new(|a, i| Ok(Type::empty_tuple())),
|
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
eprint!("{}", a.get());
|
eprint!("{}", a.get());
|
||||||
std::io::stderr().lock().flush();
|
_ = std::io::stderr().lock().flush();
|
||||||
Data::empty_tuple()
|
Data::empty_tuple()
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
@ -61,7 +74,7 @@ impl Config {
|
|||||||
Data::new(data::function::Function {
|
Data::new(data::function::Function {
|
||||||
info: Arc::new(program::run::Info::neverused()),
|
info: Arc::new(program::run::Info::neverused()),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Arc::new(|a, i| Ok(Type::empty_tuple())),
|
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
eprintln!("{}", a.get());
|
eprintln!("{}", a.get());
|
||||||
Data::empty_tuple()
|
Data::empty_tuple()
|
||||||
@ -73,10 +86,10 @@ impl Config {
|
|||||||
Data::new(data::function::Function {
|
Data::new(data::function::Function {
|
||||||
info: Arc::new(program::run::Info::neverused()),
|
info: Arc::new(program::run::Info::neverused()),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Arc::new(|a, i| Ok(Type::empty_tuple())),
|
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
print!("{}", a.get());
|
print!("{}", a.get());
|
||||||
std::io::stdout().lock().flush();
|
_ = std::io::stdout().lock().flush();
|
||||||
Data::empty_tuple()
|
Data::empty_tuple()
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
@ -86,7 +99,7 @@ impl Config {
|
|||||||
Data::new(data::function::Function {
|
Data::new(data::function::Function {
|
||||||
info: Arc::new(program::run::Info::neverused()),
|
info: Arc::new(program::run::Info::neverused()),
|
||||||
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
|
||||||
out: Arc::new(|a, i| Ok(Type::empty_tuple())),
|
out: Arc::new(|_a, _i| Ok(Type::empty_tuple())),
|
||||||
run: Arc::new(|a, _i| {
|
run: Arc::new(|a, _i| {
|
||||||
println!("{}", a.get());
|
println!("{}", a.get());
|
||||||
Data::empty_tuple()
|
Data::empty_tuple()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::program::{
|
use crate::{
|
||||||
self,
|
errors::{CheckError, SourceRange},
|
||||||
run::{CheckError, SourceRange},
|
program::{self},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
errors::{CheckError, SourceRange},
|
||||||
info,
|
info,
|
||||||
program::{
|
program::{self},
|
||||||
self,
|
|
||||||
run::{CheckError, SourceRange},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use crate::program::run::{CheckError, SourceRange};
|
use crate::{
|
||||||
use crate::{info, program};
|
errors::{CheckError, SourceRange},
|
||||||
|
info, program,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::program::run::{CheckError, SourceRange};
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data,
|
data,
|
||||||
|
errors::{CheckError, SourceRange},
|
||||||
program::{self, run::CheckInfo},
|
program::{self, run::CheckInfo},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,8 +29,8 @@ impl MersStatement for Function {
|
|||||||
let arg_target = Arc::new(self.arg.compile(info, comp)?);
|
let arg_target = Arc::new(self.arg.compile(info, comp)?);
|
||||||
comp.is_init = false;
|
comp.is_init = false;
|
||||||
let run = Arc::new(self.run.compile(info, comp)?);
|
let run = Arc::new(self.run.compile(info, comp)?);
|
||||||
let arg2 = Arc::clone(&arg_target);
|
let arg2: Arc<Box<dyn crate::program::run::MersStatement>> = Arc::clone(&arg_target);
|
||||||
let run2 = Arc::clone(&run);
|
let run2: Arc<Box<dyn crate::program::run::MersStatement>> = Arc::clone(&run);
|
||||||
Ok(Box::new(program::run::function::Function {
|
Ok(Box::new(program::run::function::Function {
|
||||||
pos_in_src: self.pos_in_src,
|
pos_in_src: self.pos_in_src,
|
||||||
func_no_info: data::function::Function {
|
func_no_info: data::function::Function {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::program::{
|
use crate::{
|
||||||
self,
|
errors::{CheckError, SourceRange},
|
||||||
run::{CheckError, SourceRange},
|
program::{self},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
|
@ -4,11 +4,9 @@ use colored::Colorize;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data},
|
data::{self, Data},
|
||||||
|
errors::{error_colors, CheckError, SourceRange},
|
||||||
info::{self, Local},
|
info::{self, Local},
|
||||||
program::{
|
program::{self},
|
||||||
self,
|
|
||||||
run::{error_colors, CheckError, SourceRange},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
@ -27,7 +25,7 @@ impl MersStatement for IncludeMers {
|
|||||||
info: &mut info::Info<super::Local>,
|
info: &mut info::Info<super::Local>,
|
||||||
comp: CompInfo,
|
comp: CompInfo,
|
||||||
) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
|
) -> Result<Box<dyn program::run::MersStatement>, CheckError> {
|
||||||
let compiled = match self.include.compile(info, comp) {
|
let compiled: Arc<Box<dyn crate::program::run::MersStatement>> = match self.include.compile(info, comp) {
|
||||||
Ok(v) => Arc::new(v),
|
Ok(v) => Arc::new(v),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(CheckError::new()
|
return Err(CheckError::new()
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use crate::program::run::SourceRange;
|
use crate::{
|
||||||
use crate::program::{self, run::CheckError};
|
errors::{CheckError, SourceRange},
|
||||||
|
program::{self},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use std::{collections::HashMap, fmt::Debug};
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
|
|
||||||
use crate::info;
|
use crate::{
|
||||||
|
errors::{CheckError, SourceRange},
|
||||||
use super::run::{CheckError, SourceRange};
|
info,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "parse")]
|
#[cfg(feature = "parse")]
|
||||||
pub mod assign_to;
|
pub mod assign_to;
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
errors::{CheckError, SourceRange},
|
||||||
info,
|
info,
|
||||||
program::{
|
program::{self},
|
||||||
self,
|
|
||||||
run::{CheckError, SourceRange},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use crate::program::run::{CheckError, SourceRange};
|
use crate::{
|
||||||
use crate::{data::Data, program};
|
data::Data,
|
||||||
|
errors::{CheckError, SourceRange},
|
||||||
|
program,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
|
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
errors::{error_colors, CheckError, SourceRange},
|
||||||
info::Local,
|
info::Local,
|
||||||
program::{
|
program::{self},
|
||||||
self,
|
|
||||||
run::{error_colors, CheckError, SourceRange},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{CompInfo, MersStatement};
|
use super::{CompInfo, MersStatement};
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
|
||||||
use crate::data::{self, Data, MersType, Type};
|
use crate::{
|
||||||
|
data::{self, Data, MersType, Type},
|
||||||
|
errors::{error_colors, CheckError, SourceRange},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{error_colors, CheckError, CheckInfo, MersStatement, SourceRange};
|
use super::{CheckInfo, MersStatement};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AssignTo {
|
pub struct AssignTo {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use crate::data::Type;
|
use crate::{
|
||||||
|
data::Type,
|
||||||
|
errors::{CheckError, SourceRange},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{MersStatement, SourceRange};
|
use super::{CheckInfo, MersStatement};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
@ -10,9 +13,9 @@ pub struct Block {
|
|||||||
impl MersStatement for Block {
|
impl MersStatement for Block {
|
||||||
fn check_custom(
|
fn check_custom(
|
||||||
&self,
|
&self,
|
||||||
info: &mut super::CheckInfo,
|
info: &mut CheckInfo,
|
||||||
init_to: Option<&Type>,
|
init_to: Option<&Type>,
|
||||||
) -> Result<crate::data::Type, super::CheckError> {
|
) -> Result<crate::data::Type, CheckError> {
|
||||||
if init_to.is_some() {
|
if init_to.is_some() {
|
||||||
return Err("can't init to statement type Block".to_string().into());
|
return Err("can't init to statement type Block".to_string().into());
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,12 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
|
||||||
use crate::data::{Data, Type};
|
use crate::{
|
||||||
|
data::{Data, Type},
|
||||||
|
errors::{error_colors, CheckError, SourceRange},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{error_colors, CheckError, MersStatement, SourceRange};
|
use super::MersStatement;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Chain {
|
pub struct Chain {
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::data::{self, Data, MersData, Type};
|
use crate::{
|
||||||
|
data::{self, Data, MersData, Type},
|
||||||
|
errors::{CheckError, SourceRange},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{MersStatement, SourceRange};
|
use super::MersStatement;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
@ -15,7 +18,7 @@ impl MersStatement for Function {
|
|||||||
&self,
|
&self,
|
||||||
info: &mut super::CheckInfo,
|
info: &mut super::CheckInfo,
|
||||||
init_to: Option<&Type>,
|
init_to: Option<&Type>,
|
||||||
) -> Result<data::Type, super::CheckError> {
|
) -> Result<data::Type, CheckError> {
|
||||||
if init_to.is_some() {
|
if init_to.is_some() {
|
||||||
return Err("can't init to statement type Function".to_string().into());
|
return Err("can't init to statement type Function".to_string().into());
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,12 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
|
||||||
use crate::data::{self, Data, MersType, Type};
|
use crate::{
|
||||||
|
data::{self, Data, MersType, Type},
|
||||||
|
errors::{error_colors, CheckError, SourceRange},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{error_colors, CheckError, MersStatement, SourceRange};
|
use super::MersStatement;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct If {
|
pub struct If {
|
||||||
@ -19,7 +22,7 @@ impl MersStatement for If {
|
|||||||
&self,
|
&self,
|
||||||
info: &mut super::CheckInfo,
|
info: &mut super::CheckInfo,
|
||||||
init_to: Option<&Type>,
|
init_to: Option<&Type>,
|
||||||
) -> Result<data::Type, super::CheckError> {
|
) -> Result<data::Type, CheckError> {
|
||||||
if init_to.is_some() {
|
if init_to.is_some() {
|
||||||
return Err("can't init to statement type If".to_string().into());
|
return Err("can't init to statement type If".to_string().into());
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fmt::{Debug, Display},
|
fmt::Debug,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
use colored::Colorize;
|
|
||||||
use line_span::LineSpanExt;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
data::{self, Data, Type},
|
data::{self, Data, Type},
|
||||||
|
errors::{CheckError, SourceRange},
|
||||||
info,
|
info,
|
||||||
parsing::{Source, SourcePos},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "run")]
|
#[cfg(feature = "run")]
|
||||||
@ -61,208 +58,6 @@ pub trait MersStatement: Debug + Send + Sync {
|
|||||||
fn source_range(&self) -> SourceRange;
|
fn source_range(&self) -> SourceRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct SourceRange {
|
|
||||||
start: SourcePos,
|
|
||||||
end: SourcePos,
|
|
||||||
}
|
|
||||||
impl From<(SourcePos, SourcePos)> for SourceRange {
|
|
||||||
fn from(value: (SourcePos, SourcePos)) -> Self {
|
|
||||||
SourceRange {
|
|
||||||
start: value.0,
|
|
||||||
end: value.1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl SourceRange {
|
|
||||||
pub fn start(&self) -> SourcePos {
|
|
||||||
self.start
|
|
||||||
}
|
|
||||||
pub fn end(&self) -> SourcePos {
|
|
||||||
self.end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct CheckError(Vec<CheckErrorComponent>);
|
|
||||||
#[allow(non_upper_case_globals)]
|
|
||||||
pub mod error_colors {
|
|
||||||
use colored::Color;
|
|
||||||
|
|
||||||
pub const UnknownVariable: Color = Color::Red;
|
|
||||||
|
|
||||||
pub const WhitespaceAfterHashtag: Color = Color::Red;
|
|
||||||
pub const HashUnknown: Color = Color::Red;
|
|
||||||
pub const HashIncludeCantLoadFile: Color = Color::Red;
|
|
||||||
pub const HashIncludeNotAString: Color = Color::Red;
|
|
||||||
pub const HashIncludeErrorInIncludedFile: Color = Color::Red;
|
|
||||||
|
|
||||||
pub const BackslashEscapeUnknown: Color = Color::Red;
|
|
||||||
pub const BackslashEscapeEOF: Color = Color::Red;
|
|
||||||
pub const StringEOF: Color = Color::Red;
|
|
||||||
|
|
||||||
pub const IfConditionNotBool: Color = Color::Red;
|
|
||||||
pub const ChainWithNonFunction: Color = Color::Yellow;
|
|
||||||
|
|
||||||
pub const Function: Color = Color::BrightMagenta;
|
|
||||||
pub const FunctionArgument: Color = Color::BrightBlue;
|
|
||||||
|
|
||||||
pub const InitFrom: Color = Color::BrightCyan;
|
|
||||||
pub const InitTo: Color = Color::Green;
|
|
||||||
pub const AssignFrom: Color = InitFrom;
|
|
||||||
pub const AssignTo: Color = InitTo;
|
|
||||||
pub const AssignTargetNonReference: Color = Color::BrightYellow;
|
|
||||||
}
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
enum CheckErrorComponent {
|
|
||||||
Message(String),
|
|
||||||
Error(CheckError),
|
|
||||||
Source(Vec<(SourceRange, Option<colored::Color>)>),
|
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CheckErrorHRConfig {
|
|
||||||
indent_start: String,
|
|
||||||
indent_default: String,
|
|
||||||
indent_end: String,
|
|
||||||
}
|
|
||||||
pub struct CheckErrorDisplay<'a> {
|
|
||||||
e: &'a CheckError,
|
|
||||||
src: Option<&'a Source>,
|
|
||||||
}
|
|
||||||
impl Display for CheckErrorDisplay<'_> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.e.human_readable(
|
|
||||||
f,
|
|
||||||
self.src,
|
|
||||||
&CheckErrorHRConfig {
|
|
||||||
indent_start: String::new(),
|
|
||||||
indent_default: String::new(),
|
|
||||||
indent_end: String::new(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl CheckError {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
CheckError(vec![])
|
|
||||||
}
|
|
||||||
fn add(mut self, v: CheckErrorComponent) -> Self {
|
|
||||||
self.0.push(v);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub(crate) fn msg(self, s: String) -> Self {
|
|
||||||
self.add(CheckErrorComponent::Message(s))
|
|
||||||
}
|
|
||||||
pub(crate) fn err(self, e: Self) -> Self {
|
|
||||||
self.add(CheckErrorComponent::Error(e))
|
|
||||||
}
|
|
||||||
pub(crate) fn src(self, s: Vec<(SourceRange, Option<colored::Color>)>) -> Self {
|
|
||||||
self.add(CheckErrorComponent::Source(s))
|
|
||||||
}
|
|
||||||
pub fn display<'a>(&'a self, src: &'a Source) -> CheckErrorDisplay<'a> {
|
|
||||||
CheckErrorDisplay {
|
|
||||||
e: self,
|
|
||||||
src: Some(src),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn display_no_src<'a>(&'a self) -> CheckErrorDisplay<'a> {
|
|
||||||
CheckErrorDisplay { e: self, src: None }
|
|
||||||
}
|
|
||||||
// will, unless empty, end in a newline
|
|
||||||
fn human_readable(
|
|
||||||
&self,
|
|
||||||
f: &mut std::fmt::Formatter<'_>,
|
|
||||||
src: Option<&Source>,
|
|
||||||
cfg: &CheckErrorHRConfig,
|
|
||||||
) -> std::fmt::Result {
|
|
||||||
let len = self.0.len();
|
|
||||||
for (i, component) in self.0.iter().enumerate() {
|
|
||||||
macro_rules! indent {
|
|
||||||
() => {
|
|
||||||
if i + 1 == len {
|
|
||||||
&cfg.indent_end
|
|
||||||
} else if i == 0 {
|
|
||||||
&cfg.indent_start
|
|
||||||
} else {
|
|
||||||
&cfg.indent_default
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
match component {
|
|
||||||
CheckErrorComponent::Message(msg) => writeln!(f, "{}{msg}", indent!())?,
|
|
||||||
CheckErrorComponent::Error(err) => {
|
|
||||||
let mut cfg = cfg.clone();
|
|
||||||
cfg.indent_start.push_str("│");
|
|
||||||
cfg.indent_default.push_str("│");
|
|
||||||
cfg.indent_end.push_str("└");
|
|
||||||
err.human_readable(f, src, &cfg)?;
|
|
||||||
}
|
|
||||||
CheckErrorComponent::Source(highlights) => {
|
|
||||||
if let Some(src) = src {
|
|
||||||
let start = highlights.iter().map(|v| v.0.start.pos()).min();
|
|
||||||
let end = highlights.iter().map(|v| v.0.start.pos()).max();
|
|
||||||
if let (Some(start), Some(end)) = (start, end) {
|
|
||||||
writeln!(f, "{}Line(s) [?] ({start}..{end})", indent!())?;
|
|
||||||
let start = src.get_line_start(start);
|
|
||||||
let end = src.get_line_end(end);
|
|
||||||
let lines = src.src()[start..end].line_spans().collect::<Vec<_>>();
|
|
||||||
for line in lines {
|
|
||||||
let line_start = line.start();
|
|
||||||
let line_end = line.end();
|
|
||||||
let line = line.as_str();
|
|
||||||
writeln!(f, "{} {line}", indent!())?;
|
|
||||||
let mut right = 0;
|
|
||||||
for (pos, color) in highlights {
|
|
||||||
if let Some(color) = color {
|
|
||||||
let highlight_start = pos.start.pos() - start;
|
|
||||||
let highlight_end = pos.end.pos() - start;
|
|
||||||
if highlight_start < line_end && highlight_end > line_start
|
|
||||||
{
|
|
||||||
// where the highlight starts in this line
|
|
||||||
let hl_start =
|
|
||||||
highlight_start.saturating_sub(line_start);
|
|
||||||
// highlight would be further left than cursor, so we need a new line
|
|
||||||
if hl_start < right {
|
|
||||||
right = 0;
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
|
||||||
// length of the highlight
|
|
||||||
let hl_len = highlight_end
|
|
||||||
.saturating_sub(line_start)
|
|
||||||
.saturating_sub(hl_start);
|
|
||||||
let hl_space = hl_start - right;
|
|
||||||
let print_indent = right == 0;
|
|
||||||
let hl_len = hl_len.min(line.len() - right);
|
|
||||||
right += hl_space + hl_len;
|
|
||||||
if print_indent && right != 0 {
|
|
||||||
write!(f, "{} ", indent!())?;
|
|
||||||
}
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}{}",
|
|
||||||
" ".repeat(hl_space),
|
|
||||||
"~".repeat(hl_len).color(*color)
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if right != 0 {
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<String> for CheckError {
|
|
||||||
fn from(value: String) -> Self {
|
|
||||||
Self::new().msg(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Info = info::Info<Local>;
|
pub type Info = info::Info<Local>;
|
||||||
pub type CheckInfo = info::Info<CheckLocal>;
|
pub type CheckInfo = info::Info<CheckLocal>;
|
||||||
|
|
||||||
|
@ -2,9 +2,12 @@ use std::{collections::VecDeque, sync::Arc};
|
|||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
|
||||||
use crate::data::{self, tuple::TupleT, Data, Type};
|
use crate::{
|
||||||
|
data::{self, tuple::TupleT, Data, Type},
|
||||||
|
errors::{error_colors, SourceRange},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{error_colors, MersStatement, SourceRange};
|
use super::MersStatement;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Tuple {
|
pub struct Tuple {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
use crate::data::{Data, Type};
|
use crate::{
|
||||||
|
data::{Data, Type},
|
||||||
|
errors::SourceRange,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{MersStatement, SourceRange};
|
use super::{CheckInfo, MersStatement};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Value {
|
pub struct Value {
|
||||||
@ -14,7 +17,7 @@ impl MersStatement for Value {
|
|||||||
}
|
}
|
||||||
fn check_custom(
|
fn check_custom(
|
||||||
&self,
|
&self,
|
||||||
info: &mut super::CheckInfo,
|
_info: &mut CheckInfo,
|
||||||
init_to: Option<&Type>,
|
init_to: Option<&Type>,
|
||||||
) -> Result<crate::data::Type, super::CheckError> {
|
) -> Result<crate::data::Type, super::CheckError> {
|
||||||
if init_to.is_some() {
|
if init_to.is_some() {
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use crate::data::{self, Data, Type};
|
use crate::{
|
||||||
|
data::{self, Data, Type},
|
||||||
|
errors::SourceRange,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{MersStatement, SourceRange};
|
use super::MersStatement;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Variable {
|
pub struct Variable {
|
||||||
|
Loading…
Reference in New Issue
Block a user