open import Data.Nat
open import Data.List.Most
open import Data.Integer
open import Data.Product

-- This file contains the definition of values for the definitional
-- interpreter for MJ using scopes and frames, described in Section 5
-- of the paper.

module MJSF.Values (k : ) where

open import MJSF.Syntax k
open import ScopesFrames.ScopesFrames k Ty

module ValuesG (g : Graph) where

  open SyntaxG g
  open UsesGraph g public
  open import Common.Weakening

  ------------
  -- VALUES --
  ------------

  -- The values used in our interpreter at run time are either:
  --
  -- * object references `ref`, represented in terms of a frame scoped
  --   by a class scope;
  --
  -- * null values (`ref` typed);
  --
  -- * an integer number literal (`int` typed); or
  --
  -- * `void` (`void typed -- note that there is no expression syntax
  --   for producing a `void` value directly, but method bodies still
  --   return `void`; we regard `void` as a unit type)

  data Val : VTy  List Scope  Set where
    ref    :   {s s' Σ}  s <: s'  Frame s Σ  Val (ref s') Σ
    null   :   {s Σ}  Val (ref s) Σ
    num    :   {Σ}    Val int Σ
    void   :   {Σ}  Val void Σ

  -- There are three kinds of values stored in frame slots at run
  -- time, corresponding to each of the three kinds of declarations
  -- defined in `MJSF.Syntax`:
  --
  -- * values, as defined above;
  --
  -- * methods, where a method records a "self" frame `Frame s Σ` and
  --   a well-typed method definition `Meth s ts rt`, such that the
  --   scope of the method corresponds to the "self"; and
  --
  -- * classes which record a well-typed class definition and a
  --   witness that the class has a finite inheritance chain, both
  --   used for initializing new object instances, as well as a frame
  --   pointer to the root frame (class table).

  data Valᵗ : Ty  List Scope  Set where
    vᵗ :  {t Σ}  Val t Σ  Valᵗ (vᵗ t) Σ
    mᵗ :  {s ts rt Σ}  (self : Frame s Σ)  (body : Meth s ts rt)  Valᵗ (mᵗ ts rt) Σ
    cᵗ :  { s s' Σ}  (class-def : Class  s)  (ic : Inherits s s')  (root : Frame  Σ)  Valᵗ (cᵗ  s) Σ


  ---------------
  -- WEAKENING --
  ---------------

  -- We define notions of weakening for each of the values summarized above:

  val-weaken    :   {t Σ Σ'}  Σ  Σ'  Val t Σ  Val t Σ'
  val-weaken ext (num i)  =  num i
  val-weaken ext (ref i f)  =  ref i (wk ext f)
  val-weaken ext null     =  null
  val-weaken ext void     =  void

  instance
    val-weakenable :  {t}  Weakenable (Val t)
    val-weakenable = record { wk = val-weaken }

  valᵗ-weaken :  {t Σ Σ'}  Σ  Σ'  Valᵗ t Σ  Valᵗ t Σ'
  valᵗ-weaken ext (vᵗ v)      = vᵗ (val-weaken ext v)
  valᵗ-weaken ext (mᵗ f m)    = mᵗ (wk ext f) m
  valᵗ-weaken ext (cᵗ c ic f) = cᵗ c ic (wk ext f)

  -- And pass these to the scope graph definition:

  open UsesVal Valᵗ valᵗ-weaken renaming (getFrame to getFrame')


  --------------
  -- COERCION --
  --------------

  -- Our definition of sub-typing gives rise to a notion of sub-type
  -- coercion, defined below.  Coercions essentially traverse the
  -- inheritance links of the frame hierarchy for an object instance,
  -- as described in the paper.

  upcastRef :  {t t' Σ}  t <: t'  Val (ref t) Σ  Val (ref t') Σ
  upcastRef i (ref i' f) = ref (concatₚ i' i) f
  upcastRef i null = null