/*---------------------------------------------------------------------------
  Copyright 2012-2024, Microsoft Research, Daan Leijen.

  This is free software; you can redistribute it and/or modify it under the
  terms of the Apache License, Version 2.0. A copy of the License can be
  found in the LICENSE file at the root of this distribution.
---------------------------------------------------------------------------*/

// Standard `:char` functions.
//
// Characters are unicode _codepoint_\/s.
// This is different from a unicode _grapheme_ which represents a single displayed
// symbol and can consists of multiple codepoints due to combining characters and marks.
module std/core/charstd/core/char

import std/core/typesstd/core/types
import std/core/intstd/core/int

// ----------------------------------------------------------------------------
// Characters
// ----------------------------------------------------------------------------

// Are two characters equal?
pub inline fip extern (==)std/core/char/(==): (char, char) -> bool : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
  inline "(#1 == #2)"
  js inline "(#1 === #2)"

// Are two characters not equal?
pub inline fip extern (!=)std/core/char/(!=): (char, char) -> bool : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
  inline "(#1 != #2)"
  js inline "(#1 !== #2)"

// Is a character code point lower or equal to that of another?
pub inline fip extern (<=)std/core/char/(<=): (char, char) -> bool : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
  inline "(#1 <= #2)"

// Is a character code point greater or equal to that of another?
pub inline fip extern (>=)std/core/char/(>=): (char, char) -> bool : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
  inline "(#1 >= #2)"

// Is a character code point lower to that of another?
pub inline fip extern (<)std/core/char/(<): (char, char) -> bool  : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
  inline "(#1 < #2)"

// Is a character code point greater to that of another?
pub inline fip extern (>)std/core/char/(>): (char, char) -> bool  : (charstd/core/types/char: V,charstd/core/types/char: V) -> boolstd/core/types/bool: V
  inline "(#1 > #2)"

// Compare character code points.
pub fip fun cmpstd/core/char/cmp: (x : char, y : char) -> order( xx: char : charstd/core/types/char: V, yy: char : charstd/core/types/char: V )result: -> total order : orderstd/core/types/order: V
  if xx: char <std/core/char/(<): (char, char) -> bool yy: char then Ltstd/core/types/Lt: order
  elif xx: char >std/core/char/(>): (char, char) -> bool yy: char then Gtstd/core/types/Gt: order
  else Eqstd/core/types/Eq: order

// Order two characters in ascending order.
pub fip fun order2std/core/char/order2: (x : char, y : char) -> order2<char>( xx: char : charstd/core/types/char: V, yy: char : charstd/core/types/char: V )result: -> total order2<char> : order2std/core/types/order2: V -> V<charstd/core/types/char: V>
  if (xx: char==std/core/char/(==): (char, char) -> boolyy: char) then Eq2std/core/types/Eq2: forall<a> (eq : a) -> order2<a>(xx: char) elif (xx: char <std/core/char/(<): (char, char) -> bool yy: char) then Lt2std/core/types/Lt2: forall<a> (lt : a, gt : a) -> order2<a>(xx: char,yy: char) else Gt2std/core/types/Gt2: forall<a> (lt : a, gt : a) -> order2<a>(yy: char,xx: char)

// Convert a character to its unicode code point
pub inline fip extern intstd/core/char/int: (char) -> int : (charstd/core/types/char: V) -> intstd/core/types/int: V
  inline "#1"
  c "kk_integer_from_int"
  cs inline "new BigInteger(#1)"

// Convert a unicode code point to a character
pub inline fip extern int/charstd/core/char/int/char: (i : int) -> char( i : intstd/core/types/int: V) : charstd/core/types/char: V
  inline "(#1)"
  c "kk_integer_clamp32"
  cs inline "Primitive.IntToInt32(#1)"

// Add two character code points
pub fip fun (+)std/core/char/(+): (c : char, d : char) -> char(cc: char : charstd/core/types/char: V, dd: char : charstd/core/types/char: V)result: -> total char : totalstd/core/types/total: E charstd/core/types/char: V
  (cc: char.intstd/core/char/int: (char) -> int +std/core/int/(+): (x : int, y : int) -> int dd: char.intstd/core/char/int: (char) -> int).charstd/core/char/int/char: (i : int) -> char

