php-kilo/src/functions.php

226 lines
5.0 KiB
PHP

<?php declare(strict_types=1);
namespace Aviat\Kilo;
use Aviat\Kilo\Enum\{Color, Highlight, RawKeyCode};
// ----------------------------------------------------------------------------
// ! C function/macro equivalents
// ----------------------------------------------------------------------------
/**
* Do bit twiddling to convert a letter into
* its Ctrl-letter equivalent ordinal ascii value
*
* @param string $char
* @return int
*/
function ctrl_key(string $char): int
{
if ( ! is_ascii($char))
{
return -1;
}
// b1,100,001 (a) & b0,011,111 (0x1f) = b0,000,001 (SOH)
// b1,100,010 (b) & b0,011,111 (0x1f) = b0,000,010 (STX)
// ...and so on
return ord($char) & 0x1f;
}
/**
* Does the one-character string contain an ascii ordinal value?
*
* @param string $single_char
* @return bool
*/
function is_ascii(string $single_char): bool
{
if (strlen($single_char) > 1)
{
return FALSE;
}
return ord($single_char) < 0x80;
}
/**
* Does the one-character string contain an ascii control character?
*
* @param string $char
* @return bool
*/
function is_ctrl(string $char): bool
{
$c = ord($char);
return is_ascii($char) && ( $c === 0x7f || $c < 0x20 );
}
/**
* Does the one-character string contain an ascii number?
*
* @param string $char
* @return bool
*/
function is_digit(string $char): bool
{
$c = ord($char);
return is_ascii($char) && ( $c > 0x2f && $c < 0x3a );
}
/**
* Does the one-character string contain ascii whitespace?
*
* @param string $char
* @return bool
*/
function is_space(string $char): bool
{
return match($char) {
RawKeyCode::CARRIAGE_RETURN,
RawKeyCode::FORM_FEED,
RawKeyCode::NEWLINE,
RawKeyCode::SPACE,
RawKeyCode::TAB,
RawKeyCode::VERTICAL_TAB => true,
default => false,
};
}
// ----------------------------------------------------------------------------
// ! Helper functions
// ----------------------------------------------------------------------------
/**
* Does the one-character string contain a character that separates tokens?
*
* @param string $char
* @return bool
*/
function is_separator(string $char): bool
{
if ( ! is_ascii($char))
{
return FALSE;
}
$isSep = str_contains(',.()+-/*=~%<>[];', $char);
return is_space($char) || $char === RawKeyCode::NULL || $isSep;
}
/**
* Replaces a slice of an array with the same value
*
* @param array $array The array to update
* @param int $offset The index of the first location to update
* @param int $length The number of indices to update
* @param mixed $value The value to replace in the range
*/
function array_replace_range(array &$array, int $offset, int $length, mixed $value):void
{
if ($length === 1)
{
$array[$offset] = $value;
return;
}
$replacement = array_fill(0, $length, $value);
array_splice($array, $offset, $length, $replacement);
}
/**
* Does the string $haystack contain $str, optionally searching from $offset?
*
* @param string $haystack
* @param string $str
* @param int|null $offset
* @return bool
*/
function str_has(string $haystack, string $str, ?int $offset = NULL): bool
{
if (empty($str))
{
return FALSE;
}
return ($offset !== NULL)
? strpos($haystack, $str, $offset) !== FALSE
: \str_contains($haystack, $str);
}
/**
* Get the ASCII color escape number for the specified syntax type
*
* @param int $hl
* @return int
*/
function syntax_to_color(int $hl): int
{
return match ($hl)
{
Highlight::COMMENT => Color::FG_CYAN,
Highlight::ML_COMMENT => Color::FG_BRIGHT_BLACK,
Highlight::KEYWORD1 => Color::FG_YELLOW,
Highlight::KEYWORD2 => Color::FG_GREEN,
Highlight::STRING => Color::FG_MAGENTA,
Highlight::CHARACTER => Color::FG_BRIGHT_MAGENTA,
Highlight::NUMBER => Color::FG_BRIGHT_RED,
Highlight::OPERATOR => Color::FG_BRIGHT_GREEN,
Highlight::VARIABLE => Color::FG_BRIGHT_CYAN,
Highlight::DELIMITER => Color::FG_BLUE,
Highlight::INVALID => Color::BG_BRIGHT_RED,
Highlight::MATCH => Color::INVERT,
Highlight::IDENTIFIER => Color::FG_BRIGHT_WHITE,
default => Color::FG_WHITE,
};
}
/**
* Replace tabs with the specified number of spaces.
*
* @param string $str
* @param int $number
* @return string
*/
function tabs_to_spaces(string $str, int $number = KILO_TAB_STOP): string
{
return str_replace(RawKeyCode::TAB, str_repeat(RawKeyCode::SPACE, $number), $str);
}
function error_code_name(int $code): string
{
return match ($code) {
E_ERROR => 'Error',
E_WARNING => 'Warning',
E_PARSE => 'Parse Error',
E_NOTICE => 'Notice',
E_CORE_ERROR => 'Core Error',
E_CORE_WARNING => 'Core Warning',
E_COMPILE_ERROR => 'Compile Error',
E_COMPILE_WARNING => 'Compile Warning',
E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_RECOVERABLE_ERROR => 'Recoverable Error',
E_DEPRECATED => 'Deprecated',
E_USER_DEPRECATED => 'User Deprecated',
default => 'Unknown',
};
}
function saturating_add(int $a, int $b, int $max): int
{
return ($a + $b > $max) ? $max : $a + $b;
}
function saturating_sub(int $a, int $b): int
{
if ($b > $a)
{
return 0;
}
return $a - $b;
}