mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 实现 parser crate
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OxideError {
|
||||
pub message: String,
|
||||
pub span: (usize, usize),
|
||||
}
|
||||
|
||||
impl fmt::Display for OxideError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{} at {:?}", self.message, self.span)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for OxideError {}
|
||||
|
||||
impl From<oxc_diagnostics::OxcDiagnostic> for OxideError {
|
||||
fn from(diag: oxc_diagnostics::OxcDiagnostic) -> Self {
|
||||
let span = diag
|
||||
.labels
|
||||
.clone()
|
||||
.and_then(|labels| labels.first().map(|l| (l.offset() as usize, (l.offset() + l.len()) as usize)))
|
||||
.unwrap_or((0, 0));
|
||||
|
||||
OxideError {
|
||||
message: diag.message.to_string(),
|
||||
span,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1,29 @@
|
||||
#![doc = "OxideJS - JavaScript parser (oxc_parser re-export)"]
|
||||
|
||||
mod error;
|
||||
|
||||
pub use error::OxideError;
|
||||
pub use oxc_allocator::Allocator;
|
||||
pub use oxc_ast::ast::*;
|
||||
pub use oxc_span::Span;
|
||||
|
||||
pub fn parse<'a>(allocator: &'a Allocator, source: &'a str) -> Result<Program<'a>, Vec<OxideError>> {
|
||||
use oxc_parser::Parser;
|
||||
use oxc_span::SourceType;
|
||||
|
||||
let source_type = SourceType::default();
|
||||
let ret = Parser::new(allocator, source, source_type).parse();
|
||||
|
||||
if ret.panicked {
|
||||
return Err(vec![OxideError {
|
||||
message: "Parser panicked: unrecoverable syntax error".to_string(),
|
||||
span: (0, 0),
|
||||
}]);
|
||||
}
|
||||
|
||||
if !ret.errors.is_empty() {
|
||||
return Err(ret.errors.into_iter().map(OxideError::from).collect());
|
||||
}
|
||||
|
||||
Ok(ret.program)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
use oxide_parser::Allocator;
|
||||
|
||||
#[test]
|
||||
fn parse_simple_expression() {
|
||||
let allocator = Allocator::default();
|
||||
let result = oxide_parser::parse(&allocator, "1 + 2");
|
||||
assert!(result.is_ok(), "1+2 should parse successfully");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_empty_string() {
|
||||
let allocator = Allocator::default();
|
||||
let result = oxide_parser::parse(&allocator, "");
|
||||
assert!(result.is_ok(), "empty string should parse");
|
||||
let program = result.unwrap();
|
||||
assert!(program.body.is_empty(), "empty program should have empty body");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_function_declaration() {
|
||||
let allocator = Allocator::default();
|
||||
let result = oxide_parser::parse(&allocator, "function foo() { return 42; }");
|
||||
assert!(result.is_ok(), "function declaration should parse");
|
||||
let program = result.unwrap();
|
||||
assert!(!program.body.is_empty(), "program with function should not be empty");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_syntax_error() {
|
||||
let allocator = Allocator::default();
|
||||
let result = oxide_parser::parse(&allocator, "function(");
|
||||
assert!(result.is_err(), "syntax error should return Err");
|
||||
let errors = result.unwrap_err();
|
||||
assert!(!errors.is_empty(), "syntax error should produce at least one error");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_variable_declaration() {
|
||||
let allocator = Allocator::default();
|
||||
let result = oxide_parser::parse(&allocator, "var x = 42;");
|
||||
assert!(result.is_ok(), "variable declaration should parse");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_multiple_statements() {
|
||||
let allocator = Allocator::default();
|
||||
let result = oxide_parser::parse(
|
||||
&allocator,
|
||||
"var a = 1; var b = 2; var c = a + b;",
|
||||
);
|
||||
assert!(result.is_ok(), "multiple statements should parse");
|
||||
let program = result.unwrap();
|
||||
assert_eq!(program.body.len(), 3, "should have 3 statements");
|
||||
}
|
||||
Reference in New Issue
Block a user