sphinx/parser/
errors.rs

1use log;
2use core::fmt;
3use std::error::Error;
4use crate::utils;
5use crate::lexer::{TokenMeta, LexerError};
6use crate::debug::SourceError;
7use crate::debug::symbol::DebugSymbol;
8
9
10pub type ParseResult<T> = Result<T, ParserError>;
11
12#[derive(Debug)]
13pub enum ErrorKind {
14    LexerError,
15    EndofTokenStream,
16    SyntaxError(String),
17}
18
19impl<S> From<S> for ErrorKind where S: ToString {
20    fn from(message: S) -> Self {
21        ErrorKind::SyntaxError(message.to_string())
22    }
23}
24
25// Provide information about the type of syntactic construct from which the error originated
26#[derive(Debug, Clone, Copy)]
27pub enum ContextTag {
28    Token,  // errors retrieving the actual tokens
29    TopLevel,
30    Sync,
31    StmtMeta,
32    StmtList,
33    ControlFlow,
34    Loop,
35    WhileLoop,
36    ForLoop,
37    ExprMeta,
38    ExprList,
39    Expr,
40    BlockExpr,
41    IfExpr,
42    FunDefExpr,
43    FunParam,
44    AssignmentExpr,
45    BinaryOpExpr,
46    UnaryOpExpr,
47    PrimaryExpr,
48    MemberAccess,
49    IndexAccess,
50    Invocation,
51    ObjectCtor,
52    TupleCtor,
53    Atom,
54    Group,
55    LValue,
56    Label,
57}
58
59impl From<ErrorKind> for ParserError {
60    fn from(kind: ErrorKind) -> Self {
61        Self { 
62            kind, context: None, symbol: None, cause: None,
63        }
64    }
65}
66
67impl From<&str> for ParserError {
68    fn from(message: &str) -> Self {
69        Self { 
70            kind: message.into(), 
71            context: None, symbol: None, cause: None,
72        }
73    }
74}
75
76impl From<LexerError> for ParserError {
77    fn from(error: LexerError) -> Self {
78        Self { 
79            kind: ErrorKind::LexerError, 
80            context: None,
81            symbol: Some(*error.debug_symbol()),
82            cause: Some(Box::new(error)),
83        }
84    }
85}
86
87#[derive(Debug)]
88pub struct ParserError {
89    kind: ErrorKind,
90    context: Option<ContextTag>,
91    symbol: Option<DebugSymbol>,
92    cause: Option<Box<dyn Error>>,
93}
94
95impl ParserError {
96    pub fn with_context_tag(mut self, context: ContextTag) -> Self {
97        self.context.get_or_insert(context); self
98    }
99    
100    pub fn with_symbol(mut self, symbol: DebugSymbol) -> Self {
101        self.symbol.get_or_insert(symbol); self
102    }
103    
104    pub fn with_symbol_from_ctx(mut self, ctx: &ErrorContext) -> Self {
105        if let Some(symbol) = ctx.frame().as_debug_symbol() {
106            self.symbol.replace(symbol);
107        }
108        self
109    }
110    
111    pub fn with_cause(mut self, error: impl Error + 'static) -> Self {
112        self.cause.replace(Box::new(error)); self
113    }
114    
115    // fill in fields from context if not already set
116    pub fn with_error_context(mut self, context: ErrorContext) -> Self {
117        if self.context.is_none() {
118            self.context.replace(context.frame().context());
119        }
120        if self.symbol.is_none() {
121            self.symbol.replace(context.take_debug_symbol());
122        }
123        self
124    }
125    
126    pub fn kind(&self) -> &ErrorKind { &self.kind }
127    pub fn context(&self) -> Option<&ContextTag> { self.context.as_ref() }
128}
129
130
131impl Error for ParserError {
132    fn source(&self) -> Option<&(dyn Error + 'static)> {
133        self.cause.as_ref().map(|o| o.as_ref())
134    }
135}
136
137impl SourceError for ParserError {
138    fn debug_symbol(&self) -> Option<&DebugSymbol> { self.symbol.as_ref() }
139}
140
141impl fmt::Display for ParserError {
142    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
143        
144        let message = match self.kind() {
145            ErrorKind::LexerError => "",
146            ErrorKind::EndofTokenStream => "unexpected end of token stream",
147            ErrorKind::SyntaxError(message) => message,
148        };
149        
150        utils::format_error(fmt, "Syntax error", Some(message), self.source())
151    }
152}
153// "unpacking may only be used once in an assignment or declaration"
154
155// Structures used by the parser for error handling and synchronization
156
157#[derive(Debug)]
158pub struct ErrorContext {
159    stack: Vec<ContextFrame>,
160}
161
162impl<'m> ErrorContext {
163    pub fn new(base: ContextTag) -> Self {
164        ErrorContext {
165            stack: vec![ ContextFrame::new(base) ],
166        }
167    }
168    
169    pub fn frame(&self) -> &ContextFrame { 
170        self.stack.last().unwrap() 
171    }
172    
173    pub fn frame_mut(&mut self) -> &mut ContextFrame { 
174        self.stack.last_mut().unwrap() 
175    }
176    
177    pub fn push(&mut self, tag: ContextTag) { 
178        log::debug!("Push frame: {:0>3} {:?}", self.stack.len()+1, tag);
179        self.stack.push(ContextFrame::new(tag)) 
180    }
181    
182    // treat the prev top frame as if it was *above* the new top frame
183    pub fn push_continuation(&mut self, tag: ContextTag, frame: Option<ContextFrame>) {
184        // log::debug!("Set frame:  {:0>3} {:?} -> {:?}", self.stack.len(), self.frame().context(), tag);
185        let frame = frame.unwrap_or_else(|| self.frame().clone());
186        self.push(tag);
187        self.frame_mut().extend(frame);
188    }
189    
190    pub fn pop(&mut self) -> ContextFrame { 
191        log::debug!("Pop frame:  {:0>3} {:?}", self.stack.len(), self.frame().context());
192        assert!(self.stack.len() > 1);
193        self.stack.pop().unwrap()
194    }
195    
196    pub fn pop_extend(&mut self) {
197        let inner_frame = self.pop();
198        self.frame_mut().extend(inner_frame);
199    }
200    
201    pub fn take(mut self) -> ContextFrame {
202        assert!(!self.stack.is_empty());
203        self.stack.pop().unwrap()
204    }
205    
206    // for convenience
207    pub fn context(&self) -> ContextTag { self.frame().context() }
208    pub fn set_start(&mut self, token: &TokenMeta) { self.frame_mut().set_start(token) }
209    pub fn set_end(&mut self, token: &TokenMeta) { self.frame_mut().set_end(token) }
210    
211    pub fn take_debug_symbol(mut self) -> DebugSymbol {
212        let mut symbol = self.frame().as_debug_symbol();
213        while symbol.is_none() {
214            if self.stack.len() <= 1 {
215                symbol = self.take().as_debug_symbol();
216                break;
217            }
218            
219            self.pop();
220            symbol = self.frame().as_debug_symbol();
221        }
222        
223        symbol.expect("could not take debug symbol")
224    }
225}
226
227#[derive(Debug, Clone)]
228pub struct ContextFrame {
229    tag: ContextTag,
230    start: Option<DebugSymbol>,
231    end: Option<DebugSymbol>,
232}
233
234
235impl ContextFrame {
236    pub fn new(tag: ContextTag) -> Self { ContextFrame { tag, start: None, end: None } }
237    
238    pub fn context(&self) -> ContextTag { self.tag }
239    pub fn start(&self) -> Option<&DebugSymbol> { self.start.as_ref() }
240    pub fn end(&self) -> Option<&DebugSymbol> { self.end.as_ref() }
241    
242    pub fn set_start(&mut self, token: &TokenMeta) { 
243        self.start.replace(token.symbol); 
244    }
245    
246    pub fn set_end(&mut self, token: &TokenMeta) { 
247        self.end.replace(token.symbol); 
248    }
249    
250    pub fn set_span(&mut self, start: Option<DebugSymbol>, end: Option<DebugSymbol>) {
251        self.start = start;
252        self.end = end;
253    }
254    
255    pub fn extend(&mut self, other: ContextFrame) {
256        let spans = [self.start, other.start, self.end, other.end];
257        let start = spans.iter().filter_map(|s| s.as_ref())
258            .min_by(|a, b| a.start().cmp(&b.start()));
259        
260        let end = spans.iter().filter_map(|s| s.as_ref())
261            .max_by(|a, b| a.end().cmp(&b.end()));
262        
263        self.start = start.copied();
264        self.end = end.copied();
265    }
266    
267    pub fn as_debug_symbol(&self) -> Option<DebugSymbol> {
268        match (self.start, self.end) {
269            
270            (Some(start), Some(end)) => {
271                (start.start(), end.end()).try_into().ok()
272            },
273            
274            (Some(symbol), None) | (None, Some(symbol)) => {
275                Some(symbol)
276            },
277            
278            (None, None) => None,
279        }
280    }
281}
282
283