Skip to content

Commit

Permalink
Merge 9bd6ce5 into bd1c38a
Browse files Browse the repository at this point in the history
  • Loading branch information
minestarks authored Jan 18, 2024
2 parents bd1c38a + 9bd6ce5 commit fabbf52
Show file tree
Hide file tree
Showing 52 changed files with 1,699 additions and 1,337 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

179 changes: 108 additions & 71 deletions compiler/qsc/src/interpret/stateful.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ use miette::Diagnostic;
use num_bigint::BigUint;
use num_complex::Complex;
use qsc_codegen::qir_base::BaseProfSim;
use qsc_data_structures::span::Span;
use qsc_data_structures::{
line_column::{Encoding, Range},
span::Span,
};
use qsc_eval::{
backend::{Backend, SparseSim},
debug::{map_fir_package_to_hir, map_hir_package_to_fir, Frame},
Expand Down Expand Up @@ -92,8 +95,6 @@ pub struct Interpreter {
sim: SparseSim,
/// The evaluator environment.
env: Env,
/// The current state of the evaluator.
state: State,
}

pub type InterpretResult = Result<Value, Vec<Error>>;
Expand Down Expand Up @@ -132,51 +133,11 @@ impl Interpreter {
lowerer,
env: Env::with_empty_scope(),
sim: SparseSim::new(),
state: State::new(map_hir_package_to_fir(source_package_id)),
package: map_hir_package_to_fir(package_id),
source_package: map_hir_package_to_fir(source_package_id),
})
}

/// Loads the entry expression to the top of the evaluation stack.
/// This is needed for debugging so that when begging to debug with
/// a step action the system is already in the correct state.
/// # Errors
/// Returns a vector of errors if loading the entry point fails.
pub fn set_entry(&mut self) -> Result<(), Vec<Error>> {
let expr = self.get_entry_expr()?;
qsc_eval::eval_push_expr(&mut self.state, expr);
Ok(())
}

/// Resumes execution with specified `StepAction`.
/// # Errors
/// Returns a vector of errors if evaluating the entry point fails.
pub fn eval_step(
&mut self,
receiver: &mut impl Receiver,
breakpoints: &[StmtId],
step: StepAction,
) -> Result<StepResult, Vec<Error>> {
self.state
.eval(
&self.fir_store,
&mut self.env,
&mut self.sim,
receiver,
breakpoints,
step,
)
.map_err(|(error, call_stack)| {
eval_error(
self.compiler.package_store(),
&self.fir_store,
call_stack,
error,
)
})
}

/// Executes the entry expression until the end of execution.
/// # Errors
/// Returns a vector of errors if evaluating the entry point fails.
Expand Down Expand Up @@ -385,18 +346,70 @@ impl Interpreter {
.lower_and_update_package(fir_package, &unit_addition.hir)
}

fn source_package(&self) -> &CompileUnit {
self.compiler
.package_store()
.get(map_fir_package_to_hir(self.source_package))
.expect("Could not load package")
}

fn next_line_label(&mut self) -> String {
let label = format!("line_{}", self.lines);
self.lines += 1;
label
}
}

pub struct Debugger {
interpreter: Interpreter,
/// The encoding (utf-8 or utf-16) used for character offsets
/// in line/character positions returned by the Interpreter.
position_encoding: Encoding,
/// The current state of the evaluator.
state: State,
}

