-f+c will print the parsed script with colored highlighting

This commit is contained in:
mark 2023-05-19 21:25:05 +02:00
parent 79797e6718
commit b5924b5da1
15 changed files with 417 additions and 222 deletions

View File

@ -20,8 +20,9 @@ for word text.regex("\\S+").assume_no_enum()
if words > 0 { if words > 0 {
print(word + " ") print(word + " ")
words = words - 1 words = words - 1
sleep(0.1)
} else if words == 0 { } else if words == 0 {
println(word) println(word)
words = rnd() words = rnd()
sleep(0.75) sleep(0.5)
} }

7
mers/Cargo.lock generated
View File

@ -159,6 +159,12 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "colorize"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc17e449bc7854c50b943d113a98bc0e01dc6585d2c66eaa09ca645ebd8a7e62"
[[package]] [[package]]
name = "core-foundation-sys" name = "core-foundation-sys"
version = "0.8.4" version = "0.8.4"
@ -643,6 +649,7 @@ dependencies = [
name = "mers" name = "mers"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"colorize",
"edit", "edit",
"notify", "notify",
"nu-plugin", "nu-plugin",

View File

@ -16,6 +16,7 @@ regex = "1.7.2"
static_assertions = "1.1.0" static_assertions = "1.1.0"
nu-plugin = { version = "0.79.0", optional = true } nu-plugin = { version = "0.79.0", optional = true }
nu-protocol = { version = "0.79.0", features = ["plugin"], optional = true } nu-protocol = { version = "0.79.0", features = ["plugin"], optional = true }
colorize = "0.1.0"
[features] [features]
# default = ["nushell_plugin"] # default = ["nushell_plugin"]

View File

@ -7,6 +7,8 @@ pub mod fs_watcher {
thread::{self, JoinHandle}, thread::{self, JoinHandle},
}; };
use crate::lang::fmtgs::FormatGs;
#[derive(Debug)] #[derive(Debug)]
pub struct Error(String); pub struct Error(String);

View File

