luna_core/frontend/error.rs
1//! Syntax-error type produced by the lexer and parser.
2
3use std::fmt;
4
5/// Syntax error, formatted PUC-style: `chunkname:line: msg near 'tok'`.
6/// The `near` part is already baked into `msg` at construction time.
7///
8/// `msg` is a raw byte string — PUC 5.1 reports `near '\xff'`-style errors
9/// with the offending source byte verbatim, and `errors.lua` 5.1 :20 grep-
10/// matches that pattern. Carrying the message as `Vec<u8>` lets the lexer
11/// emit those bytes without UTF-8 enforcement getting in the way.
12#[derive(Clone, PartialEq, Eq, Debug)]
13pub struct SyntaxError {
14 /// 1-based source line where the error was detected.
15 pub line: u32,
16 /// Message bytes (PUC-style; may contain non-UTF-8 source bytes).
17 pub msg: Vec<u8>,
18}
19
20impl SyntaxError {
21 /// Build a `SyntaxError` at the given line with the given message bytes.
22 pub fn new(line: u32, msg: impl Into<Vec<u8>>) -> Self {
23 SyntaxError {
24 line,
25 msg: msg.into(),
26 }
27 }
28
29 /// Lossy `&str` for Rust-side display (PUC `luaG_addinfo` only cares
30 /// about the bytes; this is for unit tests / panic messages).
31 pub fn msg_str(&self) -> std::borrow::Cow<'_, str> {
32 String::from_utf8_lossy(&self.msg)
33 }
34}
35
36impl fmt::Display for SyntaxError {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(f, "{}: {}", self.line, self.msg_str())
39 }
40}
41
42impl std::error::Error for SyntaxError {}