setting top level values

This commit is contained in:
Michael Benfield 2024-11-21 13:29:00 -08:00
parent 334881cef5
commit 94638be01a
2 changed files with 32 additions and 18 deletions

View File

@ -245,6 +245,8 @@ pub struct Cursor<'a> {
/// Consts are stored here. /// Consts are stored here.
pub globals: HashMap<GlobalId, Value>, pub globals: HashMap<GlobalId, Value>,
pub user_values: HashMap<Symbol, Value>,
pub mappings: HashMap<GlobalId, HashMap<Value, Value>>, pub mappings: HashMap<GlobalId, HashMap<Value, Value>>,
/// For each struct type, we only need to remember the names of its members, in order. /// For each struct type, we only need to remember the names of its members, in order.
@ -271,6 +273,7 @@ impl<'a> Cursor<'a> {
values: Default::default(), values: Default::default(),
functions: Default::default(), functions: Default::default(),
globals: Default::default(), globals: Default::default(),
user_values: Default::default(),
mappings: Default::default(), mappings: Default::default(),
structs: Default::default(), structs: Default::default(),
contexts: Default::default(), contexts: Default::default(),
@ -310,16 +313,15 @@ impl<'a> Cursor<'a> {
} }
fn lookup(&self, name: Symbol) -> Option<Value> { fn lookup(&self, name: Symbol) -> Option<Value> {
let Some(context) = self.contexts.last() else { if let Some(context) = self.contexts.last() {
panic!("lookup requires a context"); let option_value =
context.names.get(&name).or_else(|| self.globals.get(&GlobalId { program: context.program, name }));
if option_value.is_some() {
return option_value.cloned();
}
}; };
let option_value = context.names.get(&name); self.user_values.get(&name).cloned()
if option_value.is_some() {
return option_value.cloned();
}
self.globals.get(&GlobalId { program: context.program, name }).cloned()
} }
pub fn lookup_mapping(&self, program: Option<Symbol>, name: Symbol) -> Option<&HashMap<Value, Value>> { pub fn lookup_mapping(&self, program: Option<Symbol>, name: Symbol) -> Option<&HashMap<Value, Value>> {
@ -340,6 +342,14 @@ impl<'a> Cursor<'a> {
self.functions.get(&GlobalId { program, name }).cloned() self.functions.get(&GlobalId { program, name }).cloned()
} }
fn set_variable(&mut self, symbol: Symbol, value: Value) {
if self.contexts.len() > 0 {
self.contexts.set(symbol, value);
} else {
self.user_values.insert(symbol, value);
}
}
/// Execute the whole step of the current Element. /// Execute the whole step of the current Element.
/// ///
/// That is, perform a step, and then finish all statements and expressions that have been pushed, /// That is, perform a step, and then finish all statements and expressions that have been pushed,
@ -462,7 +472,7 @@ impl<'a> Cursor<'a> {
Statement::Assign(assign) if step == 1 => { Statement::Assign(assign) if step == 1 => {
let value = self.values.pop().unwrap(); let value = self.values.pop().unwrap();
let Expression::Identifier(id) = &assign.place else { tc_fail!() }; let Expression::Identifier(id) = &assign.place else { tc_fail!() };
self.contexts.set(id.name, value); self.set_variable(id.name, value);
true true
} }
Statement::Block(block) => return Ok(self.step_block(block, false, step)), Statement::Block(block) => return Ok(self.step_block(block, false, step)),
@ -494,7 +504,7 @@ impl<'a> Cursor<'a> {
} }
Statement::Const(const_) if step == 1 => { Statement::Const(const_) if step == 1 => {
let value = self.pop_value()?; let value = self.pop_value()?;
self.contexts.set(const_.place.name, value); self.set_variable(const_.place.name, value);
true true
} }
Statement::Definition(definition) if step == 0 => { Statement::Definition(definition) if step == 0 => {
@ -504,7 +514,7 @@ impl<'a> Cursor<'a> {
Statement::Definition(definition) if step == 1 => { Statement::Definition(definition) if step == 1 => {
let value = self.pop_value()?; let value = self.pop_value()?;
match &definition.place { match &definition.place {
Expression::Identifier(id) => self.contexts.set(id.name, value), Expression::Identifier(id) => self.set_variable(id.name, value),
Expression::Tuple(tuple) => { Expression::Tuple(tuple) => {
let Value::Tuple(rhs) = value else { let Value::Tuple(rhs) = value else {
tc_fail!(); tc_fail!();
@ -513,7 +523,7 @@ impl<'a> Cursor<'a> {
let Expression::Identifier(id) = name else { let Expression::Identifier(id) = name else {
tc_fail!(); tc_fail!();
}; };
self.contexts.set(id.name, val); self.set_variable(id.name, val);
} }
} }
_ => tc_fail!(), _ => tc_fail!(),
@ -542,7 +552,7 @@ impl<'a> Cursor<'a> {
true true
} else { } else {
let new_start = start.inc_wrapping(); let new_start = start.inc_wrapping();
self.contexts.set(iteration.variable.name, start); self.set_variable(iteration.variable.name, start);
self.frames.push(Frame { self.frames.push(Frame {
step: 0, step: 0,
element: Element::Block { block: &iteration.block, function_body: false }, element: Element::Block { block: &iteration.block, function_body: false },
@ -906,15 +916,15 @@ impl<'a> Cursor<'a> {
FunctionVariant::Leo(function) => { FunctionVariant::Leo(function) => {
assert!(function.variant == Variant::AsyncFunction); assert!(function.variant == Variant::AsyncFunction);
let len = self.values.len(); let len = self.values.len();
let values_iter = self.values.drain(len - function.input.len()..); let values: Vec<Value> = self.values.drain(len - function.input.len()..).collect();
self.contexts.push( self.contexts.push(
gid.program, gid.program,
self.signer, self.signer,
true, // is_async true, // is_async
); );
let param_names = function.input.iter().map(|input| input.identifier.name); let param_names = function.input.iter().map(|input| input.identifier.name);
for (name, value) in param_names.zip(values_iter) { for (name, value) in param_names.zip(values) {
self.contexts.set(name, value); self.set_variable(name, value);
} }
self.frames.last_mut().unwrap().step = 1; self.frames.last_mut().unwrap().step = 1;
self.frames.push(Frame { self.frames.push(Frame {
@ -995,7 +1005,7 @@ impl<'a> Cursor<'a> {
self.contexts.push(function_program, caller, is_async); self.contexts.push(function_program, caller, is_async);
let param_names = function.input.iter().map(|input| input.identifier.name); let param_names = function.input.iter().map(|input| input.identifier.name);
for (name, value) in param_names.zip(arguments) { for (name, value) in param_names.zip(arguments) {
self.contexts.set(name, value); self.set_variable(name, value);
} }
self.frames.push(Frame { self.frames.push(Frame {
step: 0, step: 0,

View File

@ -399,11 +399,14 @@ Once a function is running, commands include
#step to take one step towards evaluating the current expression or statement; #step to take one step towards evaluating the current expression or statement;
#over to complete evaluating the current expression or statement; #over to complete evaluating the current expression or statement;
#run to finish evaluating #run to finish evaluating
#quit to exit the interpreter. #quit to quit the interpreter.
You can set a breakpoint with You can set a breakpoint with
#break program_name line_number #break program_name line_number
When executing Aleo VM code, you can print the value of a register like this:
#print 2
You may also use one letter abbreviations for these commands, such as #i. You may also use one letter abbreviations for these commands, such as #i.
You may simply enter expressions or statements on the command line You may simply enter expressions or statements on the command line
@ -541,6 +544,7 @@ pub fn interpret(
} }
std::io::stdin().read_line(&mut buffer).expect("read_line"); std::io::stdin().read_line(&mut buffer).expect("read_line");
let action = match buffer.trim() { let action = match buffer.trim() {
"" => continue,
"#i" | "#into" => InterpreterAction::Into, "#i" | "#into" => InterpreterAction::Into,
"#s" | "#step" => InterpreterAction::Step, "#s" | "#step" => InterpreterAction::Step,
"#o" | "#over" => InterpreterAction::Over, "#o" | "#over" => InterpreterAction::Over,