Merge branch 'explain-assert' into master
authorAlexis Laferrière <alexis.laf@xymus.net>
Fri, 16 Feb 2018 16:26:25 +0000 (11:26 -0500)
committerAlexis Laferrière <alexis.laf@xymus.net>
Fri, 16 Feb 2018 16:26:25 +0000 (11:26 -0500)
1  2 
lib/gamnit/dynamic_resolution.nit
lib/gamnit/flat/flat_core.nit
src/compiler/abstract_compiler.nit
src/interpreter/naive_interpreter.nit

@@@ -42,7 -42,7 +42,7 @@@ redef class Ap
        #
        # This value is applied to both X and Y, so it has an exponential effect on
        # the number of pixels.
 -      var dynamic_resolution_ratio = 1.0
 +      var dynamic_resolution_ratio = 1.0 is writable
  
        # Minimum dynamic screen resolution
        var min_dynamic_resolution_ratio = 0.0125 is writable
  
        private var perf_clock_dynamic_resolution = new Clock is lazy
  
 -      redef fun on_create
 +      # Real screen framebuffer
 +      private var screen_framebuffer_cache: Int = -1
 +
 +      # Real screen framebuffer name
 +      fun screen_framebuffer: Int
 +      do
 +              var cache = screen_framebuffer_cache
 +              if cache != -1 then return cache
 +
 +              cache = glGetIntegerv(gl_FRAMEBUFFER_BINDING, 0)
 +              self.screen_framebuffer_cache = cache
 +              return cache
 +      end
 +
 +      redef fun create_gamnit
        do
                super
  
                program.compile_and_link
                var error = program.error
                assert error == null else print_error error
 +
 +              dynamic_context_cache = null
        end
  
        redef fun on_resize(display)
        do
 -              dynamic_context.resize(display, max_dynamic_resolution_ratio)
 +              if dynamic_context_cache != null then dynamic_context.resize(display, max_dynamic_resolution_ratio)
                super
        end
  
  
                if dynamic_resolution_ratio == 1.0 then
                        # Draw directly to the screen framebuffer
 -                      glBindFramebuffer(gl_FRAMEBUFFER, dynamic_context.screen_framebuffer)
 +                      bind_screen_framebuffer screen_framebuffer
                        glViewport(0, 0, display.width, display.height)
                        glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
  
-                       var gl_error = glGetError
-                       assert gl_error == gl_NO_ERROR else print_error gl_error
+                       assert glGetError == gl_NO_ERROR
                        return
                end
  
  
                glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
  
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
        end
  
        # Draw the dynamic screen to the real screen if `dynamic_resolution_ratio != 1.0`
                var ratio = dynamic_resolution_ratio
                ratio = ratio.clamp(min_dynamic_resolution_ratio, max_dynamic_resolution_ratio)
  
 -              glBindFramebuffer(gl_FRAMEBUFFER, dynamic_context.screen_framebuffer)
 +              bind_screen_framebuffer screen_framebuffer
                glBindBuffer(gl_ARRAY_BUFFER, dynamic_context.buffer_array)
                glViewport(0, 0, display.width, display.height)
                glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
                n_floats = 2
                glEnableVertexAttribArray dynres_program.tex_coord.location
                glVertexAttribPointeri(dynres_program.tex_coord.location, n_floats, gl_FLOAT, false, 0, offset)
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # Draw
                glDrawArrays(gl_TRIANGLE_STRIP, 0, 4)
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # Take down
                glBindBuffer(gl_ARRAY_BUFFER, 0)
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                sys.perfs["gamnit flat dyn res"].add app.perf_clock_dynamic_resolution.lapse
        end
  
        # Framebuffer and texture for dynamic resolution intermediate drawing
 -      private var dynamic_context: DynamicContext = create_dynamic_context is lazy
 +      private fun dynamic_context: DynamicContext
 +      do
 +              var cache = dynamic_context_cache
 +              if cache != null then return cache
 +
 +              cache = create_dynamic_context
 +              dynamic_context_cache = cache
 +              return cache
 +      end
 +
 +      private var dynamic_context_cache: nullable DynamicContext = null
  
        private fun create_dynamic_context: DynamicContext
        do
