Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose the name of the currently called item #150

Merged
merged 3 commits into from Nov 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 19 additions & 7 deletions minijinja/src/vm/mod.rs
Expand Up @@ -83,8 +83,9 @@ impl<'env> Vm<'env> {
env: self.env,
ctx: Context::new(Frame::new(root)),
current_block: None,
instructions,
current_call: None,
auto_escape,
instructions,
blocks: prepare_blocks(blocks),
loaded_templates: BTreeSet::new(),
#[cfg(feature = "macros")]
Expand Down Expand Up @@ -115,8 +116,9 @@ impl<'env> Vm<'env> {
env: self.env,
ctx,
current_block: None,
instructions,
current_call: None,
auto_escape: state.auto_escape(),
instructions,
blocks: BTreeMap::default(),
loaded_templates: BTreeSet::new(),
#[cfg(feature = "macros")]
Expand Down Expand Up @@ -421,6 +423,7 @@ impl<'env> Vm<'env> {
stack.push(out.end_capture(state.auto_escape));
}
Instruction::ApplyFilter(name, arg_count, local_id) => {
state.current_call = Some(name);
let filter =
ctx_ok!(get_or_lookup_local(&mut loaded_filters, *local_id, || {
state.env.get_filter(name)
Expand All @@ -435,8 +438,10 @@ impl<'env> Vm<'env> {
a = ctx_ok!(filter.apply_to(state, args));
stack.drop_top(*arg_count);
stack.push(a);
state.current_call = Some(name);
}
Instruction::PerformTest(name, arg_count, local_id) => {
state.current_call = Some(name);
let test = ctx_ok!(get_or_lookup_local(&mut loaded_tests, *local_id, || {
state.env.get_test(name)
})
Expand All @@ -447,10 +452,13 @@ impl<'env> Vm<'env> {
let rv = ctx_ok!(test.perform(state, args));
stack.drop_top(*arg_count);
stack.push(Value::from(rv));
state.current_call = None;
}
Instruction::CallFunction(function_name, arg_count) => {
Instruction::CallFunction(name, arg_count) => {
state.current_call = Some(name);

// super is a special function reserved for super-ing into blocks.
if *function_name == "super" {
if *name == "super" {
if *arg_count != 0 {
bail!(Error::new(
ErrorKind::InvalidOperation,
Expand All @@ -459,7 +467,7 @@ impl<'env> Vm<'env> {
}
stack.push(ctx_ok!(self.perform_super(state, out, true)));
// loop is a special name which when called recurses the current loop.
} else if *function_name == "loop" {
} else if *name == "loop" {
if *arg_count != 1 {
bail!(Error::new(
ErrorKind::InvalidOperation,
Expand All @@ -468,23 +476,27 @@ impl<'env> Vm<'env> {
}
// leave the one argument on the stack for the recursion
recurse_loop!(true);
} else if let Some(func) = state.ctx.load(self.env, function_name) {
} else if let Some(func) = state.ctx.load(self.env, name) {
let args = stack.slice_top(*arg_count);
a = ctx_ok!(func.call(state, args));
stack.drop_top(*arg_count);
stack.push(a);
} else {
bail!(Error::new(
ErrorKind::UnknownFunction,
format!("{} is unknown", function_name),
format!("{} is unknown", name),
));
}

state.current_call = None;
}
Instruction::CallMethod(name, arg_count) => {
state.current_call = Some(name);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would need to do something like let old_call = mem::replace(&mut state.current_call, Some(name)); since you can have things like {{ foo.bar(blub.blah()) }}.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should just work as-is since foo.bar(blub.blah()) is really:

call blub.blah
pop
call foo.bar

I'll write some tests to confirm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed (no bug) via tests. This change also means you can get rid of the name argument in Object::call_method() if the unwrap() (which should always succeed) is acceptable.

let args = stack.slice_top(*arg_count);
a = ctx_ok!(args[0].call_method(state, name, &args[1..]));
stack.drop_top(*arg_count);
stack.push(a);
state.current_call = None;
}
Instruction::CallObject(arg_count) => {
let args = stack.slice_top(*arg_count);
Expand Down
9 changes: 9 additions & 0 deletions minijinja/src/vm/state.rs
Expand Up @@ -24,6 +24,7 @@ pub struct State<'vm, 'env> {
pub(crate) env: &'env Environment<'env>,
pub(crate) ctx: Context<'env>,
pub(crate) current_block: Option<&'env str>,
pub(crate) current_call: Option<&'env str>,
pub(crate) auto_escape: AutoEscape,
pub(crate) instructions: &'vm Instructions<'env>,
pub(crate) blocks: BTreeMap<&'env str, BlockStack<'vm, 'env>>,
Expand All @@ -38,6 +39,7 @@ impl<'vm, 'env> fmt::Debug for State<'vm, 'env> {
let mut ds = f.debug_struct("State");
ds.field("name", &self.instructions.name());
ds.field("current_block", &self.current_block);
ds.field("current_call", &self.current_call);
ds.field("auto_escape", &self.auto_escape);
ds.field("ctx", &self.ctx);
ds.field("env", &self.env);
Expand Down Expand Up @@ -66,6 +68,12 @@ impl<'vm, 'env> State<'vm, 'env> {
self.current_block
}

/// Returns the name of the item (filter, function, test, method) currently
/// being called.
pub fn current_call(&self) -> Option<&str> {
self.current_call
}

/// Looks up a variable by name in the context.
pub fn lookup(&self, name: &str) -> Option<Value> {
self.ctx.load(self.env(), name)
Expand All @@ -82,6 +90,7 @@ impl<'vm, 'env> State<'vm, 'env> {
blocks: BTreeMap::new(),
loaded_templates: BTreeSet::new(),
macros: Default::default(),
current_call: None,
})
}

Expand Down
3 changes: 3 additions & 0 deletions minijinja/tests/snapshots/test_templates__vm@debug.txt.snap
Expand Up @@ -8,6 +8,9 @@ input_file: minijinja/tests/inputs/debug.txt
State {
name: "debug.txt",
current_block: None,
current_call: Some(
"debug",
),
auto_escape: None,
ctx: {
"x": 0,
Expand Down