Core C++

3.4. Binary operators🔗

Definition3.4.1
Group: Values, types and expressions. (12)
Group member previews
Preview
Definition 3.1.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 3
Statement dependency previews
Preview
Definition 2.1.3
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 1✓L∃∀N

The arithmetic operators require int on both operands. The left operand is evaluated before the right one. Division and remainder truncate toward zero, as in C++, and a zero divisor is error.

\dfrac{\Gamma \vdash e_1 : \mathsf{int} \qquad \Gamma \vdash e_2 : \mathsf{int}}{\Gamma \vdash e_1 \oplus e_2 : \mathsf{int}}\;\textsf{(T-Arith)}, \quad \oplus \in \{+, -, *, /, \%\}

\dfrac{\rho, \sigma \vdash e_1 \Rightarrow \mathsf{int}\,n_1, \sigma_1 \qquad \rho, \sigma_1 \vdash e_2 \Rightarrow \mathsf{int}\,n_2, \sigma_2}{\rho, \sigma \vdash e_1 \oplus e_2 \Rightarrow \mathsf{int32}(n_1 \oplus n_2), \sigma_2}\;\textsf{(Arith)}, \quad \oplus \in \{+, -, *\}

\dfrac{\begin{array}{c} \rho, \sigma \vdash e_1 \Rightarrow \mathsf{int}\,n_1, \sigma_1 \qquad \rho, \sigma_1 \vdash e_2 \Rightarrow \mathsf{int}\,n_2, \sigma_2 \\ n_2 \neq 0 \end{array}}{\rho, \sigma \vdash e_1 \oslash e_2 \Rightarrow \mathsf{int32}(n_1 \oslash n_2), \sigma_2}\;\textsf{(Div)}, \quad \oslash \in \{/, \%\}

\dfrac{\rho, \sigma \vdash e_1 \Rightarrow \mathsf{int}\,n_1, \sigma_1 \qquad \rho, \sigma_1 \vdash e_2 \Rightarrow \mathsf{int}\,0, \sigma_2}{\rho, \sigma \vdash e_1 \oslash e_2 \Rightarrow \mathsf{error}}\;\textsf{(DivZero)}

In the code, the case Binary of Eval.expr evaluates both operands and calls Eval.binop.

Some of the implementations are partial, so Lean records opaque constants that carry the type and not the body, and no property of them is proved here.