@ -1,4 +1,5 @@
use std::{ use std::{
io::Write,
path::PathBuf, path::PathBuf,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
time::Duration, time::Duration,
@ -835,9 +836,15 @@ impl BuiltinFunction {
BuiltinFunction::Print => args[0].run(info).operate_on_data_immut(|v| { BuiltinFunction::Print => args[0].run(info).operate_on_data_immut(|v| {
if let VDataEnum::String(arg) = v { if let VDataEnum::String(arg) = v {
#[cfg(not(feature = "nushell_plugin"))] #[cfg(not(feature = "nushell_plugin"))]
print!("{}", arg); {
print!("{}", arg);
std::io::stdout().flush();
}
#[cfg(feature = "nushell_plugin")] #[cfg(feature = "nushell_plugin")]
eprint!("{}", arg); {
eprint!("{}", arg);
std::io::stderr().flush();
}
VDataEnum::Tuple(vec![]).to() VDataEnum::Tuple(vec![]).to()
} else { } else {
unreachable!("print function called with non-string arg") unreachable!("print function called with non-string arg")

View File

@ -1,6 +1,11 @@
use std::fmt::{self, Display, Formatter, Pointer}; use std::fmt::{self, Display, Formatter, Pointer};
use super::{code_macro::Macro, global_info::GlobalScriptInfo, val_data::VData, val_type::VType}; use crate::lang::global_info::ColorFormatMode;
use super::{
code_macro::Macro, fmtgs::FormatGs, global_info::GlobalScriptInfo, val_data::VData,
val_type::VType,
};
#[derive(Debug)] #[derive(Debug)]
pub enum SStatementEnum { pub enum SStatementEnum {
@ -82,101 +87,142 @@ impl SFunction {
// //
impl SStatementEnum { impl FormatGs for SStatementEnum {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result { fn fmtgs(
&self,
f: &mut Formatter,
info: Option<&GlobalScriptInfo>,
form: &mut super::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result {
match self { match self {
Self::Value(v) => v.fmtgs(f, info), Self::Value(v) => v.fmtgs(f, info, form, file),
Self::Tuple(v) => { Self::Tuple(v) => {
write!(f, "[")?; write!(f, "{}", form.open_bracket(info, "[".to_owned()))?;
for (i, v) in v.iter().enumerate() { for (i, v) in v.iter().enumerate() {
if i > 0 { if i > 0 {
write!(f, " ")?; write!(f, " ")?;
} }
v.fmtgs(f, info)?; v.fmtgs(f, info, form, file)?;
} }
write!(f, "]") write!(f, "{}", form.close_bracket(info, "]".to_owned()))
} }
Self::List(v) => { Self::List(v) => {
write!(f, "[")?; write!(f, "{}", form.open_bracket(info, "[".to_owned()))?;
for (i, v) in v.iter().enumerate() { for (i, v) in v.iter().enumerate() {
v.fmtgs(f, info)?; v.fmtgs(f, info, form, file)?;
write!(f, " ")?; write!(f, " ")?;
} }
write!(f, "...]") write!(f, "{}", form.close_bracket(info, "...]".to_owned()))
} }
Self::Variable(var, reference) => { Self::Variable(var, reference) => {
if *reference { if *reference {
write!(f, "&{var}") write!(f, "{}", form.variable_ref_symbol(info, "&".to_owned()))?;
} else {
write!(f, "{var}")
} }
write!(f, "{}", form.variable(info, var.to_owned()))
} }
Self::FunctionCall(func, args) => { Self::FunctionCall(func, args) => {
write!(f, "{func}(")?; write!(
for arg in args { f,
arg.fmtgs(f, info)?; "{}{}",
form.fncall(info, func.to_owned()),
form.open_bracket(info, "(".to_owned())
)?;
for (i, arg) in args.iter().enumerate() {
if i != 0 {
write!(f, " ");
}
arg.fmtgs(f, info, form, file)?;
} }
write!(f, ")") write!(f, "{}", form.close_bracket(info, ")".to_owned()))
} }
Self::FunctionDefinition(name, func) => { Self::FunctionDefinition(name, func) => {
if let Some(name) = name { if let Some(name) = name {
write!(f, "{name}")?; write!(
f,
"{} {}",
form.fndef_fn(info, "fn".to_owned()),
form.fndef_name(info, name.to_owned())
)?;
} }
func.fmtgs(f, info) func.fmtgs(f, info, form, file)
} }
Self::Block(b) => b.fmtgs(f, info), Self::Block(b) => b.fmtgs(f, info, form, file),
Self::If(condition, yes, no) => { Self::If(condition, yes, no) => {
write!(f, "if ")?; write!(f, "{} ", form.if_if(info, "if".to_owned()))?;
condition.fmtgs(f, info)?; condition.fmtgs(f, info, form, file)?;
write!(f, " ")?; write!(f, " ")?;
yes.fmtgs(f, info)?; yes.fmtgs(f, info, form, file)?;
if let Some(no) = no { if let Some(no) = no {
write!(f, " else ")?; write!(f, " {} ", form.if_else(info, "else".to_owned()))?;
no.fmtgs(f, info)?; no.fmtgs(f, info, form, file)?;
} }
Ok(()) Ok(())
} }
Self::Loop(b) => { Self::Loop(b) => {
write!(f, "loop ")?; write!(f, "{} ", form.loop_loop(info, "loop".to_owned()))?;
b.fmtgs(f, info) b.fmtgs(f, info, form, file)
} }
Self::For(var, i, b) => { Self::For(var, i, b) => {
write!(f, "for {} ", var)?; write!(f, "{} {} ", form.loop_for(info, "for".to_owned()), var)?;
i.fmtgs(f, info)?; i.fmtgs(f, info, form, file)?;
write!(f, " ")?; write!(f, " ")?;
b.fmtgs(f, info) b.fmtgs(f, info, form, file)
} }
Self::Switch(var, arms, force) => { Self::Switch(var, arms, force) => {
if *force { if *force {
writeln!(f, "switch! {var} {{")?; writeln!(
f,
"{} {var} {}",
form.kw_switch(info, "switch!".to_owned()),
form.open_bracket(info, "{".to_owned())
)?;
} else { } else {
writeln!(f, "switch {var} {{")?; writeln!(
f,
"{} {var} {}",
form.kw_switch(info, "switch".to_owned()),
form.open_bracket(info, "{".to_owned())
)?;
} }
form.go_deeper();
for (t, action) in arms { for (t, action) in arms {
t.fmtgs(f, info)?; write!(f, "{}", form.line_prefix())?;
t.fmtgs(f, info, form, file)?;
write!(f, " ")?; write!(f, " ")?;
action.fmtgs(f, info)?; action.fmtgs(f, info, form, file)?;
writeln!(f)?; writeln!(f)?;
} }
write!(f, "}}") form.go_shallower();
write!(f, "{}", form.line_prefix())?;
write!(f, "{}", form.close_bracket(info, "}".to_owned()))
} }
Self::Match(var, arms) => { Self::Match(var, arms) => {
write!(f, "match {var} {{")?; write!(
f,
"{} {var} {}",
form.kw_match(info, "match".to_owned()),
form.open_bracket(info, "{".to_owned())
)?;
form.go_deeper();
for (condition, action) in arms { for (condition, action) in arms {
condition.fmtgs(f, info)?; write!(f, "{}", form.line_prefix())?;
condition.fmtgs(f, info, form, file)?;
write!(f, " ")?; write!(f, " ")?;
action.fmtgs(f, info)?; action.fmtgs(f, info, form, file)?;
writeln!(f)?; writeln!(f)?;
} }
write!(f, "}}") form.go_shallower();
write!(f, "{}", form.line_prefix())?;
write!(f, "{}", form.close_bracket(info, "}".to_owned()))
} }
Self::IndexFixed(statement, index) => { Self::IndexFixed(statement, index) => {
statement.fmtgs(f, info)?; statement.fmtgs(f, info, form, file)?;
write!(f, ".{index}") write!(f, ".{index}")
} }
Self::EnumVariant(variant, inner) => { Self::EnumVariant(variant, inner) => {
write!(f, "{variant}: ")?; write!(f, "{variant}: ")?;
inner.fmtgs(f, info) inner.fmtgs(f, info, form, file)
} }
Self::TypeDefinition(name, t) => write!(f, "type {name} {t}"), Self::TypeDefinition(name, t) => write!(f, "type {name} {t}"),
Self::Macro(m) => { Self::Macro(m) => {
@ -187,32 +233,58 @@ impl SStatementEnum {
} }
impl Display for SStatementEnum { impl Display for SStatementEnum {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.fmtgs(f, None) self.fmtgs(f, None, &mut super::fmtgs::FormatInfo::default(), None)
} }
} }
impl SStatement { impl FormatGs for SStatement {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result { fn fmtgs(
&self,
f: &mut Formatter,
info: Option<&GlobalScriptInfo>,
form: &mut super::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result {
if let Some((opt, derefs)) = &self.output_to { if let Some((opt, derefs)) = &self.output_to {
if let Some(forced_type) = &self.force_output_type { // TODO!
write!(f, "{}{}::", "*".repeat(*derefs), opt)?; match opt.statement.as_ref() {
forced_type.fmtgs(f, info)?; SStatementEnum::Variable(name, is_ref) => {
write!(f, " = ")?; let derefs = if !is_ref { *derefs + 1 } else { *derefs };
} else { write!(
write!(f, "{}{} = ", "*".repeat(*derefs), opt)?; f,
"{}{} = ",
"*".repeat(derefs),
SStatementEnum::Variable(name.to_owned(), false).with(info, file)
)?;
}
_ => {
if let Some(forced_type) = &self.force_output_type {
write!(f, "{}{}::", "*".repeat(*derefs), opt.with(info, file))?;
forced_type.fmtgs(f, info, form, file)?;
write!(f, " = ")?;
} else {
write!(f, "{}{} = ", "*".repeat(*derefs), opt.with(info, file))?;
}
}
} }
} }
self.statement.fmtgs(f, info) self.statement.fmtgs(f, info, form, file)
} }
} }
impl Display for SStatement { impl Display for SStatement {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.fmtgs(f, None) self.fmtgs(f, None, &mut super::fmtgs::FormatInfo::default(), None)
} }
} }
impl SFunction { impl FormatGs for SFunction {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result { fn fmtgs(
&self,
f: &mut Formatter,
info: Option<&GlobalScriptInfo>,
form: &mut super::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result {
write!(f, "(")?; write!(f, "(")?;
for (i, (name, t)) in self.inputs.iter().enumerate() { for (i, (name, t)) in self.inputs.iter().enumerate() {
if i > 0 { if i > 0 {
@ -220,25 +292,35 @@ impl SFunction {
} else { } else {
write!(f, "{name} ")?; write!(f, "{name} ")?;
} }
t.fmtgs(f, info)?; t.fmtgs(f, info, form, file)?;
} }
write!(f, ") ")?; write!(f, ") ")?;
self.block.fmtgs(f, info) self.block.fmtgs(f, info, form, file)
} }
} }
impl SBlock { impl FormatGs for SBlock {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result { fn fmtgs(
&self,
f: &mut Formatter,
info: Option<&GlobalScriptInfo>,
form: &mut super::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result {
match self.statements.len() { match self.statements.len() {
0 => write!(f, "{{}}"), 0 => write!(f, "{{}}"),
1 => self.statements[0].fmtgs(f, info), // 1 => self.statements[0].fmtgs(f, info, form, file),
_ => { _ => {
writeln!(f, "{{")?; writeln!(f, "{}", form.open_bracket(info, "{".to_owned()))?;
form.go_deeper();
for statement in self.statements.iter() { for statement in self.statements.iter() {
statement.fmtgs(f, info)?; write!(f, "{}", form.line_prefix())?;
statement.fmtgs(f, info, form, file)?;
writeln!(f)?; writeln!(f)?;
} }
write!(f, "}}") form.go_shallower();
write!(f, "{}", form.line_prefix())?;
write!(f, "{}", form.close_bracket(info, "}".to_owned()))
} }
} }
} }

View File

@ -373,7 +373,6 @@ impl RStatementEnum {
} }
} }
#[derive(Debug)]
pub struct RScript { pub struct RScript {
main: RFunction, main: RFunction,
info: GSInfo, info: GSInfo,

View File

@ -1,5 +1,6 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
default,
fmt::Display, fmt::Display,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -8,13 +9,13 @@ use crate::libs;
use super::{ use super::{
builtins, builtins,
fmtgs::Color,
val_data::VDataEnum, val_data::VDataEnum,
val_type::{VSingleType, VType}, val_type::{VSingleType, VType},
}; };
pub type GSInfo = Arc<GlobalScriptInfo>; pub type GSInfo = Arc<GlobalScriptInfo>;
#[derive(Debug)]
pub struct GlobalScriptInfo { pub struct GlobalScriptInfo {
pub libs: Vec<libs::Lib>, pub libs: Vec<libs::Lib>,
pub lib_fns: HashMap<String, (usize, usize)>, pub lib_fns: HashMap<String, (usize, usize)>,
@ -24,10 +25,61 @@ pub struct GlobalScriptInfo {
pub custom_type_names: HashMap<String, usize>, pub custom_type_names: HashMap<String, usize>,
pub custom_types: Vec<VType>, pub custom_types: Vec<VType>,
#[cfg(debug_assertions)] pub formatter: ColorFormatter,
pub log: Logger, pub log: Logger,
} }
pub struct ColorFormatter {
pub mode: ColorFormatMode,
pub bracket_colors: Vec<Color>,
pub value_string_quotes_color: Color,
pub value_string_content_color: Color,
pub keyword_if_color: Color,
pub keyword_else_color: Color,
pub keyword_loop_color: Color,
pub keyword_for_color: Color,
pub keyword_switch_color: Color,
pub keyword_match_color: Color,
pub function_call_color: Color,
pub function_def_fn_color: Color,
pub function_def_name_color: Color,
pub variable_color: Color,
}
impl Default for ColorFormatter {
fn default() -> Self {
Self {
mode: ColorFormatMode::Plain,
bracket_colors: vec![
Color::Red,
Color::Yellow,
Color::Cyan,
Color::Blue,
Color::Magenta,
],
value_string_quotes_color: Color::Grey,
value_string_content_color: Color::Cyan,
keyword_if_color: Color::Yellow,
keyword_else_color: Color::Yellow,
keyword_loop_color: Color::Yellow,
keyword_for_color: Color::Yellow,
keyword_switch_color: Color::Yellow,
keyword_match_color: Color::Yellow,
function_call_color: Color::Magenta,
function_def_fn_color: Color::Blue,
function_def_name_color: Color::Magenta,
variable_color: Color::Green,
}
}
}
#[derive(Debug)]
pub enum ColorFormatMode {
/// No color.
Plain,
/// For terminal output
Colorize,
}
impl GlobalScriptInfo { impl GlobalScriptInfo {
pub fn to_arc(self) -> GSInfo { pub fn to_arc(self) -> GSInfo {
Arc::new(self) Arc::new(self)
@ -42,7 +94,7 @@ impl Default for GlobalScriptInfo {
enum_variants: Self::default_enum_variants(), enum_variants: Self::default_enum_variants(),
custom_type_names: HashMap::new(), custom_type_names: HashMap::new(),
custom_types: vec![], custom_types: vec![],
#[cfg(debug_assertions)] formatter: Default::default(),
log: Logger::new(), log: Logger::new(),
} }
} }
@ -57,20 +109,21 @@ impl GlobalScriptInfo {
} }
} }
#[cfg(debug_assertions)]
#[derive(Debug)] #[derive(Debug)]
pub struct Logger { pub struct Logger {
logs: Arc<Mutex<Vec<LogMsg>>>, logs: Arc<Mutex<Vec<LogMsg>>>,
pub after_parse: LogKind,
pub vdata_clone: LogKind, pub vdata_clone: LogKind,
pub vtype_fits_in: LogKind, pub vtype_fits_in: LogKind,
pub vsingletype_fits_in: LogKind, pub vsingletype_fits_in: LogKind,
} }
#[cfg(debug_assertions)]
impl Logger { impl Logger {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
logs: Arc::new(Mutex::new(vec![])), logs: Arc::new(Mutex::new(vec![])),
after_parse: Default::default(),
vdata_clone: Default::default(), vdata_clone: Default::default(),
vtype_fits_in: Default::default(), vtype_fits_in: Default::default(),
vsingletype_fits_in: Default::default(), vsingletype_fits_in: Default::default(),
@ -78,17 +131,17 @@ impl Logger {
} }
} }
#[cfg(debug_assertions)]
#[derive(Debug)] #[derive(Debug)]
pub enum LogMsg { pub enum LogMsg {
AfterParse(String),
VDataClone(Option<String>, VDataEnum, usize, usize), VDataClone(Option<String>, VDataEnum, usize, usize),
VTypeFitsIn(VType, VType, Vec<VSingleType>), VTypeFitsIn(VType, VType, Vec<VSingleType>),
VSingleTypeFitsIn(VSingleType, VSingleType, bool), VSingleTypeFitsIn(VSingleType, VSingleType, bool),
} }
#[cfg(debug_assertions)]
impl Logger { impl Logger {
pub fn log(&self, msg: LogMsg) { pub fn log(&self, msg: LogMsg) {
let kind = match msg { let kind = match msg {
LogMsg::AfterParse(..) => &self.after_parse,
LogMsg::VDataClone(..) => &self.vdata_clone, LogMsg::VDataClone(..) => &self.vdata_clone,
LogMsg::VTypeFitsIn(..) => &self.vtype_fits_in, LogMsg::VTypeFitsIn(..) => &self.vtype_fits_in,
LogMsg::VSingleTypeFitsIn(..) => &self.vsingletype_fits_in, LogMsg::VSingleTypeFitsIn(..) => &self.vsingletype_fits_in,
@ -103,14 +156,16 @@ impl Logger {
} }
} }
} }
#[cfg(debug_assertions)]
impl Display for LogMsg { impl Display for LogMsg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::AfterParse(code) => {
write!(f, "AfterParse :: {code}")
}
Self::VDataClone(varname, data, src_addr, new_addr) => { Self::VDataClone(varname, data, src_addr, new_addr) => {
write!( write!(
f, f,
"VDataClone :: {data} ({}{src_addr} -> {new_addr})", "VDataClone ::::\n{data} ({}{src_addr} -> {new_addr})",
if let Some(v) = varname { if let Some(v) = varname {
format!("{v} | ") format!("{v} | ")
} else { } else {
@ -126,13 +181,11 @@ impl Display for LogMsg {
} }
} }
#[cfg(debug_assertions)]
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct LogKind { pub struct LogKind {
pub stderr: bool, pub stderr: bool,
pub log: bool, pub log: bool,
} }
#[cfg(debug_assertions)]
impl LogKind { impl LogKind {
pub fn log(&self) -> bool { pub fn log(&self) -> bool {
self.stderr || self.log self.stderr || self.log

View File

@ -2,6 +2,7 @@ pub mod builtins;
pub mod code_macro; pub mod code_macro;
pub mod code_parsed; pub mod code_parsed;
pub mod code_runnable; pub mod code_runnable;
pub mod fmtgs;
pub mod global_info; pub mod global_info;
pub mod to_runnable; pub mod to_runnable;
pub mod val_data; pub mod val_data;

View File

@ -19,6 +19,7 @@ use super::{
code_macro::Macro, code_macro::Macro,
code_parsed::{SBlock, SFunction, SStatement, SStatementEnum}, code_parsed::{SBlock, SFunction, SStatement, SStatementEnum},
code_runnable::{RBlock, RFunction, RScript, RStatement, RStatementEnum}, code_runnable::{RBlock, RFunction, RScript, RStatement, RStatementEnum},
fmtgs::FormatGs,
global_info::GSInfo, global_info::GSInfo,
}; };
@ -51,18 +52,20 @@ impl Debug for ToRunnableError {
} }
} }
// TODO: // TODO:
// - Don't use {} to format, use .fmtgs(f, info) instead! // - Don't use {} to format, use .fmtgs(f, info, form, file) instead!
// - Show location in code where the error was found // - Show location in code where the error was found
impl Display for ToRunnableError { impl Display for ToRunnableError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmtgs(f, None) self.fmtgs(f, None, &mut super::fmtgs::FormatInfo::default(), None)
} }
} }
impl ToRunnableError { impl FormatGs for ToRunnableError {
pub fn fmtgs( fn fmtgs(
&self, &self,
f: &mut std::fmt::Formatter, f: &mut std::fmt::Formatter,
info: Option<&GlobalScriptInfo>, info: Option<&GlobalScriptInfo>,
form: &mut super::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result { ) -> std::fmt::Result {
match self { match self {
Self::MainWrongInput => write!( Self::MainWrongInput => write!(
@ -75,9 +78,9 @@ impl ToRunnableError {
Self::CannotDeclareVariableWithDereference(v) => write!(f, "Cannot declare a variable and dereference it (variable '{v}')."), Self::CannotDeclareVariableWithDereference(v) => write!(f, "Cannot declare a variable and dereference it (variable '{v}')."),
Self::CannotDereferenceTypeNTimes(og_type, derefs_wanted, last_valid_type) => { Self::CannotDereferenceTypeNTimes(og_type, derefs_wanted, last_valid_type) => {
write!(f, "Cannot dereference type ")?; write!(f, "Cannot dereference type ")?;
og_type.fmtgs(f, info)?; og_type.fmtgs(f, info, form, file)?;
write!(f, " {derefs_wanted} times (stopped at ")?; write!(f, " {derefs_wanted} times (stopped at ")?;
last_valid_type.fmtgs(f, info); last_valid_type.fmtgs(f, info, form, file);
write!(f, ")")?; write!(f, ")")?;
Ok(()) Ok(())
}, },
@ -89,28 +92,28 @@ impl ToRunnableError {
problematic, problematic,
} => { } => {
write!(f, "Invalid type: Expected ")?; write!(f, "Invalid type: Expected ")?;
expected.fmtgs(f, info)?; expected.fmtgs(f, info, form, file)?;
write!(f, " but found ")?; write!(f, " but found ")?;
found.fmtgs(f, info)?; found.fmtgs(f, info, form, file)?;
write!(f, ", which includes ")?; write!(f, ", which includes ")?;
problematic.fmtgs(f, info)?; problematic.fmtgs(f, info, form, file)?;
write!(f, " which is not covered.")?; write!(f, " which is not covered.")?;
Ok(()) Ok(())
} }
Self::CaseForceButTypeNotCovered(v) => { Self::CaseForceButTypeNotCovered(v) => {
write!(f, "Switch! statement, but not all types covered. Types to cover: ")?; write!(f, "Switch! statement, but not all types covered. Types to cover: ")?;
v.fmtgs(f, info)?; v.fmtgs(f, info, form, file)?;
Ok(()) Ok(())
} }
Self::MatchConditionInvalidReturn(v) => { Self::MatchConditionInvalidReturn(v) => {
write!(f, "match statement condition returned ")?; write!(f, "match statement condition returned ")?;
v.fmtgs(f, info)?; v.fmtgs(f, info, form, file)?;
write!(f, ", which is not necessarily a tuple of size 0 to 1.")?; write!(f, ", which is not necessarily a tuple of size 0 to 1.")?;
Ok(()) Ok(())
} }
Self::NotIndexableFixed(t, i) => { Self::NotIndexableFixed(t, i) => {
write!(f, "Cannot use fixed-index {i} on type ")?; write!(f, "Cannot use fixed-index {i} on type ")?;
t.fmtgs(f, info)?; t.fmtgs(f, info, form, file)?;
write!(f, ".")?; write!(f, ".")?;
Ok(()) Ok(())
} }
@ -118,7 +121,7 @@ impl ToRunnableError {
write!(f, "Wrong arguments for builtin function \"{}\":", builtin_name)?; write!(f, "Wrong arguments for builtin function \"{}\":", builtin_name)?;
for arg in args { for arg in args {
write!(f, " ")?; write!(f, " ")?;
arg.fmtgs(f, info)?; arg.fmtgs(f, info, form, file)?;
} }
write!(f, ".") write!(f, ".")
} }
@ -126,15 +129,15 @@ impl ToRunnableError {
write!(f, "Wrong arguments for library function {}:", name)?; write!(f, "Wrong arguments for library function {}:", name)?;
for arg in args { for arg in args {
write!(f, " ")?; write!(f, " ")?;
arg.fmtgs(f, info)?; arg.fmtgs(f, info, form, file)?;
} }
write!(f, ".") write!(f, ".")
} }
Self::CannotAssignTo(val, target) => { Self::CannotAssignTo(val, target) => {
write!(f, "Cannot assign type ")?; write!(f, "Cannot assign type ")?;
val.fmtgs(f, info)?; val.fmtgs(f, info, form, file)?;
write!(f, " to ")?; write!(f, " to ")?;
target.fmtgs(f, info)?; target.fmtgs(f, info, form, file)?;
write!(f, ".")?; write!(f, ".")?;
Ok(()) Ok(())
}, },
@ -143,11 +146,11 @@ impl ToRunnableError {
} }
Self::StatementRequiresOutputTypeToBeAButItActuallyOutputsBWhichDoesNotFitInA(required, real, problematic) => { Self::StatementRequiresOutputTypeToBeAButItActuallyOutputsBWhichDoesNotFitInA(required, real, problematic) => {
write!(f, "the statement requires its output type to be ")?; write!(f, "the statement requires its output type to be ")?;
required.fmtgs(f, info)?; required.fmtgs(f, info, form, file)?;
write!(f, ", but its real output type is ")?; write!(f, ", but its real output type is ")?;
real.fmtgs(f, info)?; real.fmtgs(f, info, form, file)?;
write!(f, ", which doesn't fit in the required type because of the problematic types ")?; write!(f, ", which doesn't fit in the required type because of the problematic types ")?;
problematic.fmtgs(f, info)?; problematic.fmtgs(f, info, form, file)?;
write!(f, ".")?; write!(f, ".")?;
Ok(()) Ok(())
} }

View File

@ -4,15 +4,14 @@ use std::{
sync::{Arc, Mutex, MutexGuard}, sync::{Arc, Mutex, MutexGuard},
}; };
use super::global_info::LogMsg;
use super::{ use super::{
code_runnable::RFunction, code_runnable::RFunction,
fmtgs::FormatGs,
global_info::{GSInfo, GlobalScriptInfo}, global_info::{GSInfo, GlobalScriptInfo},
val_type::{VSingleType, VType}, val_type::{VSingleType, VType},
}; };
#[cfg(debug_assertions)]
use super::global_info::LogMsg;
#[derive(Debug)] #[derive(Debug)]
pub enum VDataEnum { pub enum VDataEnum {
Bool(bool), Bool(bool),
@ -117,11 +116,13 @@ impl VData {
// *self doesn't modify the ::Data, it instead points the value that wraps it to a new ::Data, leaving the old one as it was. // *self doesn't modify the ::Data, it instead points the value that wraps it to a new ::Data, leaving the old one as it was.
// for proof: data is untouched, only the new_data is ever modified. // for proof: data is untouched, only the new_data is ever modified.
let new_vdata = VDataInner::Data(0, new_data).to(); let new_vdata = VDataInner::Data(0, new_data).to();
#[cfg(debug_assertions)]
if info.log.vdata_clone.log() { if info.log.vdata_clone.log() {
drop(lock); drop(lock);
info.log.log(LogMsg::VDataClone( info.log.log(LogMsg::VDataClone(
#[cfg(debug_assertions)]
self.1.clone(), self.1.clone(),
#[cfg(not(debug_assertions))]
None,
self.inner_cloned(), self.inner_cloned(),
Arc::as_ptr(&self.0) as usize, Arc::as_ptr(&self.0) as usize,
Arc::as_ptr(&new_vdata.0) as usize, Arc::as_ptr(&new_vdata.0) as usize,
@ -187,9 +188,15 @@ impl Clone for VData {
self.clone_data() self.clone_data()
} }
} }
impl VData { impl FormatGs for VData {
pub fn fmtgs(&self, f: &mut Formatter<'_>, info: Option<&GlobalScriptInfo>) -> fmt::Result { fn fmtgs(
self.operate_on_data_immut(|v| v.fmtgs(f, info)) &self,
f: &mut Formatter,
info: Option<&GlobalScriptInfo>,
form: &mut super::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result {
self.operate_on_data_immut(|v| v.fmtgs(f, info, form, file))
} }
} }
impl Debug for VData { impl Debug for VData {
@ -476,7 +483,12 @@ pub mod thread {
pub struct VDataWInfo(VData, GSInfo); pub struct VDataWInfo(VData, GSInfo);
impl Display for VDataWInfo { impl Display for VDataWInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmtgs(f, Some(&self.1)) self.0.fmtgs(
f,
Some(&self.1),
&mut super::fmtgs::FormatInfo::default(),
None,
)
} }
} }
impl VData { impl VData {
@ -485,39 +497,51 @@ impl VData {
} }
} }
impl VDataEnum { impl FormatGs for VDataEnum {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result { fn fmtgs(
&self,
f: &mut Formatter,
info: Option<&GlobalScriptInfo>,
form: &mut super::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result {
match self { match self {
Self::Bool(true) => write!(f, "true"), Self::Bool(true) => write!(f, "true"),
Self::Bool(false) => write!(f, "false"), Self::Bool(false) => write!(f, "false"),
Self::Int(v) => write!(f, "{v}"), Self::Int(v) => write!(f, "{v}"),
Self::Float(v) => write!(f, "{v}"), Self::Float(v) => write!(f, "{v}"),
Self::String(v) => write!(f, "\"{v}\""), Self::String(v) => write!(
f,
"{}{}{}",
form.value_string_quotes(info, "\"".to_owned()),
form.value_string_content(info, v.to_owned()),
form.value_string_quotes(info, "\"".to_owned())
),
Self::Tuple(v) => { Self::Tuple(v) => {
write!(f, "[")?; write!(f, "[")?;
for (i, v) in v.iter().enumerate() { for (i, v) in v.iter().enumerate() {
if i > 0 { if i > 0 {
write!(f, " ")?; write!(f, " ")?;
} }
v.fmtgs(f, info)?; v.fmtgs(f, info, form, file)?;
} }
write!(f, "]") write!(f, "]")
} }
Self::List(_t, v) => { Self::List(_t, v) => {
write!(f, "[")?; write!(f, "[")?;
for (i, v) in v.iter().enumerate() { for (i, v) in v.iter().enumerate() {
v.fmtgs(f, info)?; v.fmtgs(f, info, form, file)?;
write!(f, " ")?; write!(f, " ")?;
} }
write!(f, "...]") write!(f, "...]")
} }
Self::Function(func) => { Self::Function(func) => {
VSingleType::Function(func.input_output_map.clone()).fmtgs(f, info) VSingleType::Function(func.input_output_map.clone()).fmtgs(f, info, form, file)
} }
Self::Thread(..) => write!(f, "[TODO] THREAD"), Self::Thread(..) => write!(f, "[TODO] THREAD"),
Self::Reference(inner) => { Self::Reference(inner) => {
write!(f, "&")?; write!(f, "&")?;
inner.fmtgs(f, info) inner.fmtgs(f, info, form, file)
} }
Self::EnumVariant(variant, inner) => { Self::EnumVariant(variant, inner) => {
if let Some(name) = if let Some(info) = info { if let Some(name) = if let Some(info) = info {
@ -535,13 +559,13 @@ impl VDataEnum {
} else { } else {
write!(f, "{variant}: ")?; write!(f, "{variant}: ")?;
} }
inner.fmtgs(f, info) inner.fmtgs(f, info, form, file)
} }
} }
} }
} }
impl Display for VDataEnum { impl Display for VDataEnum {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.fmtgs(f, None) self.fmtgs(f, None, &mut super::fmtgs::FormatInfo::default(), None)
} }
} }

View File

@ -4,9 +4,11 @@ use std::{
ops::BitOr, ops::BitOr,
}; };
use super::global_info::{self, GSInfo, GlobalScriptInfo}; use super::{
fmtgs::FormatGs,
global_info::{self, GSInfo, GlobalScriptInfo},
};
#[cfg(debug_assertions)]
use super::global_info::LogMsg; use super::global_info::LogMsg;
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@ -161,7 +163,6 @@ impl VType {
no.push(t.clone()) no.push(t.clone())
} }
} }
#[cfg(debug_assertions)]
if info.log.vtype_fits_in.log() { if info.log.vtype_fits_in.log() {
info.log info.log
.log(LogMsg::VTypeFitsIn(self.clone(), rhs.clone(), no.clone())) .log(LogMsg::VTypeFitsIn(self.clone(), rhs.clone(), no.clone()))
@ -359,7 +360,6 @@ impl VSingleType {
(Self::Thread(a), Self::Thread(b)) => a.fits_in(b, info).is_empty(), (Self::Thread(a), Self::Thread(b)) => a.fits_in(b, info).is_empty(),
(Self::Thread(..), _) => false, (Self::Thread(..), _) => false,
}; };
#[cfg(debug_assertions)]
if info.log.vsingletype_fits_in.log() { if info.log.vsingletype_fits_in.log() {
info.log info.log
.log(LogMsg::VSingleTypeFitsIn(self.clone(), rhs.clone(), o)); .log(LogMsg::VSingleTypeFitsIn(self.clone(), rhs.clone(), o));
@ -393,7 +393,12 @@ impl Into<VType> for VSingleType {
pub struct VTypeWInfo(VType, GSInfo); pub struct VTypeWInfo(VType, GSInfo);
impl Display for VTypeWInfo { impl Display for VTypeWInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmtgs(f, Some(&self.1)) self.0.fmtgs(
f,
Some(&self.1),
&mut super::fmtgs::FormatInfo::default(),
None,
)
} }
} }
impl VType { impl VType {
@ -402,8 +407,14 @@ impl VType {
} }
} }
impl VSingleType { impl FormatGs for VSingleType {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result { fn fmtgs(
&self,
f: &mut Formatter,
info: Option<&GlobalScriptInfo>,
form: &mut super::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result {
match self { match self {
Self::Bool => write!(f, "bool"), Self::Bool => write!(f, "bool"),
Self::Int => write!(f, "int"), Self::Int => write!(f, "int"),
@ -415,13 +426,13 @@ impl VSingleType {
if i > 0 { if i > 0 {
write!(f, " ")?; write!(f, " ")?;
} }
v.fmtgs(f, info)?; v.fmtgs(f, info, form, file)?;
} }
write!(f, "]") write!(f, "]")
} }
Self::List(v) => { Self::List(v) => {
write!(f, "[")?; write!(f, "[")?;
v.fmtgs(f, info)?; v.fmtgs(f, info, form, file)?;
write!(f, " ...]") write!(f, " ...]")
} }
Self::Function(func) => { Self::Function(func) => {
@ -429,22 +440,22 @@ impl VSingleType {
for (inputs, output) in func { for (inputs, output) in func {
write!(f, "(")?; write!(f, "(")?;
for i in inputs { for i in inputs {
i.fmtgs(f, info)?; i.fmtgs(f, info, form, file)?;
write!(f, " "); write!(f, " ");
} }
output.fmtgs(f, info)?; output.fmtgs(f, info, form, file)?;
write!(f, ")")?; write!(f, ")")?;
} }
write!(f, ")") write!(f, ")")
} }
Self::Thread(out) => { Self::Thread(out) => {
write!(f, "thread(")?; write!(f, "thread(")?;
out.fmtgs(f, info)?; out.fmtgs(f, info, form, file)?;
write!(f, ")") write!(f, ")")
} }
Self::Reference(inner) => { Self::Reference(inner) => {
write!(f, "&")?; write!(f, "&")?;
inner.fmtgs(f, info) inner.fmtgs(f, info, form, file)
} }
Self::EnumVariant(variant, inner) => { Self::EnumVariant(variant, inner) => {
if let Some(name) = if let Some(info) = info { if let Some(name) = if let Some(info) = info {
@ -462,12 +473,12 @@ impl VSingleType {
} else { } else {
write!(f, "{variant}(")?; write!(f, "{variant}(")?;
} }
inner.fmtgs(f, info)?; inner.fmtgs(f, info, form, file)?;
write!(f, ")") write!(f, ")")
} }
Self::EnumVariantS(name, inner) => { Self::EnumVariantS(name, inner) => {
write!(f, "{name}(")?; write!(f, "{name}(")?;
inner.fmtgs(f, info)?; inner.fmtgs(f, info, form, file)?;
write!(f, ")") write!(f, ")")
} }
Self::CustomType(t) => { Self::CustomType(t) => {
@ -510,23 +521,29 @@ impl VSingleType {
} }
impl Display for VSingleType { impl Display for VSingleType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.fmtgs(f, None) self.fmtgs(f, None, &mut super::fmtgs::FormatInfo::default(), None)
} }
} }
impl VType { impl FormatGs for VType {
pub fn fmtgs(&self, f: &mut Formatter, info: Option<&GlobalScriptInfo>) -> fmt::Result { fn fmtgs(
&self,
f: &mut Formatter,
info: Option<&GlobalScriptInfo>,
form: &mut super::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result {
for (i, t) in self.types.iter().enumerate() { for (i, t) in self.types.iter().enumerate() {
if i > 0 { if i > 0 {
write!(f, "/")?; write!(f, "/")?;
} }
t.fmtgs(f, info)?; t.fmtgs(f, info, form, file)?;
} }
Ok(()) Ok(())
} }
} }
impl Display for VType { impl Display for VType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.fmtgs(f, None) self.fmtgs(f, None, &mut super::fmtgs::FormatInfo::default(), None)
} }
} }

View File

@ -3,11 +3,13 @@
use std::{fs, time::Instant}; use std::{fs, time::Instant};
use lang::global_info::ColorFormatMode;
use lang::global_info::GlobalScriptInfo; use lang::global_info::GlobalScriptInfo;
#[cfg(debug_assertions)]
use lang::global_info::LogKind; use lang::global_info::LogKind;
use notify::Watcher as FsWatcher; use notify::Watcher as FsWatcher;
use crate::lang::fmtgs::FormatGs;
mod interactive_mode; mod interactive_mode;
mod lang; mod lang;
mod libs; mod libs;
@ -26,6 +28,7 @@ fn main() {
fn normal_main() { fn normal_main() {
let args: Vec<_> = std::env::args().skip(1).collect(); let args: Vec<_> = std::env::args().skip(1).collect();
let mut info = GlobalScriptInfo::default(); let mut info = GlobalScriptInfo::default();
let mut run = true;
let mut args_to_skip = 2; let mut args_to_skip = 2;
let mut file = match args.len() { let mut file = match args.len() {
0 => { 0 => {
@ -52,6 +55,10 @@ fn normal_main() {
match ch { match ch {
'e' => execute = true, 'e' => execute = true,
'v' => verbose = true, 'v' => verbose = true,
'f' => {
run = false;
info.log.after_parse.stderr = true;
}
'V' => print_version = true, 'V' => print_version = true,
'i' => interactive += 1, 'i' => interactive += 1,
't' => teachme = true, 't' => teachme = true,
@ -75,6 +82,11 @@ fn normal_main() {
verbose_args.push(ch); verbose_args.push(ch);
} }
} }
'f' => match ch {
'c' => info.formatter.mode = ColorFormatMode::Colorize,
'C' => info.formatter.mode = ColorFormatMode::Plain,
_ => eprintln!("Ignoring f+{ch}. (unknown adv char)"),
},
_ => (), _ => (),
} }
} else { } else {
@ -97,9 +109,6 @@ fn normal_main() {
return; return;
} }
if verbose { if verbose {
#[cfg(not(debug_assertions))]
eprintln!("WARN: Verbose (-v) only works in debug builds!");
#[cfg(debug_assertions)]
if verbose_args.is_empty() { if verbose_args.is_empty() {
fn f() -> LogKind { fn f() -> LogKind {
LogKind { LogKind {
@ -187,12 +196,9 @@ fn normal_main() {
}; };
match parsing::parse::parse_custom_info(&mut file, info) { match parsing::parse::parse_custom_info(&mut file, info) {
Ok(script) => { Ok(script) => {
println!(" - - - - -"); if run {
let start = Instant::now(); script.run(std::env::args().skip(args_to_skip).collect());
let out = script.run(std::env::args().skip(args_to_skip).collect()); }
let elapsed = start.elapsed();
println!(" - - - - -");
println!("Output ({}s)\n{out}", elapsed.as_secs_f64());
} }
Err(e) => { Err(e) => {
println!("Couldn't compile:\n{}", e.with_file(&file)); println!("Couldn't compile:\n{}", e.with_file(&file));

View File

@ -5,6 +5,7 @@ use crate::{
code_macro::MacroError, code_macro::MacroError,
code_parsed::*, code_parsed::*,
code_runnable::RScript, code_runnable::RScript,
fmtgs::{FormatGs, FormatWithGs},
global_info::{GSInfo, GlobalScriptInfo}, global_info::{GSInfo, GlobalScriptInfo},
to_runnable::{self, ToRunnableError}, to_runnable::{self, ToRunnableError},
val_data::VDataEnum, val_data::VDataEnum,
@ -13,6 +14,8 @@ use crate::{
libs, libs,
}; };
use crate::lang::global_info::LogMsg;
use super::file::File; use super::file::File;
pub enum ScriptError { pub enum ScriptError {
@ -51,59 +54,30 @@ impl std::fmt::Display for ScriptError {
} }
} }
} }
pub struct ScriptErrorWithFile<'a>(&'a ScriptError, &'a File); impl FormatGs for ScriptError {
pub struct ScriptErrorWithInfo<'a>(&'a ScriptError, &'a GlobalScriptInfo); fn fmtgs(
pub struct ScriptErrorWithFileAndInfo<'a>(&'a ScriptError, &'a File, &'a GlobalScriptInfo);
impl<'a> ScriptError {
pub fn with_file(&'a self, file: &'a File) -> ScriptErrorWithFile {
ScriptErrorWithFile(self, file)
}
pub fn with_gsinfo(&'a self, info: &'a GlobalScriptInfo) -> ScriptErrorWithInfo {
ScriptErrorWithInfo(self, info)
}
pub fn with_file_and_gsinfo(
&'a self,
file: &'a File,
info: &'a GlobalScriptInfo,
) -> ScriptErrorWithFileAndInfo {
ScriptErrorWithFileAndInfo(self, file, info)
}
}
impl<'a> std::fmt::Display for ScriptErrorWithFile<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt_custom(f, Some(self.1), None)
}
}
impl<'a> std::fmt::Display for ScriptErrorWithInfo<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt_custom(f, None, Some(self.1))
}
}
impl<'a> std::fmt::Display for ScriptErrorWithFileAndInfo<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt_custom(f, Some(self.1), Some(self.2))
}
}
impl ScriptError {
fn fmt_custom(
&self, &self,
f: &mut std::fmt::Formatter<'_>, f: &mut std::fmt::Formatter,
file: Option<&File>,
info: Option<&GlobalScriptInfo>, info: Option<&GlobalScriptInfo>,
form: &mut crate::lang::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result { ) -> std::fmt::Result {
match &self { match &self {
ScriptError::CannotFindPathForLibrary(e) => write!(f, "{e}"), ScriptError::CannotFindPathForLibrary(e) => write!(f, "{e}"),
ScriptError::ParseError(e) => { ScriptError::ParseError(e) => {
write!(f, "failed while parsing: ")?; write!(f, "failed while parsing: ")?;
e.fmt_custom(f, file)?; e.fmtgs(f, info, form, file)?;
Ok(()) Ok(())
} }
ScriptError::UnableToLoadLibrary(e) => write!(f, "{e}"), ScriptError::UnableToLoadLibrary(e) => write!(f, "{e}"),
ScriptError::ToRunnableError(e) => { ScriptError::ToRunnableError(e) => {
write!(f, "failed to compile: ")?; write!(f, "failed to compile: ")?;
e.fmtgs(f, info); e.fmtgs(
Ok(()) f,
info,
&mut crate::lang::fmtgs::FormatInfo::default(),
file,
)
} }
} }
} }
@ -123,14 +97,25 @@ impl From<(ScriptError, GSInfo)> for Error {
} }
} }
} }
impl Debug for Error { impl FormatGs for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmtgs(
write!(f, "{}", self.err.with_gsinfo(&self.ginfo)) &self,
f: &mut std::fmt::Formatter,
info: Option<&GlobalScriptInfo>,
form: &mut crate::lang::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result {
self.err.fmtgs(f, Some(&self.ginfo), form, file)
} }
} }
impl Error { impl Debug for Error {
pub fn with_file<'a>(&'a self, file: &'a File) -> ScriptErrorWithFileAndInfo<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.err.with_file_and_gsinfo(file, self.ginfo.as_ref()) self.err.fmtgs(
f,
Some(self.ginfo.as_ref()),
&mut crate::lang::fmtgs::FormatInfo::default(),
None,
)
} }
} }
@ -140,19 +125,16 @@ pub fn parse(file: &mut File) -> Result<RScript, Error> {
} }
/// like parse, but GlobalInfo can be something other than Default::default(). /// like parse, but GlobalInfo can be something other than Default::default().
pub fn parse_custom_info(file: &mut File, mut ginfo: GlobalScriptInfo) -> Result<RScript, Error> { pub fn parse_custom_info(file: &mut File, mut ginfo: GlobalScriptInfo) -> Result<RScript, Error> {
let libs = match parse_step_lib_paths(file) { let libs = match parse_step_lib_paths(file, &ginfo) {
Ok(v) => v, Ok(v) => v,
Err(e) => return Err((e.into(), ginfo.to_arc()).into()), Err(e) => return Err((e.into(), ginfo.to_arc()).into()),
}; };
let func = match parse_step_interpret(file) { let func = match parse_step_interpret(file, &ginfo) {
Ok(v) => v, Ok(v) => v,
Err(e) => return Err((e.into(), ginfo.to_arc()).into()), Err(e) => return Err((e.into(), ginfo.to_arc()).into()),
}; };
#[cfg(debug_assertions)]
eprintln!("{func:#?}");
ginfo.libs = match parse_step_libs_load(libs, &mut ginfo) { ginfo.libs = match parse_step_libs_load(libs, &mut ginfo) {
Ok(v) => v, Ok(v) => v,
Err(e) => return Err((e.into(), ginfo.to_arc()).into()), Err(e) => return Err((e.into(), ginfo.to_arc()).into()),
@ -174,7 +156,10 @@ impl std::fmt::Display for CannotFindPathForLibrary {
write!(f, "Couldn't find a path for the library with the path '{}'. Maybe set the MERS_LIB_DIR env variable?", self.0) write!(f, "Couldn't find a path for the library with the path '{}'. Maybe set the MERS_LIB_DIR env variable?", self.0)
} }
} }
pub fn parse_step_lib_paths(file: &mut File) -> Result<Vec<Command>, CannotFindPathForLibrary> { pub fn parse_step_lib_paths(
file: &mut File,
ginfo: &GlobalScriptInfo,
) -> Result<Vec<Command>, CannotFindPathForLibrary> {
let mut libs = vec![]; let mut libs = vec![];
loop { loop {
file.skip_whitespaces(); file.skip_whitespaces();
@ -198,14 +183,23 @@ pub fn parse_step_lib_paths(file: &mut File) -> Result<Vec<Command>, CannotFindP
Ok(libs) Ok(libs)
} }
pub fn parse_step_interpret(file: &mut File) -> Result<SFunction, ParseError> { pub fn parse_step_interpret(
Ok(SFunction::new( file: &mut File,
ginfo: &GlobalScriptInfo,
) -> Result<SFunction, ParseError> {
let o = SFunction::new(
vec![( vec![(
"args".to_string(), "args".to_string(),
VSingleType::List(VSingleType::String.into()).to(), VSingleType::List(VSingleType::String.into()).to(),
)], )],
parse_block_advanced(file, Some(false), true, true, false)?, parse_block_advanced(file, Some(false), true, true, false)?,
)) );
if ginfo.log.after_parse.log() {
ginfo.log.log(LogMsg::AfterParse(
o.with_info_and_file(ginfo, &file).to_string(),
));
}
Ok(o)
} }
#[derive(Debug)] #[derive(Debug)]
@ -242,17 +236,6 @@ pub fn parse_step_compile(
to_runnable::to_runnable(main_func, ginfo) to_runnable::to_runnable(main_func, ginfo)
} }
pub struct ParseErrorWithFile<'a>(&'a ParseError, &'a File);
impl<'a> ParseError {
pub fn with_file(&'a self, file: &'a File) -> ParseErrorWithFile {
ParseErrorWithFile(self, file)
}
}
impl<'a> std::fmt::Display for ParseErrorWithFile<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt_custom(f, Some(self.1))
}
}
pub struct ParseError { pub struct ParseError {
err: ParseErrors, err: ParseErrors,
// the location of the error // the location of the error
@ -264,13 +247,15 @@ pub struct ParseError {
)>, )>,
info: Option<GlobalScriptInfo>, info: Option<GlobalScriptInfo>,
} }
impl ParseError { impl FormatGs for ParseError {
pub fn fmt_custom( fn fmtgs(
&self, &self,
f: &mut std::fmt::Formatter<'_>, f: &mut std::fmt::Formatter,
file: Option<&super::file::File>, info: Option<&GlobalScriptInfo>,
form: &mut crate::lang::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result { ) -> std::fmt::Result {
self.err.fmtgs(f, self.info.as_ref(), file)?; self.err.fmtgs(f, self.info.as_ref(), form, file)?;
writeln!(f); writeln!(f);
if let Some(location_end) = self.location_end { if let Some(location_end) = self.location_end {
writeln!(f, " from {} to {}", self.location, location_end)?; writeln!(f, " from {} to {}", self.location, location_end)?;
@ -308,7 +293,12 @@ impl ParseError {
} }
impl std::fmt::Display for ParseError { impl std::fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.fmt_custom(f, None) self.fmtgs(
f,
None,
&mut crate::lang::fmtgs::FormatInfo::default(),
None,
)
} }
} }
pub enum ParseErrors { pub enum ParseErrors {
@ -327,12 +317,14 @@ pub enum ParseErrors {
ErrorParsingFunctionArgs(Box<ParseError>), ErrorParsingFunctionArgs(Box<ParseError>),
MacroError(MacroError), MacroError(MacroError),
} }
impl ParseErrors {
impl FormatGs for ParseErrors {
fn fmtgs( fn fmtgs(
&self, &self,
f: &mut std::fmt::Formatter, f: &mut std::fmt::Formatter,
info: Option<&GlobalScriptInfo>, info: Option<&GlobalScriptInfo>,
file: Option<&super::file::File>, form: &mut crate::lang::fmtgs::FormatInfo,
file: Option<&crate::parsing::file::File>,
) -> std::fmt::Result { ) -> std::fmt::Result {
match self { match self {
Self::StatementCannotStartWith(ch) => { Self::StatementCannotStartWith(ch) => {
@ -360,17 +352,17 @@ impl ParseErrors {
Self::InvalidType(name) => write!(f, "\"{name}\" is not a type."), Self::InvalidType(name) => write!(f, "\"{name}\" is not a type."),
Self::CannotUseFixedIndexingWithThisType(t) => { Self::CannotUseFixedIndexingWithThisType(t) => {
write!(f, "cannot use fixed-indexing with type ")?; write!(f, "cannot use fixed-indexing with type ")?;
t.fmtgs(f, info)?; t.fmtgs(f, info, form, file)?;
write!(f, ".") write!(f, ".")
} }
Self::CannotWrapWithThisStatement(s) => { Self::CannotWrapWithThisStatement(s) => {
write!(f, "cannot wrap with this kind of statement: ")?; write!(f, "cannot wrap with this kind of statement: ")?;
s.fmtgs(f, info)?; s.fmtgs(f, info, form, file)?;
write!(f, ".") write!(f, ".")
} }
Self::ErrorParsingFunctionArgs(parse_error) => { Self::ErrorParsingFunctionArgs(parse_error) => {
write!(f, "error parsing function args: ")?; write!(f, "error parsing function args: ")?;
parse_error.fmt_custom(f, file) parse_error.fmtgs(f, info, form, file)
} }
Self::MacroError(e) => write!(f, "error in macro: {e}"), Self::MacroError(e) => write!(f, "error in macro: {e}"),
} }

View File

@ -1,7 +1,7 @@
use std::{path::PathBuf, thread::JoinHandle, time::Instant}; use std::{path::PathBuf, thread::JoinHandle, time::Instant};
use crate::{ use crate::{
lang::{code_runnable::RScript, global_info::GSInfo, val_data::VDataEnum}, lang::{code_runnable::RScript, fmtgs::FormatGs, global_info::GSInfo, val_data::VDataEnum},
parsing::{self, file::File, parse::ScriptError}, parsing::{self, file::File, parse::ScriptError},
}; };