Repository: Keats/tera (rust)

Issue:
set_global broken in macros
Hi, I believe the `set_global` function doesn't work as it should in macros. It does define the variable in the parent's context, but it is not accessible from the macro context. The most simple way to reproduce is:
```
{% macro test_global() %}
    {% set_global output = "Gutenberg!" %}
    {{ output }}
{% endmacro test_global %}
```

Produces:
```
Error: Failed to render page '/home/user/Site/content/_common/footer.md'
Reason: Failed to render 'mytheme/templates/page.html': error while rendering macro `macros::test_global` (error happened in a parent template)
Reason: Variable `output` not found in context while rendering 'mytheme/templates/widgets/macros.html'
```

The value is accessible from `page.html` and `index.html` though (the former extends the latter).

PS: Here the `error happened in a parent template` is inaccurate. We're not exactly extending the template that failed, but rather importing it so the wording probably should be different :)

EDIT: I'm running gutenberg 0.4.2 and tera 0.11.5

Pull request:
Fix set_global context in macros and for loops
This should fix #336. At least according to my understanding of what a global context should be :D 
Please tell me whether my interpretation is correct. If so, I'll add a commit to make docs more clear about this before merging :)

Patch:
diff --git a/src/renderer/call_stack.rs b/src/renderer/call_stack.rs
index 4de5360..e6dfe51 100644
--- a/src/renderer/call_stack.rs
+++ b/src/renderer/call_stack.rs
@@ -68,9 +68,21 @@ impl<'a> CallStack<'a> {
         self.stack.push(StackFrame::new_include(name, tpl));
     }
 
-    /// Returns mutable reference to current `StackFrame`
-    pub fn origin_frame_mut(self: &mut Self) -> &mut StackFrame<'a> {
-        self.stack.first_mut().expect("Origin frame missing")
+    /// Returns mutable reference to global `StackFrame`
+    /// i.e gets first stack outside current for loops
+    pub fn global_frame_mut(self: &mut Self) -> &mut StackFrame<'a> {
+        if self.current_frame().kind == FrameType::ForLoop {
+            for stack_frame in self.stack.iter_mut().rev(){
+                // walk up the parent stacks until we meet the current template
+                if stack_frame.kind != FrameType::ForLoop {
+                    return stack_frame;
+                }
+            }
+            unreachable!("Global frame not found when trying to break out of for loop");
+        } else {
+            // Macro, Origin, or Include
+            return self.current_frame_mut();
+        }
     }
 
     /// Returns mutable reference to current `StackFrame`
@@ -118,7 +130,7 @@ impl<'a> CallStack<'a> {
     /// Add an assignment value (via {% set ... %} and {% set_global ... %} )
     pub fn add_assignment(&mut self, key: &'a str, global: bool, value: Val<'a>) {
         if global {
-            self.origin_frame_mut().insert(key, value);
+            self.global_frame_mut().insert(key, value);
         } else {
             self.current_frame_mut().insert(key, value);
         }


Test patch:
diff --git a/src/renderer/tests/macros.rs b/src/renderer/tests/macros.rs
index 1c349a2..2eaee8d 100644
--- a/src/renderer/tests/macros.rs
+++ b/src/renderer/tests/macros.rs
@@ -307,3 +307,40 @@ fn macro_can_load_macro_from_macro_files() {
     //println!("{:#?}", result);
     assert_eq!(result.unwrap(), "Emma was an amazing person! Don't you think?".to_string());
 }
+
+#[test]
+fn macro_can_access_global_context() {
+    let mut tera = Tera::default();
+    tera.add_raw_templates(vec![
+        ("parent", r#"{% import "macros" as macros %}{{ macros::test_global() }}"#),
+        ("macros", r#"{% macro test_global() %}{% set_global value1 = "42" %}{% for i in range(end=1) %}{% set_global value2 = " is the truth." %}{% endfor %}{{ value1 }}{% endmacro test_global %}"#)
+    ]).unwrap();
+
+    let result = tera.render("parent", &Context::new());
+    assert_eq!(result.unwrap(), "42".to_string());
+}
+
+#[test]
+fn template_cant_access_macros_context() {
+    let mut tera = Tera::default();
+    tera.add_raw_templates(vec![
+        ("parent", r#"{% import "macros" as macros %}{{ macros::empty() }}{{ quote | default(value="I'd rather have roses on my table than diamonds on my neck.") }}"#),
+        ("macros", r#"{% macro empty() %}{% set_global quote = "This should not reachable from the calling template!" %}{% endmacro empty %}"#)
+    ]).unwrap();
+
+    let result = tera.render("parent", &Context::new());
+    assert_eq!(result.unwrap(), "I'd rather have roses on my table than diamonds on my neck.");
+}
+
+#[test]
+fn parent_macro_cant_access_child_macro_context() {
+    let mut tera = Tera::default();
+    tera.add_raw_templates(vec![
+        ("parent", "{% import \"macros\" as macros %}{{ macros::test_global() }}"),
+        ("macros", r#"{% import "moremacros" as moremacros %}{% macro test_global() %}{% set_global value1 = "ACAB" %}{{ moremacros::another_one() }}{{ value1 }}-{{ value2 | default(value="ACAB") }}{% endmacro test_global %}"#),
+        ("moremacros", r#"{% macro another_one() %}{% set_global value2 = "1312" %}{% endmacro another_one %}"#)
+    ]).unwrap();
+
+    let result = tera.render("parent", &Context::new());
+    assert_eq!(result.unwrap(), "ACAB-ACAB".to_string());
+}