// Subtract two character code points
pub fip fun (-)std/core/char/(-): (c : char, d : char) -> char(cc: char : charstd/core/types/char: V, dd: char : charstd/core/types/char: V)result: -> total char : totalstd/core/types/total: E charstd/core/types/char: V
  (cc: char.intstd/core/char/int: (char) -> int -std/core/int/(-): (x : int, y : int) -> int dd: char.intstd/core/char/int: (char) -> int).charstd/core/char/int/char: (i : int) -> char

// Is the character a lower-case ASCII character?
pub fip fun is-lowerstd/core/char/is-lower: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V
  cc: char >=std/core/char/(>=): (char, char) -> bool 'a'literal: char
unicode= u0061
&&std/core/types/(&&): (x : bool, y : bool) -> bool cc: char <=std/core/char/(<=): (char, char) -> bool 'z'literal: char
unicode= u007A
// Is the character an upper-case ASCII character? pub fip fun is-upperstd/core/char/is-upper: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V cc: char >=std/core/char/(>=): (char, char) -> bool 'A'literal: char
unicode= u0041
&&std/core/types/(&&): (x : bool, y : bool) -> bool cc: char <=std/core/char/(<=): (char, char) -> bool 'Z'literal: char
unicode= u005A
// Is the character an ASCII digit ? pub fip fun is-digitstd/core/char/is-digit: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V cc: char >=std/core/char/(>=): (char, char) -> bool '0'literal: char
unicode= u0030
&&std/core/types/(&&): (x : bool, y : bool) -> bool cc: char <=std/core/char/(<=): (char, char) -> bool '9'literal: char
unicode= u0039
// Is the character an ASCII hexa-decimal digit? pub fip fun is-hex-digitstd/core/char/is-hex-digit: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V cc: char.is-digitstd/core/char/is-digit: (c : char) -> bool ||std/core/types/(||): (x : bool, y : bool) -> bool (cc: char >=std/core/char/(>=): (char, char) -> bool 'a'literal: char
unicode= u0061
&&std/core/types/(&&): (x : bool, y : bool) -> bool cc: char <=std/core/char/(<=): (char, char) -> bool 'f'literal: char
unicode= u0066
) ||std/core/types/(||): (x : bool, y : bool) -> bool (cc: char >=std/core/char/(>=): (char, char) -> bool 'A'literal: char
unicode= u0041
&&std/core/types/(&&): (x : bool, y : bool) -> bool cc: char <=std/core/char/(<=): (char, char) -> bool 'F'literal: char
unicode= u0046
) // Is the character an ASCII letter? pub fip fun is-alphastd/core/char/is-alpha: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V cc: char.is-lowerstd/core/char/is-lower: (c : char) -> bool ||std/core/types/(||): (x : bool, y : bool) -> bool cc: char.is-upperstd/core/char/is-upper: (c : char) -> bool // Is the character ASCII letter or digit? pub fip fun is-alpha-numstd/core/char/is-alpha-num: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V cc: char.is-alphastd/core/char/is-alpha: (c : char) -> bool ||std/core/types/(||): (x : bool, y : bool) -> bool cc: char.is-digitstd/core/char/is-digit: (c : char) -> bool // Is the character an ASCII character, e.g. `c <= '\x7F'`? pub fip fun is-asciistd/core/char/is-ascii: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V cc: char <=std/core/char/(<=): (char, char) -> bool '\DEL'literal: char
unicode= u007F
// Is the character an ASCII control character, e.g. `c < ' '`? pub fip fun is-controlstd/core/char/is-control: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V cc: char <std/core/char/(<): (char, char) -> bool ' 'literal: char
unicode= u0020
// Tests if a character is an element of `" \t\n\r"` pub fip fun is-whitestd/core/char/is-white: (c : char) -> bool( cc: char : charstd/core/types/char: V )result: -> total bool : boolstd/core/types/bool: V cc: char ==std/core/char/(==): (char, char) -> bool ' 'literal: char
unicode= u0020
||std/core/types/(||): (x : bool, y : bool) -> bool cc: char ==std/core/char/(==): (char, char) -> bool '\t'literal: char
unicode= u0009
||std/core/types/(||): (x : bool, y : bool) -> bool cc: char ==std/core/char/(==): (char, char) -> bool '\n'literal: char
unicode= u000A
||std/core/types/(||): (x : bool, y : bool) -> bool cc: char ==std/core/char/(==): (char, char) -> bool '\r'literal: char
unicode= u000D