/-
Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
module

prelude
public import Lean.Meta.Tactic.Simp.BuiltinSimprocs.Char
import Lean.Meta.StringLitProof

public section

namespace String
open Lean Meta Simp

def fromExpr? (e : Expr) : SimpM (Option String) := do
  return getStringValue? e

builtin_dsimproc [simp, seval] reduceAppend ((_ ++ _ : String)) := fun e => do
  unless e.isAppOfArity ``HAppend.hAppend 6 do return .continue
  let some a ← fromExpr? e.appFn!.appArg! | return .continue
  let some b ← fromExpr? e.appArg! | return .continue
  return .done <| toExpr (a ++ b)

private partial def reduceListChar (e : Expr) (s : String) : SimpM DStep := do
  if e.isAppOfArity ``List.nil 1 then
    return .done <| toExpr s
  else if e.isAppOfArity ``List.cons 3 then
    let some c ← Char.fromExpr? e.appFn!.appArg! | return .continue
    reduceListChar e.appArg! (s.push c)
  else
    return .continue

builtin_dsimproc [simp, seval] reduceOfList (String.ofList _) := fun e => do
  unless e.isAppOfArity ``String.ofList 1 do return .continue
  reduceListChar e.appArg! ""

builtin_dsimproc [simp, seval] reduceToList (String.toList _) := fun e => do
  unless e.isAppOfArity ``String.toList 1 do return .continue
  let some s ← fromExpr? e.appArg! | return .continue
  return .done <| toExpr s.toList

builtin_dsimproc [simp, seval] reducePush (String.push _ _) := fun e => do
  unless e.isAppOfArity ``String.push 2 do return .continue
  let some n ← fromExpr? e.appFn!.appArg! | return .continue
  let some m ← Char.fromExpr? e.appArg! | return .continue
  return .done <| toExpr (n.push m)

builtin_dsimproc [simp, seval] reduceSingleton (String.singleton _) := fun e => do
  unless e.isAppOfArity ``String.singleton 1 do return .continue
  let some c ← Char.fromExpr? e.appArg! | return .continue
  return .done <| toExpr (String.singleton c)

builtin_dsimproc_decl reduceToSingleton ((_ : String)) := fun e => do
  let some s ← fromExpr? e | return .continue
  let l := s.toList
  let [c] := l | return .continue
  return .done <| mkApp (mkConst ``String.singleton) (toExpr c)

@[inline] def reduceBinPred (declName : Name) (arity : Nat) (op : String → String → Bool) (e : Expr) : SimpM Step := do
  unless e.isAppOfArity declName arity do return .continue
  let some n ← fromExpr? e.appFn!.appArg! | return .continue
  let some m ← fromExpr? e.appArg! | return .continue
  evalPropStep e (op n m)


@[inline] def reduceBoolPred (declName : Name) (arity : Nat) (op : String → String → Bool) (e : Expr) : SimpM DStep := do
  unless e.isAppOfArity declName arity do return .continue
  let some n ← fromExpr? e.appFn!.appArg! | return .continue
  let some m ← fromExpr? e.appArg! | return .continue
  return .done <| toExpr (op n m)

builtin_simproc [simp, seval] reduceLT  (( _ : String) < _)  := reduceBinPred ``LT.lt 4 (. < .)
builtin_simproc [simp, seval] reduceLE  (( _ : String) ≤ _)  := reduceBinPred ``LE.le 4 (. ≤ .)
builtin_simproc [simp, seval] reduceGT  (( _ : String) > _)  := reduceBinPred ``GT.gt 4 (. > .)
builtin_simproc [simp, seval] reduceGE  (( _ : String) ≥ _)  := reduceBinPred ``GE.ge 4 (. ≥ .)

builtin_simproc [simp, seval] reduceEq (( _ : String) = _) := fun e => do
  unless e.isAppOfArity ``Eq 3 do return .continue
  let some n ← fromExpr? e.appFn!.appArg! | return .continue
  let some m ← fromExpr? e.appArg! | return .continue
  evalEqPropStep e (n = m) (mkStringLitNeProof n m)

builtin_simproc [simp, seval] reduceNe (( _ : String) ≠ _) := fun e => do
  unless e.isAppOfArity ``Ne 3 do return .continue
  let some n ← fromExpr? e.appFn!.appArg! | return .continue
  let some m ← fromExpr? e.appArg! | return .continue
  evalNePropStep e (n ≠ m) (mkStringLitNeProof n m)
builtin_dsimproc [simp, seval] reduceBEq  (( _ : String) == _)  := reduceBoolPred ``BEq.beq 4 (. == .)
builtin_dsimproc [simp, seval] reduceBNe  (( _ : String) != _)  := reduceBoolPred ``bne 4 (. != .)

end String
