Skip to content
Snippets Groups Projects
Verified Commit 850e7e89 authored by Louis's avatar Louis :fire:
Browse files

Start parsing test suite, propogate correct error in wasm

parent 2a9c8c8e
No related branches found
No related tags found
No related merge requests found
use crate::lexer::Span;
use crate::parse::ScriptToken;
use peg::error::ExpectedSet;
use std::error::Error;
use std::fmt::{Display, Formatter};
......@@ -133,6 +134,63 @@ pub fn print_unexpected_token<'a>(
eprintln!("|\n| Failed To Parse: expected {}", expected);
}
pub struct ErrorFormat<'a>(pub &'a str, pub &'a ScriptToken<'a>, pub &'a ExpectedSet);
impl<'a> Display for ErrorFormat<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let ErrorFormat(source, token, expected) = self;
let line = token.position.location_line() as usize;
let column = token.position.get_column();
let previous_line = if line > 1 {
source.lines().nth(line - 2)
} else {
None
};
let source_line = source.lines().nth(line - 1).expect("Missing line");
let next_line = source.lines().nth(line);
let largest_line_num = line.max(line.saturating_sub(1)).max(line.saturating_add(1));
let number_length = format!("{}", largest_line_num).len();
writeln!(f, "| Script error on line {} at \"{}\"\n|", line, token)?;
if let Some(prev) = previous_line {
writeln!(
f,
"| [{:>width$}] {}",
line - 1,
prev,
width = number_length
)?;
}
writeln!(
f,
"| [{:>width$}] {}",
line,
source_line,
width = number_length
)?;
writeln!(
f,
"| {} {}{}",
vec![" "; number_length + 2].join(""),
vec![" "; column - 1].join(""),
vec!["^"; token.token_type.len()].join(""),
)?;
if let Some(next) = next_line {
writeln!(
f,
"| [{:>width$}] {}",
line + 1,
next,
width = number_length
)?;
}
writeln!(f, "|\n| Failed To Parse: expected {}", expected)
}
}
pub fn print_forge_error<'a>(source: &'a str, fe: &'a ForgeError) {
match &fe.kind {
ForgeErrorKind::IncompleteInput => eprintln!("| Unexpected end of file"),
......@@ -142,3 +200,13 @@ pub fn print_forge_error<'a>(source: &'a str, fe: &'a ForgeError) {
}
}
}
pub fn format_forge_error<'a>(source: &'a str, fe: &'a ForgeError) -> String {
match &fe.kind {
ForgeErrorKind::IncompleteInput => String::from("| Unexpected end of file"),
ForgeErrorKind::LexerError(err) => format!("| {}", err),
ForgeErrorKind::UnexpectedToken { found, expected } => {
format!("{}", ErrorFormat(source, found, expected))
}
}
}
......@@ -3,7 +3,10 @@ mod lexer;
mod parser;
pub mod runtime;
pub use error::{print_forge_error, ParseError, ParseErrorKind, TokenError, TokenErrorKind};
pub use error::{
format_forge_error, print_forge_error, ForgeError, ForgeErrorKind, ParseError, ParseErrorKind,
TokenError, TokenErrorKind,
};
pub mod parse {
pub use super::lexer::{script_to_tokens, ScriptToken, ScriptTokenType};
pub use super::parser::ast;
......
......@@ -62,6 +62,7 @@ peg::parser! {
/ "-" { BinaryOp::Subtract }
/ "*" { BinaryOp::Multiply }
/ "/" { BinaryOp::Divide }
/ "%" { BinaryOp::Modulo }
rule unary_operator() -> UnaryOp
= "!" { UnaryOp::Not }
......
pub mod ast;
mod atoms;
mod grammar;
#[cfg(test)]
mod test_suite;
use crate::error::{ForgeError, ForgeErrorKind, ForgeResult};
use crate::print_forge_error;
......
use crate::parse::parse_program;
#[test]
fn binary_ops() {
parse_program("1+1").expect("Failed binary add");
parse_program("1-1").expect("Failed binary sub");
parse_program("1*1").expect("Failed binary mul");
parse_program("1/1").expect("Failed binary div");
parse_program("1%1").expect("Failed binary mod");
}
#[test]
fn unary_ops() {
parse_program("-1").expect("Failed binary inv");
parse_program("!1").expect("Failed binary not");
}
#[test]
fn indentifiers() {
parse_program("let my_ident").expect("Failed declare");
parse_program("let my_ident = 123").expect("Failed declare/assign");
}
#[test]
fn conditional() {
parse_program("if false { }").expect("Failed conditional with literal");
parse_program("if some_ident { }").expect("Failed conditional with identifier");
parse_program("if 1 + 1 { }").expect("Failed conditional with expr");
parse_program("if (let ident = false) { }").expect("Failed conditional with decl");
}
use forge_script_lang::format_forge_error;
use forge_script_lang::parse::parse_program;
use forge_script_lang::runtime::executor::{TreePrinter, Visitor};
use wasm_bindgen::prelude::*;
......@@ -9,13 +10,26 @@ pub fn init() {
#[wasm_bindgen]
pub fn compile_ast(program: &str) -> Result<JsValue, serde_wasm_bindgen::Error> {
serde_wasm_bindgen::to_value(&parse_program(program).expect("Failed to parse"))
match parse_program(program) {
Ok(val) => serde_wasm_bindgen::to_value(&val),
Err(e) => Err(serde_wasm_bindgen::Error::new(format_forge_error(
program, &e,
))),
}
}
#[wasm_bindgen]
pub fn format_script(program: &str) -> Result<String, serde_wasm_bindgen::Error> {
let ast = &parse_program(program).expect("Failed to parse");
let ast = match parse_program(program) {
Ok(val) => val,
Err(e) => {
return Err(serde_wasm_bindgen::Error::new(format_forge_error(
program, &e,
)));
}
};
let mut writer = TreePrinter::new();
writer.evaluate_program(ast);
writer.evaluate_program(&ast);
Ok(writer.take_value())
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment