Browse Source

Proper diagnostics

David Peter 2 years ago
parent
commit
0c26f3d7a1

+ 4 - 2
numbat-wasm/Cargo.lock

@@ -255,9 +255,11 @@ dependencies = [
 name = "numbat-wasm"
 version = "0.1.0"
 dependencies = [
+ "codespan-reporting",
  "console_error_panic_hook",
  "html-escape",
  "numbat",
+ "termcolor",
  "wasm-bindgen",
  "wasm-bindgen-test",
  "wee_alloc",
@@ -395,9 +397,9 @@ dependencies = [
 
 [[package]]
 name = "termcolor"
-version = "1.2.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
+checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
 dependencies = [
  "winapi-util",
 ]

+ 2 - 0
numbat-wasm/Cargo.toml

@@ -26,6 +26,8 @@ wee_alloc = { version = "0.4.5", optional = true }
 
 numbat = { path = "../numbat" }
 html-escape = "0.2.13"
+termcolor = "1.3.0"
+codespan-reporting = "0.11.1"
 
 [dev-dependencies]
 wasm-bindgen-test = "0.3.13"

+ 67 - 0
numbat-wasm/src/jquery_terminal_formatter.rs

@@ -1,5 +1,7 @@
 use numbat::markup::{FormatType, FormattedString, Formatter};
 
+use termcolor::{Color, WriteColor};
+
 pub struct JqueryTerminalFormatter;
 
 pub fn jt_format(class: Option<&str>, content: &str) -> String {
@@ -39,3 +41,68 @@ impl Formatter for JqueryTerminalFormatter {
         jt_format(css_class, s)
     }
 }
+
+pub struct JqueryTerminalWriter {
+    buffer: Vec<u8>,
+    color: Option<termcolor::ColorSpec>,
+}
+
+impl JqueryTerminalWriter {
+    pub fn new() -> Self {
+        JqueryTerminalWriter {
+            buffer: vec![],
+            color: None,
+        }
+    }
+
+    pub fn to_string(self) -> String {
+        String::from_utf8_lossy(&self.buffer).into()
+    }
+}
+
+impl std::io::Write for JqueryTerminalWriter {
+    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+        if let Some(color) = &self.color {
+            if color.fg() == Some(&Color::Red) {
+                self.buffer.write("[[;;;hl-diagnostic-red]".as_bytes())?;
+                let size = self.buffer.write(buf)?;
+                self.buffer.write("]".as_bytes())?;
+                Ok(size)
+            } else if color.fg() == Some(&Color::Blue) {
+                self.buffer.write("[[;;;hl-diagnostic-blue]".as_bytes())?;
+                let size = self.buffer.write(buf)?;
+                self.buffer.write("]".as_bytes())?;
+                Ok(size)
+            } else if color.bold() {
+                self.buffer.write("[[;;;hl-diagnostic-bold]".as_bytes())?;
+                let size = self.buffer.write(buf)?;
+                self.buffer.write("]".as_bytes())?;
+                Ok(size)
+            } else {
+                self.buffer.write(buf)
+            }
+        } else {
+            self.buffer.write(buf)
+        }
+    }
+
+    fn flush(&mut self) -> std::io::Result<()> {
+        self.buffer.flush()
+    }
+}
+
+impl WriteColor for JqueryTerminalWriter {
+    fn supports_color(&self) -> bool {
+        true
+    }
+
+    fn set_color(&mut self, spec: &termcolor::ColorSpec) -> std::io::Result<()> {
+        self.color = Some(spec.clone());
+        Ok(())
+    }
+
+    fn reset(&mut self) -> std::io::Result<()> {
+        self.color = None;
+        Ok(())
+    }
+}

+ 26 - 5
numbat-wasm/src/lib.rs

@@ -2,18 +2,20 @@ mod jquery_terminal_formatter;
 mod utils;
 mod wasm_importer;
 
+use numbat::diagnostic::ErrorDiagnostic;
 use std::sync::{Arc, Mutex};
+use wasm_bindgen::prelude::*;
 
 use jquery_terminal_formatter::{jt_format, JqueryTerminalFormatter};
+use wasm_importer::WasmImporter;
+
 use numbat::markup::Formatter;
 use numbat::pretty_print::PrettyPrint;
 use numbat::resolver::CodeSource;
-use numbat::{markup as m, Type};
+use numbat::{markup as m, NameResolutionError, NumbatError, Type};
 use numbat::{Context, InterpreterResult, InterpreterSettings};
 
-use wasm_bindgen::prelude::*;
-
-use crate::wasm_importer::WasmImporter;
+use crate::jquery_terminal_formatter::JqueryTerminalWriter;
 
 // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
 // allocator.
@@ -113,7 +115,26 @@ impl Numbat {
 
                 output
             }
-            Err(e) => format!("{:#}", e),
+            Err(NumbatError::ResolverError(e)) => self.print_diagnostic(&e),
+            Err(NumbatError::NameResolutionError(
+                e @ (NameResolutionError::IdentifierClash { .. }
+                | NameResolutionError::ReservedIdentifier(_)),
+            )) => self.print_diagnostic(&e),
+            Err(NumbatError::TypeCheckError(e)) => self.print_diagnostic(&e),
+            Err(NumbatError::RuntimeError(e)) => self.print_diagnostic(&e),
         }
     }
