pretty good parsing errors
This commit is contained in:
parent
d6a004d9ac
commit
f97f6670bd
4
pkg/rudus.d.ts
vendored
4
pkg/rudus.d.ts
vendored
|
@ -14,8 +14,8 @@ export interface InitOutput {
|
|||
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
||||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
readonly __wbindgen_export_6: WebAssembly.Table;
|
||||
readonly closure304_externref_shim: (a: number, b: number, c: any) => void;
|
||||
readonly closure328_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
readonly closure303_externref_shim: (a: number, b: number, c: any) => void;
|
||||
readonly closure327_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
readonly __wbindgen_start: () => void;
|
||||
}
|
||||
|
||||
|
|
|
@ -240,13 +240,13 @@ function _assertNum(n) {
|
|||
function __wbg_adapter_20(arg0, arg1, arg2) {
|
||||
_assertNum(arg0);
|
||||
_assertNum(arg1);
|
||||
wasm.closure304_externref_shim(arg0, arg1, arg2);
|
||||
wasm.closure303_externref_shim(arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
function __wbg_adapter_50(arg0, arg1, arg2, arg3) {
|
||||
_assertNum(arg0);
|
||||
_assertNum(arg1);
|
||||
wasm.closure328_externref_shim(arg0, arg1, arg2, arg3);
|
||||
wasm.closure327_externref_shim(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
async function __wbg_load(module, imports) {
|
||||
|
@ -425,8 +425,8 @@ function __wbg_get_imports() {
|
|||
_assertBoolean(ret);
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_closure_wrapper7890 = function() { return logError(function (arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 305, __wbg_adapter_20);
|
||||
imports.wbg.__wbindgen_closure_wrapper7980 = function() { return logError(function (arg0, arg1, arg2) {
|
||||
const ret = makeMutClosure(arg0, arg1, 304, __wbg_adapter_20);
|
||||
return ret;
|
||||
}, arguments) };
|
||||
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
|
||||
|
|
Binary file not shown.
4
pkg/rudus_bg.wasm.d.ts
vendored
4
pkg/rudus_bg.wasm.d.ts
vendored
|
@ -9,6 +9,6 @@ export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
|||
export const __wbindgen_malloc: (a: number, b: number) => number;
|
||||
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
export const __wbindgen_export_6: WebAssembly.Table;
|
||||
export const closure304_externref_shim: (a: number, b: number, c: any) => void;
|
||||
export const closure328_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
export const closure303_externref_shim: (a: number, b: number, c: any) => void;
|
||||
export const closure327_externref_shim: (a: number, b: number, c: any, d: any) => void;
|
||||
export const __wbindgen_start: () => void;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// use crate::process::{LErr, Trace};
|
||||
use crate::lexer::Token;
|
||||
use crate::validator::VErr;
|
||||
use chumsky::error::RichPattern;
|
||||
use chumsky::prelude::*;
|
||||
|
||||
const SEPARATOR: &str = "\n\n";
|
||||
|
@ -42,10 +43,50 @@ pub fn validation(errs: Vec<VErr>) -> String {
|
|||
msgs.join(SEPARATOR)
|
||||
}
|
||||
|
||||
pub fn parsing(errs: Vec<Rich<'static, Token>>) -> String {
|
||||
let mut msg = "Syntax errors".to_string();
|
||||
pub fn parsing(errs: Vec<Rich<'static, Token>>, src: &'static str, input: &'static str) -> String {
|
||||
let mut msgs = vec!["Ludus found some errors.".to_string()];
|
||||
for err in errs {
|
||||
msg = format!("{msg}\n{:#?}", err);
|
||||
let mut msg = vec![];
|
||||
let line_number = line_number(src, *err.span());
|
||||
let line = get_line(src, line_number);
|
||||
let details = parsing_message(err);
|
||||
msg.push(format!("Syntax error: {}", details));
|
||||
msg.push(format!(" on line {} in {}", line_number + 1, input));
|
||||
msg.push(format!(" >>> {line}"));
|
||||
msgs.push(msg.join("\n"))
|
||||
}
|
||||
msg
|
||||
msgs.join(SEPARATOR)
|
||||
}
|
||||
|
||||
fn parsing_message(err: Rich<'static, Token>) -> String {
|
||||
let found = match err.found() {
|
||||
Some(token) => token.show(),
|
||||
None => "end of input".to_string(),
|
||||
};
|
||||
let expected = err.expected();
|
||||
let mut expecteds = vec![];
|
||||
for pattern in expected {
|
||||
let shown = match pattern {
|
||||
RichPattern::Token(t) => t.show(),
|
||||
RichPattern::Label(s) => s.to_string(),
|
||||
RichPattern::Identifier(s) => s.clone(),
|
||||
RichPattern::Any => "any".to_string(),
|
||||
RichPattern::SomethingElse => "something else".to_string(),
|
||||
RichPattern::EndOfInput => "eof".to_string(),
|
||||
};
|
||||
expecteds.push(shown);
|
||||
}
|
||||
let expecteds = if expecteds.iter().any(|e| e == &"else".to_string()) {
|
||||
vec!["else".to_string()]
|
||||
} else {
|
||||
expecteds
|
||||
};
|
||||
let expecteds = if expecteds.iter().any(|e| e == &"then".to_string()) {
|
||||
vec!["then".to_string()]
|
||||
} else {
|
||||
expecteds
|
||||
};
|
||||
|
||||
let expecteds = expecteds.join(" | ");
|
||||
format!("Ludus did not expect to see: {found}\n expected: {expecteds}")
|
||||
}
|
||||
|
|
26
src/lexer.rs
26
src/lexer.rs
|
@ -2,7 +2,7 @@ use crate::spans::*;
|
|||
use chumsky::prelude::*;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Token {
|
||||
Nil,
|
||||
Number(f64),
|
||||
|
@ -32,6 +32,24 @@ impl fmt::Display for Token {
|
|||
}
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub fn show(&self) -> String {
|
||||
match self {
|
||||
Token::Number(n) => format!("{n}"),
|
||||
Token::Boolean(b) => format!("{b}"),
|
||||
Token::Keyword(k) => format!(":{k}"),
|
||||
Token::Method(m) => format!("::{m}"),
|
||||
Token::Nil => "nil".to_string(),
|
||||
Token::String(s) => format!("\"{s}\""),
|
||||
Token::Reserved(s) | Token::Word(s) => s.to_string(),
|
||||
Token::Punctuation(s) => {
|
||||
let out = if *s == "\n" { "newline" } else { s };
|
||||
out.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lexer(
|
||||
) -> impl Parser<'static, &'static str, Vec<(Token, Span)>, extra::Err<Rich<'static, char, Span>>> {
|
||||
let number = just('-')
|
||||
|
@ -71,14 +89,14 @@ pub fn lexer(
|
|||
let escape = just('\\')
|
||||
.then(choice((
|
||||
just('\\').to('\\'),
|
||||
just('"').to('"'),
|
||||
just('n').to('\n'),
|
||||
just('t').to('\t'),
|
||||
just('r').to('\r'),
|
||||
just('"').to('"'), // TODO: figure out why this isn't working
|
||||
)))
|
||||
.ignored();
|
||||
|
||||
let string = none_of("\\\"")
|
||||
let string = none_of('"')
|
||||
.ignored()
|
||||
.or(escape)
|
||||
.repeated()
|
||||
|
@ -147,6 +165,6 @@ mod tests {
|
|||
.0
|
||||
.unwrap();
|
||||
let (token, _) = spanned_toks[0].clone();
|
||||
assert_eq!(token, Token::String("foo \\\"bar baz"));
|
||||
assert_eq!(token, Token::String("foo \"bar baz"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ pub async fn ludus(src: String) {
|
|||
.parse(Stream::from_iter(tokens).map((0..src.len()).into(), |(t, s)| (t, s)))
|
||||
.into_output_errors();
|
||||
if !parse_errors.is_empty() {
|
||||
send_err_to_ludus_console(parsing(parse_errors)).await;
|
||||
send_err_to_ludus_console(parsing(parse_errors, src, "user script")).await;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -141,13 +141,15 @@ where
|
|||
just(Token::Punctuation(","))
|
||||
.or(just(Token::Punctuation("\n")))
|
||||
.then(separators.clone().repeated())
|
||||
});
|
||||
})
|
||||
.labelled("separator");
|
||||
|
||||
let terminators = recursive(|terminators| {
|
||||
just(Token::Punctuation(";"))
|
||||
.or(just(Token::Punctuation("\n")))
|
||||
.then(terminators.clone().repeated())
|
||||
});
|
||||
})
|
||||
.labelled("terminator");
|
||||
|
||||
let placeholder_pattern =
|
||||
select! {Token::Punctuation("_") => PlaceholderPattern}.map_with(|p, e| (p, e.span()));
|
||||
|
@ -207,7 +209,8 @@ where
|
|||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
|
||||
.map_with(|list, e| (ListPattern(list), e.span()));
|
||||
.map_with(|list, e| (ListPattern(list), e.span()))
|
||||
.labelled("list pattern");
|
||||
|
||||
let key_pair_pattern = select! {Token::Keyword(k) => k}
|
||||
.then(pattern.clone())
|
||||
|
@ -228,6 +231,7 @@ where
|
|||
.or(shorthand_pattern)
|
||||
.or(str_pair_pattern)
|
||||
.or(splattern.clone())
|
||||
.labelled("pair pattern")
|
||||
.separated_by(separators.clone())
|
||||
.allow_leading()
|
||||
.allow_trailing()
|
||||
|
@ -238,11 +242,14 @@ where
|
|||
)
|
||||
.map_with(|dict, e| (DictPattern(dict), e.span()));
|
||||
|
||||
let keyword = select! {Token::Keyword(k) => Keyword(k)}.map_with(|k, e| (k, e.span()));
|
||||
let keyword = select! {Token::Keyword(k) => Keyword(k)}
|
||||
.map_with(|k, e| (k, e.span()))
|
||||
.labelled("keyword");
|
||||
|
||||
let as_pattern = select! {Token::Word(w) => w}
|
||||
.then_ignore(just(Token::Reserved("as")))
|
||||
.then(select! {Token::Keyword(k) => k})
|
||||
.labelled("keyword")
|
||||
.map_with(|(w, t), e| (AsPattern(w, t), e.span()));
|
||||
|
||||
pattern.define(
|
||||
|
@ -289,7 +296,8 @@ where
|
|||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
.map_with(|tuple, e| (Tuple(tuple), e.span()));
|
||||
.map_with(|tuple, e| (Tuple(tuple), e.span()))
|
||||
.labelled("tuple");
|
||||
|
||||
let args = simple
|
||||
.clone()
|
||||
|
@ -299,7 +307,8 @@ where
|
|||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
||||
.map_with(|args, e| (Arguments(args), e.span()));
|
||||
.map_with(|args, e| (Arguments(args), e.span()))
|
||||
.labelled("args");
|
||||
|
||||
let or = just(Token::Reserved("or")).map_with(|_, e| (Or, e.span()));
|
||||
|
||||
|
@ -307,7 +316,8 @@ where
|
|||
|
||||
let method = select!(Token::Method(m) => m)
|
||||
.then(tuple.clone())
|
||||
.map_with(|(m, t), e| (Ast::Method(m, Box::new(t)), e.span()));
|
||||
.map_with(|(m, t), e| (Ast::Method(m, Box::new(t)), e.span()))
|
||||
.labelled("method");
|
||||
|
||||
let synth_root = or.or(and).or(word).or(keyword);
|
||||
|
||||
|
@ -327,7 +337,8 @@ where
|
|||
Splat(if let Word(w) = w { w } else { unreachable!() }),
|
||||
e.span(),
|
||||
)
|
||||
});
|
||||
})
|
||||
.labelled("...");
|
||||
|
||||
let list = simple
|
||||
.clone()
|
||||
|
|
Loading…
Reference in New Issue
Block a user