Lean code for Definition3.4.1●4 definitions
  • opaquedefined in CoreCpp/Typing.lean
    complete
    opaque CoreCpp.Typing.expr (p : CoreCpp.Program) (Γ : CoreCpp.TEnv) :
      CoreCpp.Expr → CoreCpp.T CoreCpp.Ty
    opaque CoreCpp.Typing.expr (p : CoreCpp.Program)
      (Γ : CoreCpp.TEnv) :
      CoreCpp.Expr → CoreCpp.T CoreCpp.Ty
    Γ ⊢ e : τ 
  • opaquedefined in CoreCpp/Eval.lean
    complete
    opaque CoreCpp.Eval.expr (fs : CoreCpp.FunEnv) (ρ : CoreCpp.Env)
      (σ : CoreCpp.Store) (e : CoreCpp.Expr) :
      CoreCpp.M (CoreCpp.Val × CoreCpp.Store)
    opaque CoreCpp.Eval.expr (fs : CoreCpp.FunEnv)
      (ρ : CoreCpp.Env) (σ : CoreCpp.Store)
      (e : CoreCpp.Expr) :
      CoreCpp.M (CoreCpp.Val × CoreCpp.Store)
    ρ, σ ⊢ e ⇒ v, σ' 
  • inductive(13 constructors)defined in CoreCpp/Syntax.lean
    complete
    inductive CoreCpp.BinOp : Type
    inductive CoreCpp.BinOp : Type
    CoreCpp.BinOp.add : CoreCpp.BinOp
    CoreCpp.BinOp.sub : CoreCpp.BinOp
    CoreCpp.BinOp.mul : CoreCpp.BinOp
    CoreCpp.BinOp.div : CoreCpp.BinOp
    CoreCpp.BinOp.mod : CoreCpp.BinOp
    CoreCpp.BinOp.eq : CoreCpp.BinOp
    CoreCpp.BinOp.ne : CoreCpp.BinOp
    CoreCpp.BinOp.lt : CoreCpp.BinOp
    CoreCpp.BinOp.le : CoreCpp.BinOp
    CoreCpp.BinOp.gt : CoreCpp.BinOp
    CoreCpp.BinOp.ge : CoreCpp.BinOp
    CoreCpp.BinOp.and : CoreCpp.BinOp
    CoreCpp.BinOp.or : CoreCpp.BinOp
  • defdefined in CoreCpp/Eval.lean
    complete
    def CoreCpp.Eval.binop :
      CoreCpp.BinOp → CoreCpp.Val → CoreCpp.Val → CoreCpp.M CoreCpp.Val
    def CoreCpp.Eval.binop :
      CoreCpp.BinOp →
        CoreCpp.Val →
          CoreCpp.Val → CoreCpp.M CoreCpp.Val
    Arithmetic and relational binary operators, on already evaluated values.
    
    ```
    ρ, σ ⊢ e₁ ⇒ int n₁, σ₁    ρ, σ₁ ⊢ e₂ ⇒ int n₂, σ₂
    ──────────────────────────────────────────────── (Arith, ⊕ ∈ {+, −, ×})
    ρ, σ ⊢ e₁ ⊕ e₂ ⇒ int32 (n₁ ⊕ n₂), σ₂
    ```
    
    ```
    ρ, σ ⊢ e₁ ⇒ int n₁, σ₁    ρ, σ₁ ⊢ e₂ ⇒ int n₂, σ₂    n₂ ≠ 0
    ──────────────────────────────────────────────────────── (Div, ⊘ ∈ {/, %})
    ρ, σ ⊢ e₁ ⊘ e₂ ⇒ int32 (n₁ ⊘ n₂), σ₂          division truncates toward zero, as in C++
    ```
    
    ```
    ρ, σ ⊢ e₁ ⇒ int n₁, σ₁    ρ, σ₁ ⊢ e₂ ⇒ int 0, σ₂
    ──────────────────────────────────────────────── (DivZero)
    ρ, σ ⊢ e₁ ⊘ e₂ ⇒ error (division by zero)
    ```
    
    ```
    ρ, σ ⊢ e₁ ⇒ v₁, σ₁    ρ, σ₁ ⊢ e₂ ⇒ v₂, σ₂
    ─────────────────────────────────────────── (Rel, ⋈ ∈ {==, !=, <, <=, >, >=})
    ρ, σ ⊢ e₁ ⋈ e₂ ⇒ bool (v₁ ⋈ v₂), σ₂
    ```
    
    Two pointers are equal when they are the same location. nullptr equals
    only nullptr. There is no order on pointers.
    
    The left operand is evaluated before the right one, the Core C++ choice
    where C++17 does not specify the order.
    
Definition3.4.2
Group: Values, types and expressions. (12)
Group member previews
Preview
Definition 3.1.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 2
Statement dependency previews
Preview
Definition 2.2.1
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 0✓L∃∀N

Equality compares two int, two bool or two pointers, and nullptr against a pointer, the relation \tau_1 \approx \tau_2. Two pointers are equal when they are the same location, and nullptr equals only nullptr. Order compares two int, there is no order on pointers. The result is bool.

\dfrac{\begin{array}{c} \Gamma \vdash e_1 : \tau_1 \qquad \Gamma \vdash e_2 : \tau_2 \qquad \tau_1 \approx \tau_2 \\ \tau_1, \tau_2 \in \{\mathsf{int}, \mathsf{bool}, \tau*, \mathsf{nullptr\_t}\} \end{array}}{\Gamma \vdash e_1 \bowtie e_2 : \mathsf{bool}}\;\textsf{(T-Eq)}, \quad \bowtie \in \{==, \mathrel{!=}\}

\dfrac{\Gamma \vdash e_1 : \mathsf{int} \qquad \Gamma \vdash e_2 : \mathsf{int}}{\Gamma \vdash e_1 \bowtie e_2 : \mathsf{bool}}\;\textsf{(T-Rel)}, \quad \bowtie \in \{<, <=, >, >=\}