+
+    fn print_diagnostic(&self, error: &dyn ErrorDiagnostic) -> String {
+        use codespan_reporting::term::{self, Config};
+
+        let mut writer = JqueryTerminalWriter::new();
+        let config = Config::default();
+
+        let resolver = self.ctx.resolver();
+
+        term::emit(&mut writer, &config, &resolver.files, &error.diagnostic()).unwrap();
+
+        writer.to_string()
+    }
 }

+ 1 - 9
numbat-wasm/www/index.js

@@ -66,18 +66,10 @@ function colored(col, str) {
   return "[[;#" + col + ";]" + str + "]";
 }
 
-var visitedBefore = localStorage.getItem("visitedBefore") === "yes";
-var greeting = "";
-if (!visitedBefore) {
-  greeting = colored("75715E", "Welcome to Numbat. Type '?' if this is your first visit.");
-  localStorage.setItem("visitedBefore", "yes");
-} else {
-  greeting = colored("75715E", "Welcome to Numbat. Enter '?' for help.");
-}
 
 $(document).ready(function() {
   var term = $('#terminal').terminal(interpret, {
-    greetings: greeting,
+    greetings: false,
     name: "terminal",
     height: 550,
     prompt: "[[;;;prompt]>>> ]",

+ 12 - 0
numbat-wasm/www/main.css

@@ -125,6 +125,18 @@ p.links a {
     color: #A6E22E !important;
 }
 
+.hl-diagnostic-red {
+    color: #d4122c !important;
+}
+
+.hl-diagnostic-blue {
+    color: #5179ce !important;
+}
+
+.hl-diagnostic-bold {
+    font-weight: 700 !important;
+}
+
 /* Github Badge */
 
 .github-corner:hover .octo-arm {

+ 4 - 0
numbat/src/lib.rs

@@ -142,6 +142,10 @@ impl Context {
         })
     }
 
+    pub fn resolver(&self) -> &Resolver {
+        &self.resolver
+    }
+
     pub fn interpret(
         &mut self,
         code: &str,

+ 1 - 1
numbat/src/resolver.rs

@@ -44,7 +44,7 @@ pub enum ResolverError {
 
 type Result<T> = std::result::Result<T, ResolverError>;
 
-pub(crate) struct Resolver {
+pub struct Resolver {
     importer: Box<dyn ModuleImporter + Send>,
     pub files: SimpleFiles<String, String>,
     text_code_source_count: usize,