@@@ -192,6 -161,9 +187,6 @@@ en
  # Handles to reused GL buffers and texture
  private class DynamicContext
  
 -      # Real screen framebuffer
 -      var screen_framebuffer: Int = -1
 -
        # Dynamic screen framebuffer
        var dynamic_framebuffer: Int = -1
  
        do
                # TODO enable antialiasing.
  
 -              # Set aside the real screen framebuffer name
 -              var screen_framebuffer = glGetIntegerv(gl_FRAMEBUFFER_BINDING, 0)
 -              self.screen_framebuffer = screen_framebuffer
 -
                # Framebuffer
                var framebuffer = glGenFramebuffers(1).first
                glBindFramebuffer(gl_FRAMEBUFFER, framebuffer)
                assert glIsFramebuffer(framebuffer)
                self.dynamic_framebuffer = framebuffer
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # Depth & texture/color
                var depthbuffer = glGenRenderbuffers(1).first
                self.depth_renderbuffer = depthbuffer
                var texture = glGenTextures(1).first
                self.texture = texture
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                resize(display, max_dynamic_resolution_ratio)
                assert glCheckFramebufferStatus(gl_FRAMEBUFFER) == gl_FRAMEBUFFER_COMPLETE
                buffer_array = glGenBuffers(1).first
                glBindBuffer(gl_ARRAY_BUFFER, buffer_array)
                assert glIsBuffer(buffer_array)
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                ## coord
                var data = new Array[Float]
  
                glBindBuffer(gl_ARRAY_BUFFER, 0)
  
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
        end
  
        # Init size or resize `depth_renderbuffer` and `texture`
                assert glIsRenderbuffer(depthbuffer)
                glRenderbufferStorage(gl_RENDERBUFFER, gl_DEPTH_COMPONENT16, width, height)
                glFramebufferRenderbuffer(gl_FRAMEBUFFER, gl_DEPTH_ATTACHMENT, gl_RENDERBUFFER, depthbuffer)
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # Texture
                glBindTexture(gl_TEXTURE_2D, texture)
                             0, gl_RGB, gl_UNSIGNED_BYTE, new Pointer.nul)
                glFramebufferTexture2D(gl_FRAMEBUFFER, gl_COLOR_ATTACHMENT0, gl_TEXTURE_2D, texture, 0)
  
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # Take down
                glBindRenderbuffer(gl_RENDERBUFFER, 0)
                glBindFramebuffer(gl_FRAMEBUFFER, 0)
  
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
        end
  
        var destroyed = false
  
                # Free the buffer
                glDeleteBuffers([buffer_array])
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
                buffer_array = -1
  
                # Free the dynamic framebuffer and its attachments
@@@ -80,27 -80,27 +80,27 @@@ class Sprit
        var texture: Texture is writable(texture_direct=)
  
        # Texture drawn to screen
 -      fun texture=(value: Texture)
 +      fun texture=(texture: Texture)
        do
 -              if isset _texture and value != texture then
 +              if isset _texture and texture != self.texture then
                        needs_update
 -                      if value.root != texture.root then needs_remap
 +                      if texture.root != self.texture.root then needs_remap
                end
 -              texture_direct = value
 +              texture_direct = texture
        end
  
        # Center position of this sprite in world coordinates
        var center: Point3d[Float] is writable(center_direct=), noautoinit
  
        # Center position of this sprite in world coordinates
 -      fun center=(value: Point3d[Float]) is autoinit do
 -              if isset _center and value != center then
 +      fun center=(center: Point3d[Float]) is autoinit do
 +              if isset _center and center != self.center then
                        needs_update
 -                      center.sprites_remove self
 +                      self.center.sprites_remove self
                end
  
 -              value.sprites_add self
 -              center_direct = value
 +              center.sprites_add self
 +              center_direct = center
        end
  
        # Last animation set with `animate`