\dfrac{\rho, \sigma \vdash e_1 \Rightarrow v_1, \sigma_1 \qquad \rho, \sigma_1 \vdash e_2 \Rightarrow v_2, \sigma_2}{\rho, \sigma \vdash e_1 \bowtie e_2 \Rightarrow \mathsf{bool}(v_1 \bowtie v_2), \sigma_2}\;\textsf{(Rel)}

Some of the implementations are partial, so Lean records opaque constants that carry the type and not the body, and no property of them is proved here.

Lean code for Definition3.4.2●4 definitions
  • opaquedefined in CoreCpp/Typing.lean
    complete
    opaque CoreCpp.Typing.expr (p : CoreCpp.Program) (Γ : CoreCpp.TEnv) :
      CoreCpp.Expr → CoreCpp.T CoreCpp.Ty
    opaque CoreCpp.Typing.expr (p : CoreCpp.Program)
      (Γ : CoreCpp.TEnv) :
      CoreCpp.Expr → CoreCpp.T CoreCpp.Ty
    Γ ⊢ e : τ 
  • opaquedefined in CoreCpp/Eval.lean
    complete
    opaque CoreCpp.Eval.expr (fs : CoreCpp.FunEnv) (ρ : CoreCpp.Env)
      (σ : CoreCpp.Store) (e : CoreCpp.Expr) :
      CoreCpp.M (CoreCpp.Val × CoreCpp.Store)
    opaque CoreCpp.Eval.expr (fs : CoreCpp.FunEnv)
      (ρ : CoreCpp.Env) (σ : CoreCpp.Store)
      (e : CoreCpp.Expr) :
      CoreCpp.M (CoreCpp.Val × CoreCpp.Store)
    ρ, σ ⊢ e ⇒ v, σ' 
  • defdefined in CoreCpp/Eval.lean
    complete
    def CoreCpp.Eval.binop :
      CoreCpp.BinOp → CoreCpp.Val → CoreCpp.Val → CoreCpp.M CoreCpp.Val
    def CoreCpp.Eval.binop :
      CoreCpp.BinOp →
        CoreCpp.Val →
          CoreCpp.Val → CoreCpp.M CoreCpp.Val
    Arithmetic and relational binary operators, on already evaluated values.
    
    ```
    ρ, σ ⊢ e₁ ⇒ int n₁, σ₁    ρ, σ₁ ⊢ e₂ ⇒ int n₂, σ₂
    ──────────────────────────────────────────────── (Arith, ⊕ ∈ {+, −, ×})
    ρ, σ ⊢ e₁ ⊕ e₂ ⇒ int32 (n₁ ⊕ n₂), σ₂
    ```
    
    ```
    ρ, σ ⊢ e₁ ⇒ int n₁, σ₁    ρ, σ₁ ⊢ e₂ ⇒ int n₂, σ₂    n₂ ≠ 0
    ──────────────────────────────────────────────────────── (Div, ⊘ ∈ {/, %})
    ρ, σ ⊢ e₁ ⊘ e₂ ⇒ int32 (n₁ ⊘ n₂), σ₂          division truncates toward zero, as in C++
    ```
    
    ```
    ρ, σ ⊢ e₁ ⇒ int n₁, σ₁    ρ, σ₁ ⊢ e₂ ⇒ int 0, σ₂
    ──────────────────────────────────────────────── (DivZero)
    ρ, σ ⊢ e₁ ⊘ e₂ ⇒ error (division by zero)
    ```
    
    ```
    ρ, σ ⊢ e₁ ⇒ v₁, σ₁    ρ, σ₁ ⊢ e₂ ⇒ v₂, σ₂
    ─────────────────────────────────────────── (Rel, ⋈ ∈ {==, !=, <, <=, >, >=})
    ρ, σ ⊢ e₁ ⋈ e₂ ⇒ bool (v₁ ⋈ v₂), σ₂
    ```
    
    Two pointers are equal when they are the same location. nullptr equals
    only nullptr. There is no order on pointers.
    
    The left operand is evaluated before the right one, the Core C++ choice
    where C++17 does not specify the order.
    
  • defdefined in CoreCpp/Typing.lean
    complete
    def CoreCpp.Typing.compat (p : CoreCpp.Program) :
      CoreCpp.Ty → CoreCpp.Ty → Bool
    def CoreCpp.Typing.compat
      (p : CoreCpp.Program) :
      CoreCpp.Ty → CoreCpp.Ty → Bool
    τ ≈ τ', the type τ of a value is accepted where τ' is expected. Equal
    types, nullptr against a pointer type, or, by subsumption, a pointer to a
    derived class where a pointer to its base is expected. These and the lambda
    to `std::function` are the only implicit conversions.
    
    ```
    D derives from B
    ──────────────── (Subsumption)
    D* ≈ B*
    ```
    
    ```
    Γ ⊢ e : D*    D derives from B
    ────────────────────────────── (T-Sub)      subsumption where a value is
    Γ ⊢ e : B*                                  used, wherever ≈ is required
    ```
    
