blueprint_starlark_syntax/
call_stack.rs

1/*
2 * Copyright 2019 The Starlark in Rust Authors.
3 * Copyright (c) Facebook, Inc. and its affiliates.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18//! Starlark call stack.
19
20// FIXME: I think we should rewrite the CallStack stuff entirely:
21// * Don't keep a call stack, just a call stack depth.
22// * When people did StackGuard.inc just do CallStack.inc, we need less info
23// once it's an int so can reuse.
24// * When an exception happens, decorate it with the call stack on the way back
25//   up, in eval_call.
26
27use std::fmt;
28use std::fmt::Debug;
29use std::fmt::Display;
30
31use crate::frame::Frame;
32
33pub const CALL_STACK_TRACEBACK_PREFIX: &str = "Traceback (most recent call last):";
34
35/// Owned call stack.
36#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
37pub struct CallStack {
38    /// The frames.
39    pub frames: Vec<Frame>,
40}
41
42impl CallStack {
43    /// Is the call stack empty?
44    pub fn is_empty(&self) -> bool {
45        self.frames.is_empty()
46    }
47
48    /// Take the contained frames.
49    pub fn into_frames(self) -> Vec<Frame> {
50        self.frames
51    }
52}
53
54impl Display for CallStack {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        if !self.frames.is_empty() {
57            // Match Python output.
58            writeln!(f, "{CALL_STACK_TRACEBACK_PREFIX}")?;
59            // TODO(nga): use real module name.
60            let mut prev = "<module>";
61            for x in &self.frames {
62                x.write_two_lines("  ", prev, f)?;
63                prev = &x.name;
64            }
65        }
66        Ok(())
67    }
68}