@@@ -399,9 -399,6 +399,9 @@@ redef class Ap
                var display = display
                assert display != null
                glClear gl_COLOR_BUFFER_BIT
 +
 +              ui_camera.reset_height 1080.0
 +              glViewport(0, 0, display.width, display.height)
                frame_core_ui_sprites display
                display.flip
  
        # Second performance clock for smaller operations
        private var perf_clock_sprites = new Clock is lazy
  
 -      redef fun on_create
 +      redef fun create_gamnit
        do
                super
 +              create_flat
 +      end
  
 +      # Prepare the flat framework services
 +      fun create_flat
 +      do
                var display = display
                assert display != null
  
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # Prepare program
                var program = simple_2d_program
                glViewport(0, 0, display.width, display.height)
                glClearColor(0.0, 0.0, 0.0, 1.0)
  
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # Prepare to draw
                for tex in all_root_textures do
                        glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR)
                        glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR)
                end
 +
 +              sprites.reset
 +              ui_sprites.reset
        end
  
        redef fun on_stop
        do
 -              # Clean up
 -              simple_2d_program.delete
 +              super
  
                # Close gamnit
                var display = display
                for sprite in ui_sprites do sprite.needs_update
        end
  
 +      redef fun on_resume
 +      do
 +              clock.lapse
 +              super
 +      end
 +
        redef fun frame_core(display)
        do
                # Check errors
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # Update game logic and set sprites
                perf_clock_main.lapse
                display.flip
  
                # Check errors
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
        end
  
        private var frame_dt = 0.0
  
                # draw
                sprite_set.draw
 +
 +              assert glGetError == gl_NO_ERROR
        end
  
        # Draw world sprites from `sprites`
@@@ -981,7 -959,7 +977,7 @@@ class SpriteSe
                for sprite in sprites_to_remap do
  
                        # Skip if it was removed from this set after being modified
 -                      if sprite.context != self then continue
 +                      if sprite.sprite_set != self then continue
  
                        unmap_sprite sprite
                        map_sprite sprite
                for c in contexts_items do c.destroy
                contexts_map.clear
                contexts_items.clear
 +              sprites_to_remap.clear
 +      end
 +
 +      private fun reset
 +      do
 +              for sprite in self do
 +                      sprite.context = null
 +              end
 +
 +              for c in contexts_items do c.destroy
 +              contexts_map.clear
 +              contexts_items.clear
 +              sprites_to_remap.clear
 +
 +              for sprite in self do
 +                      map_sprite sprite
 +              end
        end
  end
  