Definition3.4.3
Group: Values, types and expressions. (12)
Group member previews
Preview
Definition 3.1.1
Loading preview
Group member preview content is loaded from the rendered-fragment cache.
Statement uses 2
Statement dependency previews
Preview
Definition 2.2.1
Loading preview
Statement dependency preview content is loaded from the rendered-fragment cache.
used by 0✓L∃∀N

Conjunction and disjunction require bool and short circuit. The second operand is evaluated only when the first one does not decide the result.

\dfrac{\Gamma \vdash e_1 : \mathsf{bool} \qquad \Gamma \vdash e_2 : \mathsf{bool}}{\Gamma \vdash e_1 \odot e_2 : \mathsf{bool}}\;\textsf{(T-Logic)}, \quad \odot \in \{\&\&, ||\}

\dfrac{\rho, \sigma \vdash e_1 \Rightarrow \mathsf{bool}\,\mathtt{false}, \sigma_1}{\rho, \sigma \vdash e_1 \mathbin{\&\&} e_2 \Rightarrow \mathsf{bool}\,\mathtt{false}, \sigma_1}\;\textsf{(And-False)}

\dfrac{\rho, \sigma \vdash e_1 \Rightarrow \mathsf{bool}\,\mathtt{true}, \sigma_1 \qquad \rho, \sigma_1 \vdash e_2 \Rightarrow v, \sigma_2}{\rho, \sigma \vdash e_1 \mathbin{\&\&} e_2 \Rightarrow v, \sigma_2}\;\textsf{(And-True)}

\dfrac{\rho, \sigma \vdash e_1 \Rightarrow \mathsf{bool}\,\mathtt{true}, \sigma_1}{\rho, \sigma \vdash e_1 \mathbin{||} e_2 \Rightarrow \mathsf{bool}\,\mathtt{true}, \sigma_1}\;\textsf{(Or-True)}

\dfrac{\rho, \sigma \vdash e_1 \Rightarrow \mathsf{bool}\,\mathtt{false}, \sigma_1 \qquad \rho, \sigma_1 \vdash e_2 \Rightarrow v, \sigma_2}{\rho, \sigma \vdash e_1 \mathbin{||} e_2 \Rightarrow v, \sigma_2}\;\textsf{(Or-False)}

In the code, the cases And and Or of Eval.expr implement the two pairs of rules.

The implementations are partial, so Lean records opaque constants that carry the type and not the body, and no property of them is proved here.

Lean code for Definition3.4.3●2 definitions
  • opaquedefined in CoreCpp/Typing.lean
    complete
    opaque CoreCpp.Typing.expr (p : CoreCpp.Program) (Γ : CoreCpp.TEnv) :
      CoreCpp.Expr → CoreCpp.T CoreCpp.Ty
    opaque CoreCpp.Typing.expr (p : CoreCpp.Program)
      (Γ : CoreCpp.TEnv) :
      CoreCpp.Expr → CoreCpp.T CoreCpp.Ty
    Γ ⊢ e : τ 
  • opaquedefined in CoreCpp/Eval.lean
    complete
    opaque CoreCpp.Eval.expr (fs : CoreCpp.FunEnv) (ρ : CoreCpp.Env)
      (σ : CoreCpp.Store) (e : CoreCpp.Expr) :
      CoreCpp.M (CoreCpp.Val × CoreCpp.Store)
    opaque CoreCpp.Eval.expr (fs : CoreCpp.FunEnv)
      (ρ : CoreCpp.Env) (σ : CoreCpp.Store)
      (e : CoreCpp.Expr) :
      CoreCpp.M (CoreCpp.Val × CoreCpp.Store)
    ρ, σ ⊢ e ⇒ v, σ'