impl Debugger {
pub fn new(interpreter: Interpreter, position_encoding: Encoding) -> Self {
let source_package_id = interpreter.source_package;
Self {
interpreter,
position_encoding,
state: State::new(source_package_id),
}
}

/// Loads the entry expression to the top of the evaluation stack.
/// This is needed for debugging so that when begging to debug with
/// a step action the system is already in the correct state.
/// # Errors
/// Returns a vector of errors if loading the entry point fails.
pub fn set_entry(&mut self) -> Result<(), Vec<Error>> {
let expr = self.interpreter.get_entry_expr()?;
qsc_eval::eval_push_expr(&mut self.state, expr);
Ok(())
}

/// Resumes execution with specified `StepAction`.
/// # Errors
/// Returns a vector of errors if evaluating the entry point fails.
pub fn eval_step(
&mut self,
receiver: &mut impl Receiver,
breakpoints: &[StmtId],
step: StepAction,
) -> Result<StepResult, Vec<Error>> {
self.state
.eval(
&self.interpreter.fir_store,
&mut self.interpreter.env,
&mut self.interpreter.sim,
receiver,
breakpoints,
step,
)
.map_err(|(error, call_stack)| {
eval_error(
self.interpreter.compiler.package_store(),
&self.interpreter.fir_store,
call_stack,
error,
)
})
}

#[must_use]
pub fn get_stack_frames(&self) -> Vec<StackFrame> {
Expand All @@ -405,6 +418,7 @@ impl Interpreter {
.iter()
.map(|frame| {
let callable = self
.interpreter
.fir_store
.get_global(frame.id)
.expect("frame should exist");
Expand All @@ -415,6 +429,7 @@ impl Interpreter {
};

let hir_package = self
.interpreter
.compiler
.package_store()
.get(map_fir_package_to_hir(frame.id.package))
Expand All @@ -424,20 +439,24 @@ impl Interpreter {
.find_by_offset(frame.span.lo)
.expect("frame should have a source");
let path = source.name.to_string();

StackFrame {
name,
functor,
path,
lo: frame.span.lo - source.offset,
hi: frame.span.hi - source.offset,
range: Range::from_span(
self.position_encoding,
&source.contents,
&(frame.span - source.offset),
),
}
})
.collect();
stack_frames
}

pub fn capture_quantum_state(&mut self) -> (Vec<(BigUint, Complex<f64>)>, usize) {
self.sim.capture_quantum_state()
self.interpreter.sim.capture_quantum_state()
}

#[must_use]
Expand All @@ -446,21 +465,28 @@ impl Interpreter {

if let Some(source) = unit.sources.find_by_name(path) {
let package = self
.interpreter
.fir_store
.get(self.source_package)
.get(self.interpreter.source_package)
.expect("package should have been lowered");
let mut collector = BreakpointCollector::new(&unit.sources, source.offset, package);
let mut collector = BreakpointCollector::new(
&unit.sources,
source.offset,
package,
self.position_encoding,
);
collector.visit_package(package);
let mut spans: Vec<_> = collector
.statements
.iter()
.map(|bps| BreakpointSpan {
id: bps.id,
lo: bps.lo,
hi: bps.hi,
range: bps.range,
})
.collect();
spans.sort_by_key(|s| s.lo);

// Sort by start position (line first, column next)
spans.sort_by_key(|s| (s.range.start_line, s.range.start_column));
spans
} else {
Vec::new()
Expand All @@ -469,12 +495,21 @@ impl Interpreter {

#[must_use]
pub fn get_locals(&self) -> Vec<VariableInfo> {
self.env
self.interpreter
.env
.get_variables_in_top_frame()
.into_iter()
.filter(|v| !v.name.starts_with('@'))
.collect()
}

fn source_package(&self) -> &CompileUnit {
self.interpreter
.compiler
.package_store()
.get(map_fir_package_to_hir(self.interpreter.source_package))
.expect("Could not load package")
}
}

/// Represents a stack frame for debugging.
Expand All @@ -485,36 +520,39 @@ pub struct StackFrame {
pub functor: String,
/// The path of the source file.
pub path: String,
/// The start of the call site span in utf8 characters.
pub lo: u32,
/// The end of the call site span in utf8 characters.
pub hi: u32,
/// The call site span.
pub range: Range,
}

#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct BreakpointSpan {
/// The id of the statement representing the breakpoint location.
pub id: u32,
/// The start of the call site span in utf8 characters.
pub lo: u32,
/// The end of the call site span in utf8 characters.
pub hi: u32,
/// The call site span.
pub range: Range,
}

struct BreakpointCollector<'a> {
statements: FxHashSet<BreakpointSpan>,
sources: &'a SourceMap,
offset: u32,
package: &'a Package,
position_encoding: Encoding,
}

impl<'a> BreakpointCollector<'a> {
fn new(sources: &'a SourceMap, offset: u32, package: &'a Package) -> Self {
fn new(
sources: &'a SourceMap,
offset: u32,
package: &'a Package,
position_encoding: Encoding,
) -> Self {
Self {
statements: FxHashSet::default(),
sources,
offset,
package,
position_encoding,
}
}

Expand All @@ -531,8 +569,7 @@ impl<'a> BreakpointCollector<'a> {
if span != Span::default() {
let bps = BreakpointSpan {
id: stmt.id.into(),
lo: span.lo,
hi: span.hi,
range: Range::from_span(self.position_encoding, &source.contents, &span),
};
self.statements.insert(bps);
}
Expand Down
Loading

0 comments on commit fabbf52

Please sign in to comment.