@@@ -1128,16 -1089,14 +1124,14 @@@ private class SpriteContex
                buffer_array = bufs[0]
                buffer_element = bufs[1]
  
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
        end
  
        # Destroy `buffer_array` and `buffer_element`
        fun destroy
        do
                glDeleteBuffers([buffer_array, buffer_element])
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                buffer_array = -1
                buffer_element = -1
                glBindBuffer(gl_ARRAY_BUFFER, buffer_array)
                assert glIsBuffer(buffer_array)
                glBufferData(gl_ARRAY_BUFFER, array_bytes, new Pointer.nul, usage)
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # GL_TRIANGLES 6 vertices * sprite
                var n_indices = capacity * indices_per_sprite
                glBindBuffer(gl_ELEMENT_ARRAY_BUFFER, buffer_element)
                assert glIsBuffer(buffer_element)
                glBufferData(gl_ELEMENT_ARRAY_BUFFER, element_bytes, new Pointer.nul, usage)
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                buffer_capacity = capacity
  
                glBindBuffer(gl_ELEMENT_ARRAY_BUFFER, buffer_element)
                glBufferSubData(gl_ELEMENT_ARRAY_BUFFER, sprite_index*6*2, 6*2, indices.native_array)
  
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
        end
  
        # Draw all `sprites`
                        glBindTexture(gl_TEXTURE_2D, texture.gl_texture)
                        app.simple_2d_program.texture.uniform 0
                end
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                var animation = animation_texture
                if animation != null then
                        glBindTexture(gl_TEXTURE_2D, animation.gl_texture)
                        app.simple_2d_program.animation_texture.uniform 1
                end
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # Configure attributes, in order:
                # vec4 translation, vec4 color, float scale, vec4 coord, vec2 tex_coord, vec4 rotation_row*,
                glEnableVertexAttribArray p.translation.location
                glVertexAttribPointeri(p.translation.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 4
                glEnableVertexAttribArray p.color.location
                glVertexAttribPointeri(p.color.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 1
                glEnableVertexAttribArray p.scale.location
                glVertexAttribPointeri(p.scale.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 4
                glEnableVertexAttribArray p.coord.location
                glVertexAttribPointeri(p.coord.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 2
                glEnableVertexAttribArray p.tex_coord.location
                glVertexAttribPointeri(p.tex_coord.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 4
                for r in [p.rotation_row0, p.rotation_row1, p.rotation_row2, p.rotation_row3] do
                                glVertexAttribPointeri(r.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                        end
                        offset += size * sizeof_gl_float
-                       gl_error = glGetError
-                       assert gl_error == gl_NO_ERROR else print_error gl_error
+                       assert glGetError == gl_NO_ERROR
                end
  
                size = 1
                glEnableVertexAttribArray p.animation_fps.location
                glVertexAttribPointeri(p.animation_fps.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 1
                glEnableVertexAttribArray p.animation_n_frames.location
                glVertexAttribPointeri(p.animation_n_frames.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 2
                glEnableVertexAttribArray p.animation_coord.location
                glVertexAttribPointeri(p.animation_coord.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 2
                glEnableVertexAttribArray p.animation_tex_coord.location
                glVertexAttribPointeri(p.animation_tex_coord.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 2
                glEnableVertexAttribArray p.animation_tex_diff.location
                glVertexAttribPointeri(p.animation_tex_diff.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 1
                glEnableVertexAttribArray p.animation_start.location
                glVertexAttribPointeri(p.animation_start.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                size = 1
                glEnableVertexAttribArray p.animation_loops.location
                glVertexAttribPointeri(p.animation_loops.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
                offset += size * sizeof_gl_float
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
  
                # Actual draw
                for s in sprites.starts, e in sprites.ends do
                        var l = e-s
                        glDrawElementsi(gl_TRIANGLES, l*indices_per_sprite, gl_UNSIGNED_SHORT, 2*s*indices_per_sprite)
-                       gl_error = glGetError
-                       assert gl_error == gl_NO_ERROR else print_error gl_error
+                       assert glGetError == gl_NO_ERROR
                end
  
                # Take down
                             p.rotation_row0, p.rotation_row1, p.rotation_row2, p.rotation_row3: Attribute] do
                        if not attr.is_active then continue
                        glDisableVertexAttribArray(attr.location)
-                       gl_error = glGetError
-                       assert gl_error == gl_NO_ERROR else print_error gl_error
+                       assert glGetError == gl_NO_ERROR
                end
  
                glBindBuffer(gl_ARRAY_BUFFER, 0)
                glBindBuffer(gl_ELEMENT_ARRAY_BUFFER, 0)
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
        end
  end
  
  redef class GLfloatArray
        private fun fill_from_matrix(matrix: Matrix, dst_offset: nullable Int)
        do
 -              dst_offset = dst_offset or else 0
 +              dst_offset = dst_offset or else add_index
                var mat_len = matrix.width*matrix.height
                assert length >= mat_len + dst_offset
                native_array.fill_from_matrix_native(matrix.items, dst_offset, mat_len)
 +              add_index += mat_len
        end
  end
  
@@@ -24,7 -24,7 +24,8 @@@ import c_tool
  private import annotation
  import mixin
  import counter
 +import pkgconfig
+ private import explain_assert_api
  
  # Add compiling options
  redef class ToolContext
@@@ -189,8 -189,6 +190,8 @@@ class MakefileToolchai
                var time1 = get_time
                self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
  
 +              if not toolcontext.check_errors then return
 +
                # Execute the Makefile
  
                if self.toolcontext.opt_no_cc.value then return
@@@ -469,19 -467,14 +470,19 @@@ endi
                        f.close
                end
  
 -              var java_files = new Array[ExternFile]
 -
 +              # pkg-config annotation support
                var pkgconfigs = new Array[String]
                for f in compiler.extern_bodies do
                        pkgconfigs.add_all f.pkgconfigs
                end
 -              # Protect pkg-config
 +
 +              # Only test if pkg-config is used
                if not pkgconfigs.is_empty then
 +
 +                      # Check availability of pkg-config, silence the proc output
 +                      toolcontext.check_pkgconfig_packages pkgconfigs
 +
 +                      # Double the check in the Makefile in case it's distributed
                        makefile.write """
  # does pkg-config exists?
  ifneq ($(shell which pkg-config >/dev/null; echo $$?), 0)
@@@ -499,7 -492,6 +500,7 @@@ endi
                end
  
                # Compile each required extern body into a specific .o
 +              var java_files = new Array[ExternFile]
                for f in compiler.extern_bodies do
                        var o = f.makefile_rule_name
                        var ff = f.filename.basename
@@@ -3615,6 -3607,9 +3616,9 @@@ redef class AAssertExp
                var cond = v.expr_bool(self.n_expr)
                v.add("if (unlikely(!{cond})) \{")
                v.stmt(self.n_else)
+               explain_assert v
                var nid = self.n_id
                if nid != null then
                        v.add_abort("Assert '{nid.text}' failed")
                end
                v.add("\}")
        end
+       # Explain assert if it fails
+       private fun explain_assert(v: AbstractCompilerVisitor)
+       do
+               var explain_assert_str = explain_assert_str
+               if explain_assert_str == null then return
+               var nas = v.compiler.modelbuilder.model.get_mclasses_by_name("NativeArray")
+               if nas == null then return
+               var expr = explain_assert_str.expr(v)
+               if expr == null then return
+               var cstr = v.send(v.get_property("to_cstring", expr.mtype), [expr])
+               if cstr == null then return
+               v.add "PRINT_ERROR(\"Runtime assert: %s\\n\", {cstr});"
+       end
  end
  
  redef class AOrExpr
@@@ -23,6 -23,7 +23,7 @@@ private import parser::table
  import mixin
  import primitive_types
  private import model::serialize_model
+ private import frontend::explain_assert_api
  
  redef class ToolContext
        # --discover-call-trace
@@@ -825,7 -826,7 +826,7 @@@ class InterpreterFram
        super Frame
  
        # Mapping between a variable and the current value
 -      private var map: Map[Variable, Instance] = new HashMap[Variable, Instance]
 +      var map: Map[Variable, Instance] = new HashMap[Variable, Instance]
  end
  
  redef class ANode
@@@ -874,10 -875,7 +875,10 @@@ redef class AMethPropde
                return res
        end
  
 -      private fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame): nullable Instance
 +      # Execution of the body of the method
 +      #
 +      # It handle the common special cases: super, intern, extern
 +      fun call_commons(v: NaiveInterpreter, mpropdef: MMethodDef, arguments: Array[Instance], f: Frame): nullable Instance
        do
                v.frames.unshift(f)
  
@@@ -1702,8 -1700,6 +1703,8 @@@ redef class AEscapeExp
                        var i = v.expr(ne)
                        if i == null then return
                        v.escapevalue = i
 +              else
 +                      v.escapevalue = null
                end
                v.escapemark = self.escapemark
        end
@@@ -1880,6 -1876,22 +1881,22 @@@ redef class AAssertExp
                if not cond.is_true then
                        v.stmt(self.n_else)
                        if v.is_escaping then return
+                       # Explain assert if it fails
+                       var explain_assert_str = explain_assert_str
+                       if explain_assert_str != null then
+                               var i = v.expr(explain_assert_str)
+                               if i isa MutableInstance then
+                                       var res = v.send(v.force_get_primitive_method("to_cstring", i.mtype), [i])
+                                       if res != null then
+                                               var val = res.val
+                                               if val != null then
+                                                       print_error "Runtime assert: {val.to_s}"
+                                               end
+                                       end
+                               end
+                       end
                        var nid = self.n_id
                        if nid != null then
                                fatal(v, "Assert '{nid.text}' failed")