Repository: PebbleTemplates/pebble
Pull request #434 (2019-03-25 03:47:07)

Embed tag for overriding blocks in included templates
This PR adds an `embed` tag, which works like [Twig's `embed` tag](https://twig.symfony.com/doc/2.x/tags/embed.html). It effectively includes a template but allows that template's blocks to be overridden in the host template within the body of the `embed` tag.

This will address a number of open issues, it's clearly a highly-desired feature: 
- #224
- #318
- #319
- #378

My initial work on this seems very promising. I am opening this PR now so the community knows it is coming soon, and to get more eyes on it and make sure it's being implemented correctly.

**To-Do:**

- [x] More tests, especially around error-handling, and verifying it doesn't cause strange behavior when used in a template that uses other block-inheritance mechanisms (`extends`, `block`, `parent()`, `block(name)`)
- [x] Documentation
- [x] Verify Pebble's `embed` behavior matches that of Twig


cjbrooks12: I've added a bunch more tests, and am comparing them to how Twig would render them, and I can't find any differences yet. Would love to get some more eyes on the PR, especially from people who have used Twig's `embed` tag in real-world usage. 

But besides that, I just need to add some documentation to the wiki and I think this should be ready-to-go.
cjbrooks12: Alright, I think this PR is ready to be merged at this point

Patch:
diff --git a/docs/pom.xml b/docs/pom.xml
index 91c21de4..70532678 100644
--- a/docs/pom.xml
+++ b/docs/pom.xml
@@ -16,7 +16,7 @@
   <url>http://pebbletemplates.io</url>
 
   <properties>
-    <orchid.version>0.12.17</orchid.version>
+    <orchid.version>0.16.4</orchid.version>
   </properties>
 
   <profiles>
@@ -33,32 +33,7 @@
             <dependencies>
               <dependency>
                 <groupId>io.github.javaeden.orchid</groupId>
-                <artifactId>OrchidCore</artifactId>
-                <version>${orchid.version}</version>
-              </dependency>
-              <dependency>
-                <groupId>io.github.javaeden.orchid</groupId>
-                <artifactId>OrchidEditorial</artifactId>
-                <version>${orchid.version}</version>
-              </dependency>
-              <dependency>
-                <groupId>io.github.javaeden.orchid</groupId>
-                <artifactId>OrchidSearch</artifactId>
-                <version>${orchid.version}</version>
-              </dependency>
-              <dependency>
-                <groupId>io.github.javaeden.orchid</groupId>
-                <artifactId>OrchidPages</artifactId>
-                <version>${orchid.version}</version>
-              </dependency>
-              <dependency>
-                <groupId>io.github.javaeden.orchid</groupId>
-                <artifactId>OrchidWiki</artifactId>
-                <version>${orchid.version}</version>
-              </dependency>
-              <dependency>
-                <groupId>io.github.javaeden.orchid</groupId>
-                <artifactId>OrchidChangelog</artifactId>
+                <artifactId>OrchidDocs</artifactId>
                 <version>${orchid.version}</version>
               </dependency>
               <dependency>
@@ -71,11 +46,6 @@
                 <artifactId>OrchidPluginDocs</artifactId>
                 <version>${orchid.version}</version>
               </dependency>
-              <dependency>
-                <groupId>io.github.javaeden.orchid</groupId>
-                <artifactId>OrchidSyntaxHighlighter</artifactId>
-                <version>${orchid.version}</version>
-              </dependency>
             </dependencies>
 
             <!-- 3. Use the 'BsDoc' theme, and view the site locally at 'http://localhost:8080' -->
@@ -102,20 +72,12 @@
   <!-- 2. Get Orchid from Jcenter, Bintray, and Jitpack -->
   <pluginRepositories>
     <pluginRepository>
-      <id>kotlinx</id>
-      <url>https://kotlin.bintray.com/kotlinx</url>
-    </pluginRepository>
-    <pluginRepository>
-      <id>orchid</id>
-      <url>https://dl.bintray.com/javaeden/Orchid</url>
+      <id>jcenter</id>
+      <url>https://jcenter.bintray.com </url>
     </pluginRepository>
     <pluginRepository>
-      <id>eden</id>
-      <url>https://dl.bintray.com/javaeden/Eden</url>
-    </pluginRepository>
-    <pluginRepository>
-      <id>jitpack</id>
-      <url>https://jitpack.io</url>
+      <id>kotlinx</id>
+      <url>https://kotlin.bintray.com/kotlinx</url>
     </pluginRepository>
   </pluginRepositories>
 </project>
\ No newline at end of file
diff --git a/docs/src/orchid/resources/config.yml b/docs/src/orchid/resources/config.yml
index dbf327b8..15f990b5 100644
--- a/docs/src/orchid/resources/config.yml
+++ b/docs/src/orchid/resources/config.yml
@@ -17,6 +17,9 @@ theme:
       itemId: 'Contributing'
     - type: 'page'
       itemId: 'Changelog'
+    - type: 'link'
+      title: 'Offline Documentation (PDF)'
+      url: '#{$0|baseUrl}/wiki/book.pdf'
     - type: 'separator'
       title: 'Wiki'
     - type: 'wiki'
@@ -53,6 +56,7 @@ allPages:
 wiki:
   defaultConfig:
     includeIndexInPageTitle: false
+    createPdf: true
 
 javadoc:
   sourceDirs:
diff --git a/docs/src/orchid/resources/data/twig-compatibility/tags.yml b/docs/src/orchid/resources/data/twig-compatibility/tags.yml
index 048db4e6..a2ad7b4d 100644
--- a/docs/src/orchid/resources/data/twig-compatibility/tags.yml
+++ b/docs/src/orchid/resources/data/twig-compatibility/tags.yml
@@ -11,7 +11,9 @@
   support: 'none'
 - name: 'embed'
   twigLink: 'https://twig.symfony.com/doc/2.x/tags/embed.html'
-  support: 'none'
+  support: 'partial'
+  page: 'embed'
+  notes: '`only` clause and `ignore missing` clause not supported'
 - name: 'extends'
   twigLink: 'https://twig.symfony.com/doc/2.x/tags/extends.html'
   support: 'full'
@@ -41,8 +43,9 @@
   page: 'import'
 - name: 'include'
   twigLink: 'https://twig.symfony.com/doc/2.x/tags/include.html'
-  support: 'full'
+  support: 'partial'
   page: 'include'
+  notes: '`only` clause and `ignore missing` clause not supported'
 - name: 'macro'
   twigLink: 'https://twig.symfony.com/doc/2.x/tags/macro.html'
   support: 'full'
diff --git a/docs/src/orchid/resources/wiki/summary.md b/docs/src/orchid/resources/wiki/summary.md
index 4bf6c9b8..8ae526c0 100644
--- a/docs/src/orchid/resources/wiki/summary.md
+++ b/docs/src/orchid/resources/wiki/summary.md
@@ -12,11 +12,12 @@
 - [autoescape](tag/autoescape.md)
 - [block](tag/block.md)
 - [cache](tag/cache.md)
+- [embed](tag/embed.md)
 - [extends](tag/extends.md)
 - [filter](tag/filter.md)
-- [from](tag/from.md)
 - [flush](tag/flush.md)
 - [for](tag/for.md)
+- [from](tag/from.md)
 - [if](tag/if.md)
 - [import](tag/import.md)
 - [include](tag/include.md)
diff --git a/docs/src/orchid/resources/wiki/tag/embed.md b/docs/src/orchid/resources/wiki/tag/embed.md
new file mode 100644
index 00000000..c48bc70b
--- /dev/null
+++ b/docs/src/orchid/resources/wiki/tag/embed.md
@@ -0,0 +1,100 @@
+---
+---
+
+# `embed`
+
+The `embed` tag allows you to insert the rendered output of another template directly into the current template, while 
+overriding some of its blocks. It effectively combines the behavior of {{anchor('include')}} with that of 
+{{anchor('extends')}} for creating reusable, yet flexible, template fragments, or for composing micro-layouts.
+
+{% verbatim %}
+
+For example, imagine building a template `card.peb` as a reusable component in your layout. All cards should have the 
+same markup, but the content can change drastically throughout your site. `card.peb` might then look like:
+
+```twig
+// card.peb
+<div class="card">
+    {% block cardContent %}
+    {% endblock %}
+</div>
+```
+
+Now, you can include that template elsewhere in your layout, and override the `cardContent` block to "inject" rich 
+content into that template at the call-side. For example, you may want to display a grid of your store's most popular 
+products as cards, with the last card linking to the full catalog. Embedding `card.peb` and overriding the `cardContent`
+block ensures that the markup for both types of cards are always the same, even though what's displayed on each card is 
+quite different.
+
+```twig
+// layout.peb
+
+{% for product in popularProducts %}
+    {% embed 'card.peb' %}
+        {% block cardContent %}
+            <h1>{{ product.name }}</h1>
+            <p>{{ product.description }}</p>
+        {% endblock %}
+    {% endembed %}
+{% endfor %}
+
+{% embed 'card.peb' %}
+    {% block cardContent %}
+        <a href="...">See all 100+ products</a>
+    {% endblock %}
+{% endembed %}
+```
+
+Embeds can be used multiple times in the same template, and may also be used in a template that itself extends another.
+Each template will then maintain its own block hierarchy. In other words, block overridden within the body of the 
+`embed` tag will not accidentally override those defined in the main template, and likewise blocks defined in the main
+template or its parent templates will not get mixed with those in the embedded template or its parent templates. 
+
+```twig
+// main.peb
+{% extends 'base.peb' %}
+
+{% block mainContent %}
+    {{ parent() }} {# renders mainContent block from base.peb #}
+    {{ block('footer') }} {# renders footer block from base.peb, the global page footer #}
+    
+    {% embed 'card.peb' %}
+        {% block mainContent %}
+            {{ parent() }} {# renders mainContent block from card.peb #}
+            {{ block('footer') }} {# renders footer block from card.peb, the card footer (not the global page footer) #}
+        {% endblock %}
+    {% endembed %}
+{% endblock %}
+```
+
+## Scope
+
+Embedded templates will have access to the same variables that the current template does.
+
+```twig
+Top Content
+{% embed "advertisement" %}{% endembed %}
+Bottom Content
+{% embed "footer" %}{% endembed %}
+```
+
+You can add additional variables to the context of the embedded template by passing a map after the `with` keyword. The embedded template will have access to the same variables that the current template does plus the additional ones defined in the map passed after the `with` keyword:
+
+```twig
+{% embed "advertisement" with {"foo":"bar"} %}
+    {% block title %}
+        Ad with title
+    {% endblock %}
+    {% block content %}
+        Ad with title
+    {% endblock %}
+{% endembed %}
+```
+
+## Dynamic embed
+The `embed` tag will accept an expression to determine the template to embed at runtime. For example:
+```twig
+{% embed admin ? 'adminFooter' : 'defaultFooter' %}
+{% endembed %}
+```
+{% endverbatim %}
diff --git a/pebble/src/main/java/com/mitchellbosecke/pebble/extension/core/CoreExtension.java b/pebble/src/main/java/com/mitchellbosecke/pebble/extension/core/CoreExtension.java
index 2e620500..a443f580 100644
--- a/pebble/src/main/java/com/mitchellbosecke/pebble/extension/core/CoreExtension.java
+++ b/pebble/src/main/java/com/mitchellbosecke/pebble/extension/core/CoreExtension.java
@@ -42,6 +42,7 @@ import com.mitchellbosecke.pebble.operator.UnaryOperator;
 import com.mitchellbosecke.pebble.operator.UnaryOperatorImpl;
 import com.mitchellbosecke.pebble.tokenParser.BlockTokenParser;
 import com.mitchellbosecke.pebble.tokenParser.CacheTokenParser;
+import com.mitchellbosecke.pebble.tokenParser.EmbedTokenParser;
 import com.mitchellbosecke.pebble.tokenParser.ExtendsTokenParser;
 import com.mitchellbosecke.pebble.tokenParser.FilterTokenParser;
 import com.mitchellbosecke.pebble.tokenParser.FlushTokenParser;
@@ -54,6 +55,7 @@ import com.mitchellbosecke.pebble.tokenParser.MacroTokenParser;
 import com.mitchellbosecke.pebble.tokenParser.ParallelTokenParser;
 import com.mitchellbosecke.pebble.tokenParser.SetTokenParser;
 import com.mitchellbosecke.pebble.tokenParser.TokenParser;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -66,6 +68,7 @@ public class CoreExtension extends AbstractExtension {
     List<TokenParser> parsers = new ArrayList<>();
     parsers.add(new BlockTokenParser());
     parsers.add(new ExtendsTokenParser());
+    parsers.add(new EmbedTokenParser());
     parsers.add(new FilterTokenParser());
     parsers.add(new FlushTokenParser());
     parsers.add(new ForTokenParser());
diff --git a/pebble/src/main/java/com/mitchellbosecke/pebble/node/EmbedNode.java b/pebble/src/main/java/com/mitchellbosecke/pebble/node/EmbedNode.java
new file mode 100644
index 00000000..70e7540a
--- /dev/null
+++ b/pebble/src/main/java/com/mitchellbosecke/pebble/node/EmbedNode.java
@@ -0,0 +1,63 @@
+/*
+ * This file is part of Pebble.
+ *
+ * Copyright (c) 2014 by Mitchell Bösecke
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+package com.mitchellbosecke.pebble.node;
+
+import com.mitchellbosecke.pebble.error.PebbleException;
+import com.mitchellbosecke.pebble.extension.NodeVisitor;
+import com.mitchellbosecke.pebble.node.expression.Expression;
+import com.mitchellbosecke.pebble.node.expression.MapExpression;
+import com.mitchellbosecke.pebble.template.EvaluationContextImpl;
+import com.mitchellbosecke.pebble.template.PebbleTemplateImpl;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class EmbedNode extends AbstractRenderableNode {
+
+  private final Expression<?> includeExpression;
+
+  private final MapExpression mapExpression;
+
+  private final List<BlockNode> nodes;
+
+  public EmbedNode(int lineNumber, Expression<?> includeExpression, MapExpression mapExpression, List<BlockNode> nodes) {
+    super(lineNumber);
+    this.includeExpression = includeExpression;
+    this.mapExpression = mapExpression;
+    this.nodes = nodes;
+  }
+
+  @Override
+  public void render(PebbleTemplateImpl self, Writer writer, EvaluationContextImpl context)
+      throws IOException {
+    String templateName = (String) this.includeExpression.evaluate(self, context);
+
+    Map<?, ?> map = Collections.emptyMap();
+    if (this.mapExpression != null) {
+      map = this.mapExpression.evaluate(self, context);
+    }
+
+    if (templateName == null) {
+      throw new PebbleException(
+          null,
+          "The template name in an embed tag evaluated to NULL. If the template name is static, make sure to wrap it in quotes.",
+          this.getLineNumber(), self.getName());
+    }
+    self.embedTemplate(getLineNumber(), writer, context, templateName, map, nodes);
+  }
+
+  @Override
+  public void accept(NodeVisitor visitor) {
+    visitor.visit(this);
+  }
+
+}
diff --git a/pebble/src/main/java/com/mitchellbosecke/pebble/template/EvaluationContextImpl.java b/pebble/src/main/java/com/mitchellbosecke/pebble/template/EvaluationContextImpl.java
index 63d439a9..88ffabbf 100644
--- a/pebble/src/main/java/com/mitchellbosecke/pebble/template/EvaluationContextImpl.java
+++ b/pebble/src/main/java/com/mitchellbosecke/pebble/template/EvaluationContextImpl.java
@@ -12,6 +12,9 @@ import com.mitchellbosecke.pebble.cache.CacheKey;
 import com.mitchellbosecke.pebble.cache.PebbleCache;
 import com.mitchellbosecke.pebble.error.PebbleException;
 import com.mitchellbosecke.pebble.extension.ExtensionRegistry;
+import com.mitchellbosecke.pebble.utils.Callbacks;
+
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -252,4 +255,39 @@ public class EvaluationContextImpl implements EvaluationContext {
   public Object getVariable(String key) {
     return this.scopeChain.get(key);
   }
+
+  private void pushScope(
+          EvaluationContextImpl newContext,
+          Map<?, ?> additionalVariables,
+          Callbacks.PebbleConsumer<EvaluationContextImpl> scopedFunction
+  ) throws IOException {
+    ScopeChain scopeChain = newContext.getScopeChain();
+
+    // push a new local scope
+    scopeChain.pushScope();
+
+    // if there are additional variables to be added to this scope, add them now
+    if(additionalVariables != null) {
+      for (Map.Entry<?, ?> entry : additionalVariables.entrySet()) {
+        scopeChain.put((String) entry.getKey(), entry.getValue());
+      }
+    }
+
+    // run the callback that needs to be scoped
+    scopedFunction.accept(newContext);
+
+    // pop the new local scope
+    scopeChain.popScope();
+  }
+
+  public void scopedShallowWithoutInheritanceChain(
+          PebbleTemplateImpl template,
+          Map<?, ?> additionalVariables,
+          Callbacks.PebbleConsumer<EvaluationContextImpl> scopedFunction) throws IOException {
+    pushScope(
+            this.shallowCopyWithoutInheritanceChain(template),
+            additionalVariables,
+            scopedFunction
+    );
+  }
 }
diff --git a/pebble/src/main/java/com/mitchellbosecke/pebble/template/PebbleTemplateImpl.java b/pebble/src/main/java/com/mitchellbosecke/pebble/template/PebbleTemplateImpl.java
index 01fac012..373d0c32 100644
--- a/pebble/src/main/java/com/mitchellbosecke/pebble/template/PebbleTemplateImpl.java
+++ b/pebble/src/main/java/com/mitchellbosecke/pebble/template/PebbleTemplateImpl.java
@@ -12,12 +12,17 @@ import com.mitchellbosecke.pebble.PebbleEngine;
 import com.mitchellbosecke.pebble.error.PebbleException;
 import com.mitchellbosecke.pebble.extension.escaper.SafeString;
 import com.mitchellbosecke.pebble.node.ArgumentsNode;
+import com.mitchellbosecke.pebble.node.BlockNode;
+import com.mitchellbosecke.pebble.node.BodyNode;
+import com.mitchellbosecke.pebble.node.RenderableNode;
 import com.mitchellbosecke.pebble.node.RootNode;
 import com.mitchellbosecke.pebble.utils.FutureWriter;
 import com.mitchellbosecke.pebble.utils.Pair;
+
 import java.io.IOException;
 import java.io.Writer;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -51,7 +56,7 @@ public class PebbleTemplateImpl implements PebbleTemplate {
   /**
    * The root node of the AST to be rendered.
    */
-  private final RootNode rootNode;
+  private final RenderableNode rootNode;
 
   /**
    * Name of template. Used to help with debugging.
@@ -65,7 +70,7 @@ public class PebbleTemplateImpl implements PebbleTemplate {
    * @param root The root not to evaluate
    * @param name The name of the template
    */
-  public PebbleTemplateImpl(PebbleEngine engine, RootNode root, String name) {
+  public PebbleTemplateImpl(PebbleEngine engine, RenderableNode root, String name) {
     this.engine = engine;
     this.rootNode = root;
     this.name = name;
@@ -256,6 +261,63 @@ public class PebbleTemplateImpl implements PebbleTemplate {
     scopeChain.popScope();
   }
 
+  /**
+   * Embed a template with {@code name} into this template and override its child blocks. This has the effect of
+   * essentially "including" a template (as with the `include` tag), but its blocks may be overridden in the calling
+   * template similar to extending a template.
+   *
+   * @param lineNo the line number of the node being evaluated
+   * @param writer the writer to which the output should be written to.
+   * @param context the context within which the template is rendered in.
+   * @param name the name of the template to include.
+   * @param additionalVariables the map with additional variables provided with the include tag to
+   * add within the embed tag.
+   * @param overriddenBlocks the blocks parsed out of the parent template that should override blocks in the embedded template
+   * @throws IOException Any error during the loading of the template
+   */
+  public void embedTemplate(
+          int lineNo,
+          Writer writer,
+          EvaluationContextImpl context,
+          String name,
+          Map<?, ?> additionalVariables,
+          List<BlockNode> overriddenBlocks
+  ) throws IOException {
+    // get the template to embed
+    String embeddedTemplateName = this.resolveRelativePath(name);
+    final PebbleTemplateImpl embeddedTemplate = (PebbleTemplateImpl) this.engine.getTemplate(embeddedTemplateName);
+
+    // push a child scope based on the current scope
+    context.scopedShallowWithoutInheritanceChain(embeddedTemplate, additionalVariables, (newContext) -> {
+
+      // create a fake root template to act as the parent of the embedded template. That root node simply renders the
+      // embedded template's own RootNode, but now we're able to isolate its template hierarchy and provide new blocks
+      // into that hierarchy
+      BodyNode embeddedTemplateBody = ((RootNode) embeddedTemplate.rootNode).getBody();
+      BodyNode bodyNode = new BodyNode(lineNo, Collections.singletonList(embeddedTemplateBody));
+      PebbleTemplateImpl fakeRootTemplate = new PebbleTemplateImpl(engine, bodyNode, embeddedTemplateName);
+
+      // push the blocks from the embedded template into the fake root, to make sure they are able to rendered if they
+      // are not overridden
+      for(Block block : embeddedTemplate.blocks.values()) {
+        fakeRootTemplate.registerBlock(block);
+      }
+
+      // push the overridden blocks into the embedded template, since they were added to the host template rather than
+      // the embdedded template during parsing. Overridden blocks must be present in the embedded template.
+      for(BlockNode blockNode : overriddenBlocks) {
+        embeddedTemplate.registerBlock(blockNode.getBlock());
+      }
+
+      // push the new fake template root into the child context so blocks are resolved properly.
+      newContext.getHierarchy().pushAncestor(fakeRootTemplate);
+
+      // evaluate the embedded template. Its blocks will now override those defined in the fake root template using the
+      // same mechanism as for overriding blocks when extending a template
+      embeddedTemplate.evaluate(writer, newContext);
+    });
+  }
+
   /**
    * Checks if a macro exists
    *
diff --git a/pebble/src/main/java/com/mitchellbosecke/pebble/tokenParser/EmbedTokenParser.java b/pebble/src/main/java/com/mitchellbosecke/pebble/tokenParser/EmbedTokenParser.java
new file mode 100644
index 00000000..222e7a7a
--- /dev/null
+++ b/pebble/src/main/java/com/mitchellbosecke/pebble/tokenParser/EmbedTokenParser.java
@@ -0,0 +1,105 @@
+/*
+ * This file is part of Pebble.
+ *
+ * Copyright (c) 2014 by Mitchell Bösecke
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+package com.mitchellbosecke.pebble.tokenParser;
+
+import com.mitchellbosecke.pebble.error.ParserException;
+import com.mitchellbosecke.pebble.lexer.Token;
+import com.mitchellbosecke.pebble.lexer.TokenStream;
+import com.mitchellbosecke.pebble.node.BlockNode;
+import com.mitchellbosecke.pebble.node.EmbedNode;
+import com.mitchellbosecke.pebble.node.RenderableNode;
+import com.mitchellbosecke.pebble.node.expression.Expression;
+import com.mitchellbosecke.pebble.node.expression.MapExpression;
+import com.mitchellbosecke.pebble.parser.Parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EmbedTokenParser implements TokenParser {
+
+  private BlockTokenParser blockTokenParser = new BlockTokenParser();
+
+  @Override
+  public RenderableNode parse(Token token, Parser parser) {
+    TokenStream stream = parser.getStream();
+    int lineNumber = token.getLineNumber();
+
+    // skip over the 'embed' token
+    stream.next();
+
+    Expression<?> embedExpression = parser.getExpressionParser().parseExpression();
+
+    Token current = stream.current();
+    MapExpression mapExpression = null;
+
+    // We check if there is an optional 'with' parameter on the embed tag.
+    if (current.getType().equals(Token.Type.NAME) && current.getValue().equals("with")) {
+
+      // Skip over 'with'
+      stream.next();
+
+      Expression<?> parsedExpression = parser.getExpressionParser().parseExpression();
+
+      if (parsedExpression instanceof MapExpression) {
+        mapExpression = (MapExpression) parsedExpression;
+      } else {
+        throw new ParserException(null,
+            String.format("Unexpected expression '%1s'.", parsedExpression
+                .getClass().getCanonicalName()), token.getLineNumber(), stream.getFilename());
+      }
+    }
+
+    stream.expect(Token.Type.EXECUTE_END);
+
+    List<BlockNode> blocks = parseBlocks(token, parser, stream);
+
+    return new EmbedNode(lineNumber, embedExpression, mapExpression, blocks);
+  }
+
+  private List<BlockNode> parseBlocks(Token token, Parser parser, TokenStream stream) {
+    List<BlockNode> blocks = new ArrayList<>();
+
+    while(true) {
+      BlockNode node = parseBlock(token, parser, stream);
+
+      if(node == null) break;
+
+      blocks.add(node);
+    }
+
+    return blocks;
+  }
+
+  private BlockNode parseBlock(Token token, Parser parser, TokenStream stream) {
+    if(stream.current().test(Token.Type.TEXT)) {
+      Token textToken = stream.expect(Token.Type.TEXT);
+      if(textToken.getValue().trim().length() > 0) {
+        throw new ParserException(null, "A template that extends another one cannot include content outside blocks. Did you forget to put the content inside a {% block %} tag?", textToken.getLineNumber(), stream.getFilename());
+      }
+    }
+
+    stream.expect(Token.Type.EXECUTE_START);
+
+    // we're finished with blocks, expect {% endembed %}
+    if(stream.current().test(Token.Type.NAME, "end" + this.getTag())) {
+      stream.expect(Token.Type.NAME, "end" + this.getTag());
+      stream.expect(Token.Type.EXECUTE_END);
+      return null;
+    }
+
+    // otherwise start parsing a block tag and let the actual BlockTokenParser do the rest (to make sure it parses the
+    // same as top-level blocks)
+    return (BlockNode) blockTokenParser.parse(token, parser);
+  }
+
+  @Override
+  public String getTag() {
+    return "embed";
+  }
+}
diff --git a/pebble/src/main/java/com/mitchellbosecke/pebble/utils/Callbacks.java b/pebble/src/main/java/com/mitchellbosecke/pebble/utils/Callbacks.java
new file mode 100644
index 00000000..f37a9169
--- /dev/null
+++ b/pebble/src/main/java/com/mitchellbosecke/pebble/utils/Callbacks.java
@@ -0,0 +1,11 @@
+package com.mitchellbosecke.pebble.utils;
+
+import java.io.IOException;
+
+public class Callbacks {
+
+    public interface PebbleConsumer<T> {
+        void accept(T t) throws IOException;
+    }
+
+}


Test patch:
diff --git a/pebble/src/test/java/com/mitchellbosecke/pebble/EmbedTagTest.java b/pebble/src/test/java/com/mitchellbosecke/pebble/EmbedTagTest.java
new file mode 100644
index 00000000..0773f5e7
--- /dev/null
+++ b/pebble/src/test/java/com/mitchellbosecke/pebble/EmbedTagTest.java
@@ -0,0 +1,152 @@
+package com.mitchellbosecke.pebble;
+
+import com.mitchellbosecke.pebble.error.PebbleException;
+import com.mitchellbosecke.pebble.loader.ClasspathLoader;
+import com.mitchellbosecke.pebble.loader.DelegatingLoader;
+import com.mitchellbosecke.pebble.loader.StringLoader;
+import com.mitchellbosecke.pebble.template.PebbleTemplate;
+import com.mitchellbosecke.pebble.utils.Pair;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+@RunWith(Parameterized.class)
+public class EmbedTagTest {
+
+    @Parameterized.Parameters(name = "{index}: embed({0})")
+    public static Iterable<? extends Object> data() {
+        return Arrays.asList(
+                "test0"
+                , "test1"
+                , "test2"
+                , "test3"
+                , "test4"
+                , "test5"
+                , "test6"
+                , "test7"
+                , "test8"
+                , "test9"
+                , "test10"
+                , "test11"
+                , "test12"
+                , "test13"
+                , "test14"
+                , "test15"
+                , "test16"
+                , "test17"
+                , "test18"
+        );
+    }
+
+    private final String input;
+    private final String templateDirectory;
+
+    private final PebbleEngine pebble;
+    private final Writer writer;
+    private final Map<String, Object> context;
+
+    public EmbedTagTest(String input) {
+        this.input = input;
+
+        StringLoader stringLoader = new StringLoader();
+        ClasspathLoader classpathLoader = new ClasspathLoader();
+        templateDirectory = "templates/embed/" + input;
+        classpathLoader.setPrefix(templateDirectory);
+
+        pebble = new PebbleEngine.Builder()
+                .loader(new DelegatingLoader(Arrays.asList(
+                        classpathLoader,
+                        stringLoader
+                )))
+                .strictVariables(false)
+                .build();
+
+        writer = new StringWriter();
+        context = new HashMap<>();
+        context.put("foo", "FOO");
+        context.put("bar", "BAR");
+    }
+
+    @Test
+    public void tests() throws PebbleException, IOException {
+        renderTemplateAndCheck();
+    }
+
+    private void renderTemplateAndCheck() throws PebbleException, IOException {
+        Pair<String, Throwable> actualTemplate = renderTemplate();
+        String expectedTemplate = getResource("./" + templateDirectory + "/template.result.txt");
+        String expectedTwigTemplate = getResource("./" + templateDirectory + "/template.result.twig.txt");
+        String expectedError = getResource("./" + templateDirectory + "/template.error.txt");
+
+        // template rendered correctly
+        if(actualTemplate.getLeft() != null) {
+            assertNotNull(actualTemplate.getLeft());
+            assertNull(actualTemplate.getRight());
+
+            assertNotNull(expectedTemplate);
+            assertNull(expectedError);
+
+            assertEquals(expectedTemplate, actualTemplate.getLeft());
+
+            // if Twig could render the same template (meaning it doesn't use Pebble-specific syntax), make sure it renders
+            // the same thing Twig does (ignoring whitespace)
+            if(expectedTwigTemplate != null) {
+                assertNotNull(expectedTwigTemplate);
+                assertEquals(expectedTwigTemplate.replaceAll("\\s", ""), actualTemplate.getLeft().replaceAll("\\s", ""));
+            }
+        }
+
+        // template did not render correctly, check the error message
+        else {
+            assertNull(actualTemplate.getLeft());
+            assertNotNull(actualTemplate.getRight());
+
+            actualTemplate.getRight().printStackTrace();
+
+            assertNull(expectedTemplate);
+            assertNotNull(expectedError);
+
+            assertEquals(expectedError, actualTemplate.getRight().getMessage());
+        }
+    }
+
+    private Pair<String, Throwable> renderTemplate() {
+        try {
+            PebbleTemplate template = pebble.getTemplate("template.peb");
+            template.evaluate(writer, context);
+            return new Pair<>(writer.toString(), null);
+        }
+        catch (Throwable t) {
+            return new Pair<>(null, t);
+        }
+    }
+
+    private String getResource(String filename) {
+        try {
+            File file = new File(
+                    this
+                            .getClass()
+                            .getClassLoader()
+                            .getResource(filename)
+                            .getFile()
+            );
+
+            return new String(Files.readAllBytes(file.toPath()));
+        }
+        catch (Exception e) {
+            return null;
+        }
+    }
+
+}
diff --git a/pebble/src/test/resources/templates/embed/notes.md b/pebble/src/test/resources/templates/embed/notes.md
new file mode 100644
index 00000000..819853c3
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/notes.md
@@ -0,0 +1,43 @@
+This is a complete example using the `embed` tag with lots of different scenarios for using the embed, and specifically
+how it interacts with the main template hierarchy. Ideally, the embed is a completely isolated template which maintains
+its own template hierarchy, and blocks are resolved entirely within its isolated hierarchy. Outside of the embed, blocks
+are resolved related to the normal hierarchy, and there is no mixing of the two. 
+
+The majority of these tests were compared to Twig for fidelity, using https://twigfiddle.com/.
+
+## Unit Tests
+
+- test2 - Bare minimum, can an `embed` include a template. Without overriding a block, an `embed` should work identical 
+    to an `include`
+- test0 - Can an `embed` override a block in an included template
+- test1 - Can an `embed` override a block in an included template, using Pebble's string block name syntax
+- test3 - Variables can be passed to the included template's scope using `with`. Overridden blocks use the scope of the 
+    included template, not the parent template, and can use Pebble's string block name syntax
+- test4 - Variables can be passed to the included template's scope using `with`. Overridden blocks use the scope of the 
+    included template, not the parent template
+- test5 - Multiple blocks can be overridden at once. When using the `block()` function, looked-up blocks will also use
+    the overridden block rather than the one in the included template
+- test6 - When using the `parent()` function, looked-up blocks will use the parent block in the included template
+
+## Integration Tests
+
+- test7 - The template being embedded may itself extend other templates. This may go many layers deep. 
+- test8 - The parent templates of the embedded template may override blocks from their parents
+- test9 - The parent templates of the embedded template may override blocks from their parents. Different templates may
+    override different blocks simultaneously
+- test10 - The embed tab can override blocks at the same time that parent templates do, and they are all resolved 
+    properly
+- test11 - `block()` and `parent()` functions can be used within the `embed` tag's overridden blocks to refer to it's 
+    parent template blocks, which are resolved with overrides properly
+- test12 - An embed tag can be used in a template that itself extends another template. The same parent template may
+    be used in either case
+- test13 - The `extends` tag and `embed` tag maintain different template hierarchies. Blocks are resolved using the 
+    proper hierarchy for the scope the `block()` and `parent()` functions are used in
+- test14 - Blocks do not bleed from the parent template hierarchy into the embed template hierarchy.
+
+## Error-checking Tests
+
+- test15 - Error thrown if content is added to the embed tag (instead of a block inside the embed)
+- test16 - Error thrown if content is added before a block in the the embed tag
+- test17 - Error thrown if content is added after a block in the the embed tag
+- test18 - Error thrown if content is added between blocks in the the embed tag
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test0/template.base.peb b/pebble/src/test/resources/templates/embed/test0/template.base.peb
new file mode 100644
index 00000000..7ea3efbb
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test0/template.base.peb
@@ -0,0 +1,5 @@
+BEFORE BASE
+{% block embedBlock1 %}
+EMBED BASE
+{% endblock %}
+AFTER BASE
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test0/template.peb b/pebble/src/test/resources/templates/embed/test0/template.peb
new file mode 100644
index 00000000..73b99a35
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test0/template.peb
@@ -0,0 +1,4 @@
+BEFORE ALL
+{% embed './template.base.peb' %}{% endembed %}
+
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test0/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test0/template.result.twig.txt
new file mode 100644
index 00000000..3be8a84d
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test0/template.result.twig.txt
@@ -0,0 +1,5 @@
+BEFORE ALL
+BEFORE BASE
+EMBED BASE
+AFTER BASE
+AFTER ALL
diff --git a/pebble/src/test/resources/templates/embed/test0/template.result.txt b/pebble/src/test/resources/templates/embed/test0/template.result.txt
new file mode 100644
index 00000000..0beafe08
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test0/template.result.txt
@@ -0,0 +1,5 @@
+BEFORE ALL
+BEFORE BASE
+EMBED BASE
+AFTER BASE
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test1/template.base.peb b/pebble/src/test/resources/templates/embed/test1/template.base.peb
new file mode 100644
index 00000000..7ea3efbb
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test1/template.base.peb
@@ -0,0 +1,5 @@
+BEFORE BASE
+{% block embedBlock1 %}
+EMBED BASE
+{% endblock %}
+AFTER BASE
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test1/template.peb b/pebble/src/test/resources/templates/embed/test1/template.peb
new file mode 100644
index 00000000..0ac1bee9
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test1/template.peb
@@ -0,0 +1,8 @@
+BEFORE ALL
+{% embed './template.base.peb' %}
+{% block embedBlock1 %}
+EMBED OVERRIDE
+{% endblock %}
+{% endembed %}
+
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test1/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test1/template.result.twig.txt
new file mode 100644
index 00000000..c7ce81aa
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test1/template.result.twig.txt
@@ -0,0 +1,5 @@
+BEFORE ALL
+BEFORE BASE
+EMBED OVERRIDE
+AFTER BASE
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test1/template.result.txt b/pebble/src/test/resources/templates/embed/test1/template.result.txt
new file mode 100644
index 00000000..c7ce81aa
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test1/template.result.txt
@@ -0,0 +1,5 @@
+BEFORE ALL
+BEFORE BASE
+EMBED OVERRIDE
+AFTER BASE
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test10/template.base.1.peb b/pebble/src/test/resources/templates/embed/test10/template.base.1.peb
new file mode 100644
index 00000000..300cca73
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test10/template.base.1.peb
@@ -0,0 +1,4 @@
+{% extends 'template.base.2.peb' %}
+{% block block1 %}
+block1 base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test10/template.base.2.peb b/pebble/src/test/resources/templates/embed/test10/template.base.2.peb
new file mode 100644
index 00000000..d38420a7
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test10/template.base.2.peb
@@ -0,0 +1,4 @@
+{% extends 'template.base.3.peb' %}
+{% block block2 %}
+block2 base 2
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test10/template.base.3.peb b/pebble/src/test/resources/templates/embed/test10/template.base.3.peb
new file mode 100644
index 00000000..82290e25
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test10/template.base.3.peb
@@ -0,0 +1,14 @@
+BEFORE BASE 3
+{% block block1 %}
+block1 base 3
+{% endblock %}
+{% block block2 %}
+block2 base 3
+{% endblock %}
+{% block block3 %}
+block3 base 3
+{% endblock %}
+{% block block4 %}
+block4 base 3
+{% endblock %}
+AFTER BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test10/template.peb b/pebble/src/test/resources/templates/embed/test10/template.peb
new file mode 100644
index 00000000..2cdc71a5
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test10/template.peb
@@ -0,0 +1,8 @@
+BEFORE ALL
+{% embed 'template.base.1.peb' %}
+{% block block4 %}
+block4 embed
+{% endblock %}
+{% endembed %}
+
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test10/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test10/template.result.twig.txt
new file mode 100644
index 00000000..b9cd969f
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test10/template.result.twig.txt
@@ -0,0 +1,8 @@
+BEFORE ALL
+BEFORE BASE 3
+block1 base 1
+block2 base 2
+block3 base 3
+block4 embed
+AFTER BASE 3
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test10/template.result.txt b/pebble/src/test/resources/templates/embed/test10/template.result.txt
new file mode 100644
index 00000000..b9cd969f
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test10/template.result.txt
@@ -0,0 +1,8 @@
+BEFORE ALL
+BEFORE BASE 3
+block1 base 1
+block2 base 2
+block3 base 3
+block4 embed
+AFTER BASE 3
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test11/template.base.1.peb b/pebble/src/test/resources/templates/embed/test11/template.base.1.peb
new file mode 100644
index 00000000..300cca73
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test11/template.base.1.peb
@@ -0,0 +1,4 @@
+{% extends 'template.base.2.peb' %}
+{% block block1 %}
+block1 base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test11/template.base.2.peb b/pebble/src/test/resources/templates/embed/test11/template.base.2.peb
new file mode 100644
index 00000000..d38420a7
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test11/template.base.2.peb
@@ -0,0 +1,4 @@
+{% extends 'template.base.3.peb' %}
+{% block block2 %}
+block2 base 2
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test11/template.base.3.peb b/pebble/src/test/resources/templates/embed/test11/template.base.3.peb
new file mode 100644
index 00000000..82290e25
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test11/template.base.3.peb
@@ -0,0 +1,14 @@
+BEFORE BASE 3
+{% block block1 %}
+block1 base 3
+{% endblock %}
+{% block block2 %}
+block2 base 3
+{% endblock %}
+{% block block3 %}
+block3 base 3
+{% endblock %}
+{% block block4 %}
+block4 base 3
+{% endblock %}
+AFTER BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test11/template.peb b/pebble/src/test/resources/templates/embed/test11/template.peb
new file mode 100644
index 00000000..bcb76450
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test11/template.peb
@@ -0,0 +1,12 @@
+BEFORE ALL
+{% embed 'template.base.1.peb' %}
+{% block block4 %}
+block4 embed
+parent={{ parent() }}
+block1={{ block('block1') }}
+block2={{ block('block2') }}
+block3={{ block('block3') }}
+{% endblock %}
+{% endembed %}
+
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test11/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test11/template.result.twig.txt
new file mode 100644
index 00000000..cbf4cf75
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test11/template.result.twig.txt
@@ -0,0 +1,16 @@
+BEFORE ALL
+BEFORE BASE 3
+block1 base 1
+block2 base 2
+block3 base 3
+block4 embed
+parent=block4 base 3
+
+block1=block1 base 1
+
+block2=block2 base 2
+
+block3=block3 base 3
+
+AFTER BASE 3
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test11/template.result.txt b/pebble/src/test/resources/templates/embed/test11/template.result.txt
new file mode 100644
index 00000000..d06483e1
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test11/template.result.txt
@@ -0,0 +1,12 @@
+BEFORE ALL
+BEFORE BASE 3
+block1 base 1
+block2 base 2
+block3 base 3
+block4 embed
+parent=block4 base 3
+block1=block1 base 1
+block2=block2 base 2
+block3=block3 base 3
+AFTER BASE 3
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test12/template.base.1.peb b/pebble/src/test/resources/templates/embed/test12/template.base.1.peb
new file mode 100644
index 00000000..300cca73
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test12/template.base.1.peb
@@ -0,0 +1,4 @@
+{% extends 'template.base.2.peb' %}
+{% block block1 %}
+block1 base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test12/template.base.2.peb b/pebble/src/test/resources/templates/embed/test12/template.base.2.peb
new file mode 100644
index 00000000..d38420a7
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test12/template.base.2.peb
@@ -0,0 +1,4 @@
+{% extends 'template.base.3.peb' %}
+{% block block2 %}
+block2 base 2
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test12/template.base.3.peb b/pebble/src/test/resources/templates/embed/test12/template.base.3.peb
new file mode 100644
index 00000000..82290e25
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test12/template.base.3.peb
@@ -0,0 +1,14 @@
+BEFORE BASE 3
+{% block block1 %}
+block1 base 3
+{% endblock %}
+{% block block2 %}
+block2 base 3
+{% endblock %}
+{% block block3 %}
+block3 base 3
+{% endblock %}
+{% block block4 %}
+block4 base 3
+{% endblock %}
+AFTER BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test12/template.peb b/pebble/src/test/resources/templates/embed/test12/template.peb
new file mode 100644
index 00000000..b801242f
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test12/template.peb
@@ -0,0 +1,15 @@
+{% extends 'template.base.1.peb' %}
+    {% block block4 %}
+    BEFORE ALL
+    {% embed 'template.base.1.peb' %}
+    {% block block4 %}
+    block4 embed
+    parent={{ parent() }}
+    block1={{ block('block1') }}
+    block2={{ block('block2') }}
+    block3={{ block('block3') }}
+    {% endblock %}
+    {% endembed %}
+
+    AFTER ALL
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test12/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test12/template.result.twig.txt
new file mode 100644
index 00000000..d2336c16
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test12/template.result.twig.txt
@@ -0,0 +1,21 @@
+BEFORE BASE 3
+block1 base 1
+block2 base 2
+block3 base 3
+    BEFORE ALL
+    BEFORE BASE 3
+block1 base 1
+block2 base 2
+block3 base 3
+    block4 embed
+    parent=block4 base 3
+
+    block1=block1 base 1
+
+    block2=block2 base 2
+
+    block3=block3 base 3
+
+    AFTER BASE 3
+    AFTER ALL
+AFTER BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test12/template.result.txt b/pebble/src/test/resources/templates/embed/test12/template.result.txt
new file mode 100644
index 00000000..e7a7184f
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test12/template.result.txt
@@ -0,0 +1,17 @@
+BEFORE BASE 3
+block1 base 1
+block2 base 2
+block3 base 3
+    BEFORE ALL
+    BEFORE BASE 3
+block1 base 1
+block2 base 2
+block3 base 3
+    block4 embed
+    parent=block4 base 3
+    block1=block1 base 1
+    block2=block2 base 2
+    block3=block3 base 3
+    AFTER BASE 3
+    AFTER ALL
+AFTER BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test13/template.embedbase.1.peb b/pebble/src/test/resources/templates/embed/test13/template.embedbase.1.peb
new file mode 100644
index 00000000..b37adf84
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test13/template.embedbase.1.peb
@@ -0,0 +1,4 @@
+{% extends 'template.embedbase.2.peb' %}
+{% block block1 %}
+block1 embed base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test13/template.embedbase.2.peb b/pebble/src/test/resources/templates/embed/test13/template.embedbase.2.peb
new file mode 100644
index 00000000..6c1cb5ec
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test13/template.embedbase.2.peb
@@ -0,0 +1,4 @@
+{% extends 'template.embedbase.3.peb' %}
+{% block block2 %}
+block2 embed base 2
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test13/template.embedbase.3.peb b/pebble/src/test/resources/templates/embed/test13/template.embedbase.3.peb
new file mode 100644
index 00000000..99c3aaa1
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test13/template.embedbase.3.peb
@@ -0,0 +1,14 @@
+BEFORE EMBED BASE 3
+{% block block1 %}
+block1 embed base 3
+{% endblock %}
+{% block block2 %}
+block2 embed base 3
+{% endblock %}
+{% block block3 %}
+block3 embed base 3
+{% endblock %}
+{% block block4 %}
+block4 embed base 3
+{% endblock %}
+AFTER EMBED BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test13/template.extendsbase.1.peb b/pebble/src/test/resources/templates/embed/test13/template.extendsbase.1.peb
new file mode 100644
index 00000000..be7cb697
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test13/template.extendsbase.1.peb
@@ -0,0 +1,4 @@
+{% extends 'template.extendsbase.2.peb' %}
+{% block block1 %}
+block1 extends base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test13/template.extendsbase.2.peb b/pebble/src/test/resources/templates/embed/test13/template.extendsbase.2.peb
new file mode 100644
index 00000000..1cae4f91
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test13/template.extendsbase.2.peb
@@ -0,0 +1,4 @@
+{% extends 'template.extendsbase.3.peb' %}
+{% block block2 %}
+block2 extends base 2
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test13/template.extendsbase.3.peb b/pebble/src/test/resources/templates/embed/test13/template.extendsbase.3.peb
new file mode 100644
index 00000000..1e85ff0f
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test13/template.extendsbase.3.peb
@@ -0,0 +1,14 @@
+BEFORE EXTENDS BASE 3
+{% block block1 %}
+block1 extends base 3
+{% endblock %}
+{% block block2 %}
+block2 extends base 3
+{% endblock %}
+{% block block3 %}
+block3 extends base 3
+{% endblock %}
+{% block block4 %}
+block4 extends base 3
+{% endblock %}
+AFTER EXTENDS BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test13/template.peb b/pebble/src/test/resources/templates/embed/test13/template.peb
new file mode 100644
index 00000000..29f18b75
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test13/template.peb
@@ -0,0 +1,21 @@
+{% extends 'template.extendsbase.1.peb' %}
+    {% block block4 %}
+    BEFORE ALL
+    {% embed 'template.embedbase.1.peb' %}
+    {% block block4 %}
+    block4 embed embed
+    parent={{ parent() }}
+    block1={{ block('block1') }}
+    block2={{ block('block2') }}
+    block3={{ block('block3') }}
+    {% endblock %}
+    {% endembed %}
+
+    AFTER ALL
+
+    block4 extends extends
+    parent={{ parent() }}
+    block1={{ block('block1') }}
+    block2={{ block('block2') }}
+    block3={{ block('block3') }}
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test13/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test13/template.result.twig.txt
new file mode 100644
index 00000000..ce48ce71
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test13/template.result.twig.txt
@@ -0,0 +1,31 @@
+BEFORE EXTENDS BASE 3
+block1 extends base 1
+block2 extends base 2
+block3 extends base 3
+    BEFORE ALL
+    BEFORE EMBED BASE 3
+block1 embed base 1
+block2 embed base 2
+block3 embed base 3
+    block4 embed embed
+    parent=block4 embed base 3
+
+    block1=block1 embed base 1
+
+    block2=block2 embed base 2
+
+    block3=block3 embed base 3
+
+    AFTER EMBED BASE 3
+    AFTER ALL
+
+    block4 extends extends
+    parent=block4 extends base 3
+
+    block1=block1 extends base 1
+
+    block2=block2 extends base 2
+
+    block3=block3 extends base 3
+
+AFTER EXTENDS BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test13/template.result.txt b/pebble/src/test/resources/templates/embed/test13/template.result.txt
new file mode 100644
index 00000000..9fa4856d
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test13/template.result.txt
@@ -0,0 +1,23 @@
+BEFORE EXTENDS BASE 3
+block1 extends base 1
+block2 extends base 2
+block3 extends base 3
+    BEFORE ALL
+    BEFORE EMBED BASE 3
+block1 embed base 1
+block2 embed base 2
+block3 embed base 3
+    block4 embed embed
+    parent=block4 embed base 3
+    block1=block1 embed base 1
+    block2=block2 embed base 2
+    block3=block3 embed base 3
+    AFTER EMBED BASE 3
+    AFTER ALL
+
+    block4 extends extends
+    parent=block4 extends base 3
+    block1=block1 extends base 1
+    block2=block2 extends base 2
+    block3=block3 extends base 3
+AFTER EXTENDS BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test14/template.embedbase.1.peb b/pebble/src/test/resources/templates/embed/test14/template.embedbase.1.peb
new file mode 100644
index 00000000..4689700e
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test14/template.embedbase.1.peb
@@ -0,0 +1,3 @@
+{% block block1 %}
+block1 embed base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test14/template.extendsbase.1.peb b/pebble/src/test/resources/templates/embed/test14/template.extendsbase.1.peb
new file mode 100644
index 00000000..be7cb697
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test14/template.extendsbase.1.peb
@@ -0,0 +1,4 @@
+{% extends 'template.extendsbase.2.peb' %}
+{% block block1 %}
+block1 extends base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test14/template.extendsbase.2.peb b/pebble/src/test/resources/templates/embed/test14/template.extendsbase.2.peb
new file mode 100644
index 00000000..1cae4f91
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test14/template.extendsbase.2.peb
@@ -0,0 +1,4 @@
+{% extends 'template.extendsbase.3.peb' %}
+{% block block2 %}
+block2 extends base 2
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test14/template.extendsbase.3.peb b/pebble/src/test/resources/templates/embed/test14/template.extendsbase.3.peb
new file mode 100644
index 00000000..1e85ff0f
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test14/template.extendsbase.3.peb
@@ -0,0 +1,14 @@
+BEFORE EXTENDS BASE 3
+{% block block1 %}
+block1 extends base 3
+{% endblock %}
+{% block block2 %}
+block2 extends base 3
+{% endblock %}
+{% block block3 %}
+block3 extends base 3
+{% endblock %}
+{% block block4 %}
+block4 extends base 3
+{% endblock %}
+AFTER EXTENDS BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test14/template.peb b/pebble/src/test/resources/templates/embed/test14/template.peb
new file mode 100644
index 00000000..29f18b75
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test14/template.peb
@@ -0,0 +1,21 @@
+{% extends 'template.extendsbase.1.peb' %}
+    {% block block4 %}
+    BEFORE ALL
+    {% embed 'template.embedbase.1.peb' %}
+    {% block block4 %}
+    block4 embed embed
+    parent={{ parent() }}
+    block1={{ block('block1') }}
+    block2={{ block('block2') }}
+    block3={{ block('block3') }}
+    {% endblock %}
+    {% endembed %}
+
+    AFTER ALL
+
+    block4 extends extends
+    parent={{ parent() }}
+    block1={{ block('block1') }}
+    block2={{ block('block2') }}
+    block3={{ block('block3') }}
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test14/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test14/template.result.twig.txt
new file mode 100644
index 00000000..38278906
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test14/template.result.twig.txt
@@ -0,0 +1,19 @@
+BEFORE EXTENDS BASE 3
+block1 extends base 1
+block2 extends base 2
+block3 extends base 3
+    BEFORE ALL
+    block1 embed base 1
+
+    AFTER ALL
+
+    block4 extends extends
+    parent=block4 extends base 3
+
+    block1=block1 extends base 1
+
+    block2=block2 extends base 2
+
+    block3=block3 extends base 3
+
+AFTER EXTENDS BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test14/template.result.txt b/pebble/src/test/resources/templates/embed/test14/template.result.txt
new file mode 100644
index 00000000..9b34a4b5
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test14/template.result.txt
@@ -0,0 +1,15 @@
+BEFORE EXTENDS BASE 3
+block1 extends base 1
+block2 extends base 2
+block3 extends base 3
+    BEFORE ALL
+    block1 embed base 1
+
+    AFTER ALL
+
+    block4 extends extends
+    parent=block4 extends base 3
+    block1=block1 extends base 1
+    block2=block2 extends base 2
+    block3=block3 extends base 3
+AFTER EXTENDS BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test15/template.base.peb b/pebble/src/test/resources/templates/embed/test15/template.base.peb
new file mode 100644
index 00000000..4689700e
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test15/template.base.peb
@@ -0,0 +1,3 @@
+{% block block1 %}
+block1 embed base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test15/template.error.txt b/pebble/src/test/resources/templates/embed/test15/template.error.txt
new file mode 100644
index 00000000..72747667
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test15/template.error.txt
@@ -0,0 +1,1 @@
+A template that extends another one cannot include content outside blocks. Did you forget to put the content inside a {% block %} tag? (template.peb:3)
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test15/template.peb b/pebble/src/test/resources/templates/embed/test15/template.peb
new file mode 100644
index 00000000..35a517ed
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test15/template.peb
@@ -0,0 +1,3 @@
+{% embed 'template.base.peb' %}
+    instead of blocks
+{% endembed %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test16/template.base.peb b/pebble/src/test/resources/templates/embed/test16/template.base.peb
new file mode 100644
index 00000000..4689700e
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test16/template.base.peb
@@ -0,0 +1,3 @@
+{% block block1 %}
+block1 embed base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test16/template.error.txt b/pebble/src/test/resources/templates/embed/test16/template.error.txt
new file mode 100644
index 00000000..72747667
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test16/template.error.txt
@@ -0,0 +1,1 @@
+A template that extends another one cannot include content outside blocks. Did you forget to put the content inside a {% block %} tag? (template.peb:3)
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test16/template.peb b/pebble/src/test/resources/templates/embed/test16/template.peb
new file mode 100644
index 00000000..37155a3a
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test16/template.peb
@@ -0,0 +1,6 @@
+{% embed 'template.base.peb' %}
+    before blocks
+    {% block block1 %}
+    overridden
+    {% endblock %}
+{% endembed %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test17/template.base.peb b/pebble/src/test/resources/templates/embed/test17/template.base.peb
new file mode 100644
index 00000000..4689700e
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test17/template.base.peb
@@ -0,0 +1,3 @@
+{% block block1 %}
+block1 embed base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test17/template.error.txt b/pebble/src/test/resources/templates/embed/test17/template.error.txt
new file mode 100644
index 00000000..55599e76
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test17/template.error.txt
@@ -0,0 +1,1 @@
+A template that extends another one cannot include content outside blocks. Did you forget to put the content inside a {% block %} tag? (template.peb:6)
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test17/template.peb b/pebble/src/test/resources/templates/embed/test17/template.peb
new file mode 100644
index 00000000..19934f57
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test17/template.peb
@@ -0,0 +1,6 @@
+{% embed 'template.base.peb' %}
+    {% block block1 %}
+    overridden
+    {% endblock %}
+    after blocks
+{% endembed %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test18/template.base.peb b/pebble/src/test/resources/templates/embed/test18/template.base.peb
new file mode 100644
index 00000000..94311d33
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test18/template.base.peb
@@ -0,0 +1,6 @@
+{% block block1 %}
+block1 embed base
+{% endblock %}
+{% block block2 %}
+block2 embed base
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test18/template.error.txt b/pebble/src/test/resources/templates/embed/test18/template.error.txt
new file mode 100644
index 00000000..55599e76
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test18/template.error.txt
@@ -0,0 +1,1 @@
+A template that extends another one cannot include content outside blocks. Did you forget to put the content inside a {% block %} tag? (template.peb:6)
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test18/template.peb b/pebble/src/test/resources/templates/embed/test18/template.peb
new file mode 100644
index 00000000..614dc956
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test18/template.peb
@@ -0,0 +1,9 @@
+{% embed 'template.base.peb' %}
+    {% block block1 %}
+    overridden
+    {% endblock %}
+    between blocks
+    {% block block2 %}
+    overridden
+    {% endblock %}
+{% endembed %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test2/template.base.peb b/pebble/src/test/resources/templates/embed/test2/template.base.peb
new file mode 100644
index 00000000..7ea3efbb
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test2/template.base.peb
@@ -0,0 +1,5 @@
+BEFORE BASE
+{% block embedBlock1 %}
+EMBED BASE
+{% endblock %}
+AFTER BASE
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test2/template.peb b/pebble/src/test/resources/templates/embed/test2/template.peb
new file mode 100644
index 00000000..70101afc
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test2/template.peb
@@ -0,0 +1,8 @@
+BEFORE ALL
+{% embed './template.base.peb' %}
+{% block 'embedBlock1' %}
+EMBED OVERRIDE
+{% endblock %}
+{% endembed %}
+
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test2/template.result.txt b/pebble/src/test/resources/templates/embed/test2/template.result.txt
new file mode 100644
index 00000000..c7ce81aa
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test2/template.result.txt
@@ -0,0 +1,5 @@
+BEFORE ALL
+BEFORE BASE
+EMBED OVERRIDE
+AFTER BASE
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test3/template.base.peb b/pebble/src/test/resources/templates/embed/test3/template.base.peb
new file mode 100644
index 00000000..4f262c22
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test3/template.base.peb
@@ -0,0 +1,5 @@
+BEFORE BASE [{{ foo }}]
+{% block embedBlock1 %}
+EMBED BASE [{{ foo }}]
+{% endblock %}
+AFTER BASE [{{ foo }}]
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test3/template.peb b/pebble/src/test/resources/templates/embed/test3/template.peb
new file mode 100644
index 00000000..fec5b479
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test3/template.peb
@@ -0,0 +1,8 @@
+BEFORE ALL [{{ foo }}]
+{% embed './template.base.peb' with {'foo': 'NEWFOO', 'bar': 'NEWBAR'} %}
+{% block 'embedBlock1' %}
+EMBED OVERRIDE [{{ bar }}]
+{% endblock %}
+{% endembed %}
+
+AFTER ALL [{{ bar }}]
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test3/template.result.txt b/pebble/src/test/resources/templates/embed/test3/template.result.txt
new file mode 100644
index 00000000..1d82376d
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test3/template.result.txt
@@ -0,0 +1,5 @@
+BEFORE ALL [FOO]
+BEFORE BASE [NEWFOO]
+EMBED OVERRIDE [NEWBAR]
+AFTER BASE [NEWFOO]
+AFTER ALL [BAR]
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test4/template.base.peb b/pebble/src/test/resources/templates/embed/test4/template.base.peb
new file mode 100644
index 00000000..4f262c22
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test4/template.base.peb
@@ -0,0 +1,5 @@
+BEFORE BASE [{{ foo }}]
+{% block embedBlock1 %}
+EMBED BASE [{{ foo }}]
+{% endblock %}
+AFTER BASE [{{ foo }}]
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test4/template.peb b/pebble/src/test/resources/templates/embed/test4/template.peb
new file mode 100644
index 00000000..9fcbc1a6
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test4/template.peb
@@ -0,0 +1,8 @@
+BEFORE ALL [{{ foo }}]
+{% embed './template.base.peb' with {'foo': 'NEWFOO', 'bar': 'NEWBAR'} %}
+{% block embedBlock1 %}
+EMBED OVERRIDE [{{ bar }}]
+{% endblock %}
+{% endembed %}
+
+AFTER ALL [{{ bar }}]
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test4/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test4/template.result.twig.txt
new file mode 100644
index 00000000..1d82376d
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test4/template.result.twig.txt
@@ -0,0 +1,5 @@
+BEFORE ALL [FOO]
+BEFORE BASE [NEWFOO]
+EMBED OVERRIDE [NEWBAR]
+AFTER BASE [NEWFOO]
+AFTER ALL [BAR]
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test4/template.result.txt b/pebble/src/test/resources/templates/embed/test4/template.result.txt
new file mode 100644
index 00000000..1d82376d
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test4/template.result.txt
@@ -0,0 +1,5 @@
+BEFORE ALL [FOO]
+BEFORE BASE [NEWFOO]
+EMBED OVERRIDE [NEWBAR]
+AFTER BASE [NEWFOO]
+AFTER ALL [BAR]
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test5/template.base.peb b/pebble/src/test/resources/templates/embed/test5/template.base.peb
new file mode 100644
index 00000000..6285657a
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test5/template.base.peb
@@ -0,0 +1,8 @@
+BEFORE BASE [{{ foo }}]
+{% block embedBlock1 %}
+EMBED BASE [{{ foo }}]
+{% endblock %}
+{% block embedBlock2 %}
+EMBED BASE [{{ foo }}]
+{% endblock %}
+AFTER BASE [{{ foo }}]
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test5/template.peb b/pebble/src/test/resources/templates/embed/test5/template.peb
new file mode 100644
index 00000000..934ace0d
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test5/template.peb
@@ -0,0 +1,11 @@
+BEFORE ALL
+{% embed './template.base.peb' with {'foo': 'NEWFOO', 'bar': 'NEWBAR'} %}
+{% block embedBlock1 %}
+EMBED OVERRIDE [{{ bar }}]
+{% endblock %}
+{% block embedBlock2 %}
+{{ block('embedBlock1') }}
+{% endblock %}
+{% endembed %}
+
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test5/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test5/template.result.twig.txt
new file mode 100644
index 00000000..9575170e
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test5/template.result.twig.txt
@@ -0,0 +1,7 @@
+BEFORE ALL
+BEFORE BASE [NEWFOO]
+EMBED OVERRIDE [NEWBAR]
+EMBED OVERRIDE [NEWBAR]
+
+AFTER BASE [NEWFOO]
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test5/template.result.txt b/pebble/src/test/resources/templates/embed/test5/template.result.txt
new file mode 100644
index 00000000..b5b39c79
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test5/template.result.txt
@@ -0,0 +1,6 @@
+BEFORE ALL
+BEFORE BASE [NEWFOO]
+EMBED OVERRIDE [NEWBAR]
+EMBED OVERRIDE [NEWBAR]
+AFTER BASE [NEWFOO]
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test6/template.base.peb b/pebble/src/test/resources/templates/embed/test6/template.base.peb
new file mode 100644
index 00000000..4f262c22
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test6/template.base.peb
@@ -0,0 +1,5 @@
+BEFORE BASE [{{ foo }}]
+{% block embedBlock1 %}
+EMBED BASE [{{ foo }}]
+{% endblock %}
+AFTER BASE [{{ foo }}]
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test6/template.peb b/pebble/src/test/resources/templates/embed/test6/template.peb
new file mode 100644
index 00000000..0762d59a
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test6/template.peb
@@ -0,0 +1,11 @@
+BEFORE ALL
+{% embed './template.base.peb' with {'foo': 'NEWFOO', 'bar': 'NEWBAR'} %}
+{% block embedBlock1 %}
+EMBED OVERRIDE [{{ bar }}]
+(
+parent={{ parent() }}
+)
+{% endblock %}
+{% endembed %}
+
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test6/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test6/template.result.twig.txt
new file mode 100644
index 00000000..e1784863
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test6/template.result.twig.txt
@@ -0,0 +1,8 @@
+BEFORE ALL
+BEFORE BASE [NEWFOO]
+EMBED OVERRIDE [NEWBAR]
+(
+parent=EMBED BASE [NEWFOO]
+)
+AFTER BASE [NEWFOO]
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test6/template.result.txt b/pebble/src/test/resources/templates/embed/test6/template.result.txt
new file mode 100644
index 00000000..e1784863
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test6/template.result.txt
@@ -0,0 +1,8 @@
+BEFORE ALL
+BEFORE BASE [NEWFOO]
+EMBED OVERRIDE [NEWBAR]
+(
+parent=EMBED BASE [NEWFOO]
+)
+AFTER BASE [NEWFOO]
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test7/template.base.1.peb b/pebble/src/test/resources/templates/embed/test7/template.base.1.peb
new file mode 100644
index 00000000..aee434e9
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test7/template.base.1.peb
@@ -0,0 +1,1 @@
+{% extends 'template.base.2.peb' %}
diff --git a/pebble/src/test/resources/templates/embed/test7/template.base.2.peb b/pebble/src/test/resources/templates/embed/test7/template.base.2.peb
new file mode 100644
index 00000000..e49d2296
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test7/template.base.2.peb
@@ -0,0 +1,1 @@
+{% extends 'template.base.3.peb' %}
diff --git a/pebble/src/test/resources/templates/embed/test7/template.base.3.peb b/pebble/src/test/resources/templates/embed/test7/template.base.3.peb
new file mode 100644
index 00000000..82290e25
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test7/template.base.3.peb
@@ -0,0 +1,14 @@
+BEFORE BASE 3
+{% block block1 %}
+block1 base 3
+{% endblock %}
+{% block block2 %}
+block2 base 3
+{% endblock %}
+{% block block3 %}
+block3 base 3
+{% endblock %}
+{% block block4 %}
+block4 base 3
+{% endblock %}
+AFTER BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test7/template.peb b/pebble/src/test/resources/templates/embed/test7/template.peb
new file mode 100644
index 00000000..be6f4849
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test7/template.peb
@@ -0,0 +1,5 @@
+BEFORE ALL
+{% embed 'template.base.1.peb' %}
+{% endembed %}
+
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test7/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test7/template.result.twig.txt
new file mode 100644
index 00000000..21a1d818
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test7/template.result.twig.txt
@@ -0,0 +1,8 @@
+BEFORE ALL
+BEFORE BASE 3
+block1 base 3
+block2 base 3
+block3 base 3
+block4 base 3
+AFTER BASE 3
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test7/template.result.txt b/pebble/src/test/resources/templates/embed/test7/template.result.txt
new file mode 100644
index 00000000..21a1d818
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test7/template.result.txt
@@ -0,0 +1,8 @@
+BEFORE ALL
+BEFORE BASE 3
+block1 base 3
+block2 base 3
+block3 base 3
+block4 base 3
+AFTER BASE 3
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test8/template.base.1.peb b/pebble/src/test/resources/templates/embed/test8/template.base.1.peb
new file mode 100644
index 00000000..aee434e9
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test8/template.base.1.peb
@@ -0,0 +1,1 @@
+{% extends 'template.base.2.peb' %}
diff --git a/pebble/src/test/resources/templates/embed/test8/template.base.2.peb b/pebble/src/test/resources/templates/embed/test8/template.base.2.peb
new file mode 100644
index 00000000..d38420a7
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test8/template.base.2.peb
@@ -0,0 +1,4 @@
+{% extends 'template.base.3.peb' %}
+{% block block2 %}
+block2 base 2
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test8/template.base.3.peb b/pebble/src/test/resources/templates/embed/test8/template.base.3.peb
new file mode 100644
index 00000000..82290e25
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test8/template.base.3.peb
@@ -0,0 +1,14 @@
+BEFORE BASE 3
+{% block block1 %}
+block1 base 3
+{% endblock %}
+{% block block2 %}
+block2 base 3
+{% endblock %}
+{% block block3 %}
+block3 base 3
+{% endblock %}
+{% block block4 %}
+block4 base 3
+{% endblock %}
+AFTER BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test8/template.peb b/pebble/src/test/resources/templates/embed/test8/template.peb
new file mode 100644
index 00000000..be6f4849
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test8/template.peb
@@ -0,0 +1,5 @@
+BEFORE ALL
+{% embed 'template.base.1.peb' %}
+{% endembed %}
+
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test8/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test8/template.result.twig.txt
new file mode 100644
index 00000000..55fafd5b
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test8/template.result.twig.txt
@@ -0,0 +1,8 @@
+BEFORE ALL
+BEFORE BASE 3
+block1 base 3
+block2 base 2
+block3 base 3
+block4 base 3
+AFTER BASE 3
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test8/template.result.txt b/pebble/src/test/resources/templates/embed/test8/template.result.txt
new file mode 100644
index 00000000..55fafd5b
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test8/template.result.txt
@@ -0,0 +1,8 @@
+BEFORE ALL
+BEFORE BASE 3
+block1 base 3
+block2 base 2
+block3 base 3
+block4 base 3
+AFTER BASE 3
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test9/template.base.1.peb b/pebble/src/test/resources/templates/embed/test9/template.base.1.peb
new file mode 100644
index 00000000..300cca73
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test9/template.base.1.peb
@@ -0,0 +1,4 @@
+{% extends 'template.base.2.peb' %}
+{% block block1 %}
+block1 base 1
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test9/template.base.2.peb b/pebble/src/test/resources/templates/embed/test9/template.base.2.peb
new file mode 100644
index 00000000..d38420a7
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test9/template.base.2.peb
@@ -0,0 +1,4 @@
+{% extends 'template.base.3.peb' %}
+{% block block2 %}
+block2 base 2
+{% endblock %}
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test9/template.base.3.peb b/pebble/src/test/resources/templates/embed/test9/template.base.3.peb
new file mode 100644
index 00000000..82290e25
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test9/template.base.3.peb
@@ -0,0 +1,14 @@
+BEFORE BASE 3
+{% block block1 %}
+block1 base 3
+{% endblock %}
+{% block block2 %}
+block2 base 3
+{% endblock %}
+{% block block3 %}
+block3 base 3
+{% endblock %}
+{% block block4 %}
+block4 base 3
+{% endblock %}
+AFTER BASE 3
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test9/template.peb b/pebble/src/test/resources/templates/embed/test9/template.peb
new file mode 100644
index 00000000..be6f4849
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test9/template.peb
@@ -0,0 +1,5 @@
+BEFORE ALL
+{% embed 'template.base.1.peb' %}
+{% endembed %}
+
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test9/template.result.twig.txt b/pebble/src/test/resources/templates/embed/test9/template.result.twig.txt
new file mode 100644
index 00000000..e3195b15
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test9/template.result.twig.txt
@@ -0,0 +1,8 @@
+BEFORE ALL
+BEFORE BASE 3
+block1 base 1
+block2 base 2
+block3 base 3
+block4 base 3
+AFTER BASE 3
+AFTER ALL
\ No newline at end of file
diff --git a/pebble/src/test/resources/templates/embed/test9/template.result.txt b/pebble/src/test/resources/templates/embed/test9/template.result.txt
new file mode 100644
index 00000000..e3195b15
--- /dev/null
+++ b/pebble/src/test/resources/templates/embed/test9/template.result.txt
@@ -0,0 +1,8 @@
+BEFORE ALL
+BEFORE BASE 3
+block1 base 1
+block2 base 2
+block3 base 3
+block4 base 3
+AFTER BASE 3
+AFTER ALL
\ No newline at end of file