mica_language/
common.rs

1//! Common things, mostly error handling-related.
2
3use std::borrow::Cow;
4use std::fmt;
5use std::rc::Rc;
6
7/// A source location.
8#[derive(Debug, Clone, Copy)]
9pub struct Location {
10   pub byte: usize,
11   pub line: u32,
12   pub column: u32,
13}
14
15impl Location {
16   /// The "uninitialized" location, used as a placeholder for proper locations in case there's a
17   /// bug in codegen.
18   pub const UNINIT: Self = Self {
19      byte: 0,
20      line: 0,
21      column: 0,
22   };
23
24   /// Returns whether this location is the uninitialized location.
25   pub fn is_uninit(&self) -> bool {
26      self.line == 0 && self.column == 0
27   }
28}
29
30/// The default location points to the first column on the first line.
31impl Default for Location {
32   fn default() -> Self {
33      Self {
34         byte: 0,
35         line: 1,
36         column: 1,
37      }
38   }
39}
40
41impl std::fmt::Display for Location {
42   fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43      write!(f, "{}:{}", self.line, self.column)
44   }
45}
46
47/// A [`FunctionSignature`][crate::bytecode::FunctionSignature] that can be rendered into text. One
48/// can be obtained by calling
49/// [`FunctionSignature::render`][crate::bytecode::FunctionSignature::render].
50#[derive(Debug, Clone, PartialEq, Eq, Hash)]
51pub struct RenderedSignature {
52   pub name: Rc<str>,
53   /// This arity number does not include the implicit `self` argument.
54   pub arity: Option<u16>,
55   /// The index of the trait this signature belongs to.
56   /// When `None`, the function is free and does not belong to any trait.
57   pub trait_name: Option<Rc<str>>,
58}
59
60impl RenderedSignature {
61   /// The empty string name is considered to be the invalid name, and will result in different
62   /// `Display`.
63   pub const INVALID_NAME: &'static str = "";
64
65   pub fn invalid() -> Self {
66      Self {
67         name: Rc::from(Self::INVALID_NAME),
68         arity: None,
69         trait_name: None,
70      }
71   }
72
73   pub fn is_invalid(&self) -> bool {
74      &*self.name == Self::INVALID_NAME
75   }
76}
77
78impl fmt::Display for RenderedSignature {
79   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80      if self.is_invalid() {
81         write!(f, "(invalid method)")?;
82         return Ok(());
83      }
84
85      if let Some(arity) = self.arity {
86         write!(f, "{}/{arity}", self.name)?;
87      } else {
88         write!(f, "{}/...", self.name)?;
89      }
90
91      if let Some(trait_name) = &self.trait_name {
92         write!(f, " (as {trait_name})")?;
93      }
94
95      Ok(())
96   }
97}
98
99/// The kind of an error.
100///
101/// Check the source code of the `Display` implementation to see which error kind corresponds
102/// to which error message.
103#[derive(Debug)]
104pub enum ErrorKind {
105   // Lexer
106   InvalidCharacter(char),
107   MissingDigitsAfterDecimalPoint,
108   MissingExponent,
109   UnderscoresWithoutDigits,
110   MissingClosingQuote,
111   InvalidEscape(char),
112   LineBreakInStringIsNotAllowed,
113   UEscapeLeftBraceExpected,
114   UEscapeMissingRightBrace,
115   UEscapeEmpty,
116   UEscapeOutOfRange,
117   InvalidBackslashLiteral(char),
118   RawStringMissingOpeningQuote,
119   IntLiteralOutOfRange,
120   IntRadixOutOfRange,
121   ColonExpectedAfterRadix,
122   CharacterMissingOpeningApostrophe,
123   CharacterMissingClosingApostrophe,
124
125   // Parser
126   InvalidPrefixToken,
127   InvalidInfixToken,
128   MissingDo,
129   MissingRightParen,
130   MissingEnd,
131   InvalidIfBranchToken,
132   BranchAfterElse,
133   IdentifierExpected,
134   LeftParenExpected,
135   UnexpectedEof,
136   CommaExpected,
137   ColonExpectedAfterDictKey,
138   RightBracketExpectedToCloseEmptyDict,
139   InExpectedAfterForBinding,
140
141   // Code generator
142   VariableDoesNotExist(Rc<str>),
143   InvalidAssignment,
144   TooManyLocals,
145   TooManyGlobals,
146   TooManyCaptures,
147   IfBranchTooLarge,
148   IfExpressionTooLarge,
149   OperatorRhsTooLarge,
150   LoopTooLarge,
151   BreakOutsideOfLoop,
152   TooManyFunctions,
153   TooManyArguments,
154   TooManyParameters,
155   TooManyMethods,
156   InvalidMethodName,
157   FunctionKindOutsideImpl,
158   MissingFunctionBody,
159   InvalidImplItem,
160   MissingMethodName,
161   TooManyImpls,
162   MethodAlreadyImplemented(RenderedSignature),
163   TooManyFields,
164   FieldDoesNotExist(Rc<str>),
165   FieldOutsideOfImpl,
166   MissingFields(Vec<Rc<str>>),
167   ListIsTooLong,
168   DictIsTooLarge,
169   TooManyTraits,
170   InvalidTraitItem,
171   TraitMethodCannotHaveBody,
172   TraitAlreadyHasMethod(RenderedSignature),
173   AsOutsideOfImpl,
174   TooManyTraitsInImpl,
175   AsCannotNest,
176   FunctionKindInTrait,
177   InvalidPattern,
178
179   // Runtime
180   TypeError {
181      expected: Cow<'static, str>,
182      got: Cow<'static, str>,
183   },
184   MethodDoesNotExist {
185      type_name: Rc<str>,
186      signature: RenderedSignature,
187   },
188   StructAlreadyImplemented,
189   UserDataAlreadyBorrowed,
190   DoubleMethodImplementation {
191      type_name: Rc<str>,
192      signature: RenderedSignature,
193   },
194   MethodsUnimplemented {
195      type_name: Rc<str>,
196      methods: Vec<RenderedSignature>,
197   },
198
199   User(Box<dyn std::error::Error>),
200}
201
202impl std::fmt::Display for ErrorKind {
203   fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204      match self {
205         Self::InvalidCharacter(c) => write!(f, "invalid character: {c:?}"),
206         Self::MissingDigitsAfterDecimalPoint => write!(f, "missing digits after decimal point"),
207         Self::MissingExponent => write!(f, "number exponent expected"),
208         Self::UnderscoresWithoutDigits => write!(f, "at least one digit expected, got only underscores"),
209         Self::MissingClosingQuote => write!(f, "missing closing quote '\"'"),
210         Self::InvalidEscape(c) => write!(f, "invalid escape: \\{c}"),
211         Self::LineBreakInStringIsNotAllowed => write!(f, "line breaks are not allowed in string literals; use \\n or a long string literal \\\\"),
212         Self::UEscapeLeftBraceExpected => write!(f, "left brace '{{' expected after \\u escape"),
213         Self::UEscapeEmpty => write!(f, "\\u escape is empty"),
214         Self::UEscapeMissingRightBrace => {
215            write!(f, "missing right brace '}}' for this \\u escape")
216         }
217         Self::UEscapeOutOfRange => write!(
218            f,
219            "Unicode scalar value in \\u escape is out of range (must be <= 10FFFF and outside of D800..DFFF)"
220         ),
221         Self::InvalidBackslashLiteral(c) => write!(f, "invalid extended literal: \\{c}"),
222         Self::RawStringMissingOpeningQuote => write!(f, "missing opening quote '\"' in \\r string"),
223         Self::IntLiteralOutOfRange => write!(f, "integer literal out of range"),
224         Self::IntRadixOutOfRange => write!(f, "integer radix out of range; must be >= 2 and <= 36"),
225         Self::ColonExpectedAfterRadix => write!(f, "colon ':' expected after integer radix"),
226         Self::CharacterMissingOpeningApostrophe => write!(f, "apostrophe ' expected to begin character literal"),
227         Self::CharacterMissingClosingApostrophe => write!(f, "apostrophe ' expected to end character literal"),
228
229         Self::InvalidPrefixToken => write!(f, "invalid token in prefix position"),
230         Self::InvalidInfixToken => write!(f, "invalid token in infix position"),
231         Self::MissingDo => write!(f, "'do' expected"),
232         Self::MissingRightParen => write!(f, "missing right parenthesis ')'"),
233         Self::MissingEnd => write!(f, "missing 'end'"),
234         Self::InvalidIfBranchToken => write!(f, "'elif', 'else', or 'end' expected"),
235         Self::BranchAfterElse => write!(f, "extraneous branch after 'else'"),
236         Self::IdentifierExpected => write!(f, "identifier expected"),
237         Self::LeftParenExpected => write!(f, "left parenthesis '(' expected"),
238         Self::UnexpectedEof => write!(f, "unexpected end of file"),
239         Self::CommaExpected => write!(f, "comma ',' expected"),
240         Self::ColonExpectedAfterDictKey => write!(f, "colon ':' expected after dict key"),
241         Self::RightBracketExpectedToCloseEmptyDict => write!(f, "right bracket ']' expected to close empty dict literal [:]"),
242         Self::MissingFunctionBody => write!(f, "missing function body ('= expression')"),
243         Self::InExpectedAfterForBinding => write!(f, "'in' expected after 'for' loop variable binding"),
244
245         Self::VariableDoesNotExist(name) => write!(f, "variable '{name}' does not exist"),
246         Self::InvalidAssignment => write!(f, "invalid left hand side of assignment"),
247         Self::TooManyLocals => write!(f, "too many local variables"),
248         Self::TooManyGlobals => write!(f, "too many global variables"),
249         Self::TooManyCaptures => write!(f, "too many variables captured in the closure"),
250         Self::IfBranchTooLarge => write!(f, "'if' branch is too large"),
251         Self::IfExpressionTooLarge => write!(f, "'if' expression is too large"),
252         Self::OperatorRhsTooLarge => write!(f, "the right-hand side of the operator is too large"),
253         Self::LoopTooLarge => write!(f, "loop is too large"),
254         Self::BreakOutsideOfLoop => write!(f, "'break' cannot be used outside of a loop"),
255         Self::TooManyFunctions => write!(f, "too many unique functions"),
256         Self::TooManyArguments => write!(f, "too many arguments"),
257         Self::TooManyParameters => write!(f, "too many parameters"),
258         Self::TooManyMethods => write!(f, "too many instance functions with different signatures"),
259         Self::InvalidMethodName => write!(f, "method name must be an identifier"),
260         Self::FunctionKindOutsideImpl => write!(
261            f,
262            "function kinds (static, constructor) can only be used in 'impl' blocks"
263         ),
264         Self::InvalidImplItem => write!(f, "only functions and 'as' blocks are allowed in 'impl' blocks"),
265         Self::MissingMethodName => write!(f, "missing method name"),
266         Self::TooManyImpls => write!(f, "too many 'impl' blocks"),
267         Self::MethodAlreadyImplemented(signature) => {
268            write!(f, "method {signature} is already implemented")
269         }
270         Self::TooManyFields => write!(f, "too many fields"),
271         Self::FieldOutsideOfImpl => {
272            write!(f, "fields cannot be referenced outside of 'impl' blocks")
273         }
274         Self::FieldDoesNotExist(name) => write!(f, "field '@{name}' does not exist"),
275         Self::MissingFields(fields) => {
276            let fields: Vec<_> = fields.iter().map(|name| format!("@{name}")).collect();
277            let fields = fields.join(", ");
278            write!(
279               f,
280               "the following fields were not assigned in this constructor: {fields}"
281            )
282         }
283         Self::ListIsTooLong => write!(f, "list literal has too many elements"),
284         Self::DictIsTooLarge => write!(f, "dict literal has too many pairs"),
285         Self::TooManyTraits => write!(f, "too many traits"),
286         Self::InvalidTraitItem => write!(f, "only function prototypes are allowed in traits"),
287         Self::TraitMethodCannotHaveBody => write!(f, "trait functions cannot have bodies"),
288         Self::TraitAlreadyHasMethod(signature) => {
289            write!(f, "trait already declares the method {signature}")
290         }
291         Self::AsOutsideOfImpl => write!(f, "'as' is not allowed outside of 'impl' blocks"),
292         Self::TooManyTraitsInImpl => write!(f, "too many 'as' blocks in 'impl'"),
293         Self::AsCannotNest => write!(f, "'as' blocks cannot nest"),
294         Self::FunctionKindInTrait => write!(f, "trait functions must be instance methods (cannot be constructors nor statics)"),
295         Self::InvalidPattern => write!(f, "invalid pattern for destructuring into variables"),
296
297         Self::TypeError { expected, got } => {
298            write!(f, "type mismatch, expected {expected} but got {got}")
299         }
300         Self::MethodDoesNotExist { type_name, signature } => write!(f, "method {} is not defined for {}", signature, type_name),
301         Self::StructAlreadyImplemented => write!(f, "this struct is already implemented"),
302         Self::UserDataAlreadyBorrowed => write!(f, "this user data is already borrowed"),
303         Self::DoubleMethodImplementation { type_name, signature } => {
304            write!(f, "method {signature} is already implemented by {type_name}")
305         }
306         Self::MethodsUnimplemented { type_name, methods } => {
307            writeln!(f, "{type_name} is missing the following trait methods:")?;
308            for (i, signature) in methods.iter().enumerate() {
309               if i > 0 {
310                  writeln!(f)?;
311               }
312               write!(f, "    - {signature}")?;
313            }
314            Ok(())
315         }
316
317         Self::User(error) => write!(f, "{}", error),
318      }
319   }
320}
321
322/// An entry of a stack trace.
323#[derive(Debug)]
324pub struct StackTraceEntry {
325   /// The name of the current function.
326   pub function_name: Rc<str>,
327   /// The name of the module the function was in.
328   pub module_name: Rc<str>,
329   /// The source location in the module.
330   pub location: Location,
331}
332
333/// An error.
334#[derive(Debug)]
335pub enum Error {
336   /// A compile-time error.
337   Compile {
338      kind: ErrorKind,
339      module_name: Rc<str>,
340      location: Location,
341   },
342   /// A runtime error.
343   Runtime {
344      kind: ErrorKind,
345      call_stack: Vec<StackTraceEntry>,
346   },
347}
348
349impl std::fmt::Display for Error {
350   fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351      struct FileLocation<'a>(&'a str, Location);
352
353      impl std::fmt::Display for FileLocation<'_> {
354         fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
355            let Self(file, location) = self;
356            if location.is_uninit() {
357               write!(f, "{}", file)
358            } else {
359               write!(f, "{}:{}", file, location)
360            }
361         }
362      }
363
364      match self {
365         Error::Compile {
366            kind,
367            module_name,
368            location,
369         } => {
370            write!(f, "{module_name}:{location}: error: {kind}")
371         }
372         Error::Runtime { kind, call_stack } => {
373            writeln!(f, "error: {}", kind)?;
374            write!(f, "stack traceback (most recent call first):")?;
375            let file_location_width = call_stack
376               .iter()
377               .map(|entry| FileLocation(&entry.module_name, entry.location).to_string().len())
378               .max()
379               .unwrap_or(20);
380            for entry in call_stack.iter().rev() {
381               write!(
382                  f,
383                  "\n    {:width$}  {}",
384                  // Well this is a bit horrible.
385                  FileLocation(&entry.module_name, entry.location).to_string(),
386                  entry.function_name,
387                  width = file_location_width,
388               )?;
389            }
390            Ok(())
391         }
392      }
393   }
394}