Бібліотека stdl
імпортує вбудовані класи, об’єкти та функції, які необхідні для розробки програм на мові Mash Script, зокрема для роботи з рядками, введенням-виведенням, математичними операціями та іншими можливостями.
У цій публікації акцент робиться на огляді функціоналу, доступного в бібліотеці stdl
, а не на базовому синтаксисі. Це зроблено для зручності, щоб ви могли швидко знайти інформацію про те, що міститься в цій бібліотеці, без зайвих пояснень, які можна знайти у інших відповідних довгочитах.
Імпорти
Ось фрагмент коду з імпортом всіх необхідних класів. Ви можете скопіювати цей код до своєї програми замість імпортування stdl, і все має працювати належним чином.
use Array as array; // Масиви
use Dict as dict; // Словники
use Number as number; // Дробові та цілі числа
use String as string; // Рядки
use Boolean as boolean; // Булеве значення (true, false)
use Type as type; // Клас, який описує тип
use Module as module; // Клас, який описує модуль
use Function as function; // Клас, який описує функцію
use null; // Клас null (Нічого)
use NaN; // Клас NaN (Не число)
use Console; // Клас для керування консоллю
use In; // Клас для введення даних з клавіатури
use Out; // Клас для виведення даних на консоль
use Math; // Аналог 'math' у python
Ключове слово use
імпортує класи з Python для використання в Mash Script. Зверніть увагу, що клас має бути написаний за спеціальними правилами. Ми ще повернемося до цієї теми в майбутньому.
Найближчим часом на цьому профілі буде опубліковано докладний огляд усіх базових типів даних.
Функції
Функція isinstance
Функція isinstance
призначена для перевірки типу об'єкта obj__
на відповідність одному чи декільком типам, які передаються у параметрі type_or_array
.
boolean isinstance(obj__: dynamic, type_or_array: type | array[type]) {
if(typeof(type_or_array) == array) {
ret obj__.__type__ in type_or_array;
}
else {
ret obj__.__type__ == type_or_array;
}
}
Якщо type_or_array
є одним типом, функція перевіряє, чи співпадає тип об'єкта obj__
з переданим типом і повертає true
або false
відповідно.
Якщо type_or_array
є масивом типів, функція перевіряє, чи належить тип об'єкта obj__
хоча б одному з типів масиву і також повертає true
або false
:
isinstance('Рядок 1', [number, string]) // true
isinstance('Рядок 2', string) // true
isinstance('Рядок 3', [number, boolean]) // false
Функція assert
Функція assert
використовується під час налагодження коду для перевірки, чи є умова істинною. Якщо умова не виконується (повертає false
), то генерується виключення AssertionError
.
void assert(condition: boolean, msg: string='') {
if(!condition) {
Console.error('AssertionError', msg);
}
}
Наприклад, ви можете використовувати assert
для перевірки передумов перед викликом функції, як показано в прикладі нижче:
assert(x > 0, "Значення 'x' має бути більше нуля");
Функція length
Викликати метод __length__
у об'єктів array
, string
та інших не дуже зручно. Тому існує функція length
, аналогічна len
у Python.
int length(object_: dynamic) {
ret object_.__length__();
}
length('Hello') // 5
length([1, 2, 3]) // 3
Функція split
Функція split
розділяє об'єкт на n
частин.
Аргументи:
object_
:dynamic
— об'єкт, який потрібно розділити.n
:int
— кількість частин, на які потрібно розділити об'єкт.
Повертає:
Масив, що містить
n
частин об'єкту. Якщо об'єкт не може бути розділений рівно наn
частин, залишкова частина додається як останній елемент масиву.
Функція створює масив pieces
, який містить перші n
елементів об'єкту, та масив other
, який містить залишкову частину. Потім функція об'єднує ці два масиви та повертає результат.
array split(object_: dynamic, n: int) {
var pieces: array = [object_[i] for(i in range(n))];
var other: array = object_[length(pieces) : ];
ret [*pieces, other];
}
Приклади:
split('Hello Name!', 4) // поверне ['H', 'e', 'l', 'l', 'o Name!'].
split('string', 6) // поверне ['s', 't', 'r', 'i', 'n', 'g', ''].
В наступному прикладі змінні name та age отримають значення 'Steve' та 23, а other буде масивом ['Cook', 'Paris'].
array user = ['Steve', 23, 'Cook', 'Paris'];
string name, age, other = *split(user, 2);
Функція table
Функція table
призначена для створення таблиці з заданими аргументами та організації їх у вказану кількість стовпців.
Аргументи:
[args]
:dynamic
— Аргументи, які будуть відображені у таблиці.columns
:int
— Кількість стовпців у таблиці. За замовчуванням: 2.{kwargs}
:dict
— Додаткові іменовані аргументи, передані в Out.table.
Повертає:
string: повертає таблицю у вигляді рядка.
string table([args], {kwargs}, columns: int=2) {
if(columns < 0)
return;
int col = 0;
array result = [[]];
foreach(string item in args) {
Out.println(item, col, result);
if(col == columns) {
col = 0;
result << [];
}
result[-1] << item;
col++
}
ret Out.table(result, *kwargs, file=null);
}
Приклад перший, таблиця 3 на 2:
table(1, 2, 3,
4, 5, 6,
columns=3);
Повертає рядок:
╭───┬───┬───╮
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
╰───┴───┴───╯
Приклад другий, таблиця 2 на 3:
table('Name:', 'Age:',
'Steve', '23',
'Alex', '54',
tablefmt='html');
Повертає рядок:
<table>
<tbody>
<tr><td>Name:</td><td>Age:</td></tr>
<tr><td>Steve</td><td>23 </td></tr>
<tr><td>Alex </td><td>54 </td></tr>
</tbody>
</table>
Класи
Клас Data
Клас Data
реалізує функціонал, схожий на об'єкти JavaScript.
class Data {
/* ... */
string __string__() {
return this.__dict__ &'';
}
}
Приклад:
void main() {
Data flower = new[] Data {
name: 'Ромашка',
image: 'https://www.google.com/...',
other_names: ['роман', 'ромен', 'невістка', 'рум`янок']
}
Out.println(flower);
}
Результат:
{'name': 'Ромашка', 'image': 'https://www.google.com/...', 'other_names': ['роман', 'ромен', 'невістка', 'рум`янок']}
Весь файл
/*
*
* Stdlib
*
* This module provides the standard library for Mash Script.
*
*/
use Array as array;
use Dict as dict;
use Tuple as tuple;
use Int as int;
use Float as float;
use Number as number;
use String as string;
use Boolean as boolean;
use Type as type;
use Module as module;
use Function as func;
use Pointer as pointer;
use Namespace as nspace;
use null as t_Null;
use Console;
use In;
use Out;
use Math;
use Random;
use BaseError;
use Error;
use IndexError;
use ConnectionError;
use StopIteration;
use TypeError;
use AttributeError;
use Enum;
/* variables */
string endl = '\n';
number Infinity = number.Infinity;
number NaN { "nan" };
t_Null null {};
type void = t_Null.Void;
/* dyn i;
i = 0; Ok!
i = ""; Ok! */
type[object] dyn = object;
/* any i;
i = 0; Ok!
i = ""; Err */
type[t_Null] any = t_Null;
type[type] subtype = type;
func[func] wraps(original: func)
{
func wrapper(function: func)
{
function.set_name(original.get_name());
ret function;
}
ret wrapper;
}
func[dyn] classmethod(function: func)
{
@wraps(function)
dyn wrapper(this: type, [args], {kwargs})
{
if(!this is type)
{
throw TypeError('the first argument must be a class type, but got {cls.__name__}() object.');
}
ret function(this, ..args, ..kwargs);
}
ret wrapper;
}
func[dyn] instance_method(function: func)
{
@wraps(function)
dyn wrapper(this: type, [args], {kwargs})
{
if(this is type)
{
throw TypeError('the first argument must be a object, but got type[{this.__name__}]');
}
ret function(this, ..args, ..kwargs);
}
ret wrapper;
}
class AssertionError : Error
{ }
class NoReturn
{
void __new__()
{
throw Error("Class 'NoReturn' cannot be instantiated.");
}
}
class Singleton
{
dyn __new__()
{
if(!hasattr(this, "__instance"))
this.__instance = object-> __new__(this);
ret this.__instance;
}
}
class Static
{
NoReturn __new__()
{
throw Error('Class "{this.__name__}" cannot be instantiated.');
}
}
class Optional
{
class NullOptionalError : Error
{
void __init__()
{
this.message = "Optional object does not contain any value";
}
}
@classmethod
void __prepare__()
{
this.__null_value = null;
this.__null_optional = this(this.__null_value);
}
void __init__(value: dyn=null)
{
this.__value = value;
}
@classmethod
dyn empty()
{
ret this.__null_optional;
}
@instance_method
boolean is_present()
{
ret !this.is_empty();
}
@instance_method
boolean is_empty()
{
ret this.__value == this.__null_value;
}
dyn or_else_throw(error: BaseError=null)
{
if(error == null)
error = this.NullOptionalError;
if(this.is_empty())
throw error();
}
dyn if_present(function: func)
{
if(this.is_empty())
ret;
ret function(this.__value);
}
dyn or_else(function: func, __default: dyn)
{
if(this.is_empty())
ret function(__default);
ret function(this.__value);
}
dyn get(__default: dyn=null)
{
if(this.is_empty())
ret __default;
ret this.__value;
}
dyn filter(function: func[boolean])
{
if(this.if_present(function))
{
ret this;
}
else
{
ret this.__null_optional;
}
}
}
/*
class Range
{
void __init__(start: int, stop: int=null, step: int=1)
{
if(stop == null)
start, stop = 0, start;
if(start > stop)
step = -step;
}
}
*/
/* functions */
void assert(condition: boolean, msg: string="")
{
if(!condition)
throw AssertionError(msg);
}
int length(object_: dyn)
{
ret object_.__length__();
}
namespace std
{
class RandomPicker
{
void __init__(list: array[dyn])
{
this.list = list.copy();
this.buffer = [];
}
dyn pick()
{
int index = Random.randint(0, length(this.list)-1);
dyn result = this.list.pop(index);
this.buffer << result;
if(length(this.list) == 0)
{
this.list = this.buffer;
this.buffer = [];
}
ret result;
}
}
class DictUnion
{
void __init__([mro])
{
this.__mro = mro;
}
dyn __extract__(attribute: string)
{
foreach(dyn obj in this.__mro)
{
try
{
ret obj[attribute];
}
catch(Error as error)
{
next;
}
}
throw AttributeError('None of the {length(this.__mro)} objects in "{this.__name__}" have the attribute "{attribute}"');
}
dyn __getitem__(attribute: string)
{
ret this.__extract__(attribute);
}
}
class TypeUnion
{
type __new__([mro])
{
type[Union] t = newtype(this.__name__, {}, cls, mro);
t.__mro = mro;
ret t;
}
dyn __extract__(attribute: string)
{
foreach(type t in this.__mro)
{
try
{
ret getattr(t, attribute);
}
catch(Error as error)
{
next;
}
}
throw AttributeError('None of the {length(this.__mro)} objects in "{this.__name__}" have the attribute "{attribute}"');
}
dyn __getitem__(attribute: string)
{
ret this.__extract__(attribute);
}
}
func[void] bind_ptr(result: pointer[dyn], function: func[dyn], [args], {kwargs})
{
void wrapper([args], {kwargs})
*result = function(..(->args), ..args, ..(->kwargs), ..kwargs);
ret wrapper;
}
array split(object_: dyn, n: int)
{
` split(object: dyn, n: int) -> array
Splits an object into n pieces.
Arguments:
- object_: dyn - The object to split.
- n: int - The number of pieces to split the object into.
Returns:
- array - An array containing n pieces of the object. If the object cannot be evenly split into n pieces, the remaining part is appended as the last element of the array.
Example 1:
split('Hello Name!', 4) => ['H', 'e', 'l', 'l', 'o Name!']
Example 2:
split('string', 6) => ['s', 't', 'r', 'i', 'n', 'g', '']
Example 3:
array user = ['Steve', 23, 'Cook', 'Paris'];
string name, age, other = ..split(user, 2);
// prints: Steve 23 ['Cook', 'Paris']
Out.print(name, age, other);
`;
array pieces = [object_[i] for(i in range(n))];
array other = object_[length(pieces) : ];
ret [..pieces, other];
}
string table([args], {kwargs}, columns: int=2)
{
` tabletable([args], \{kwargs\}, columns: int=2) -> string
Returns a table with the given arguments, organizing them into the specified number of columns.
Arguments:
- [args]: dyn - The arguments to be displayed in the table.
- columns: int - The number of columns in the table. Default is 2.
- \{kwargs\}: dict - Additional keyword arguments passed to Out.table.
Returns:
- string: returns the table as a string.
Example 1: ╭───┬───┬───╮
table(1, 2, 3, │ 1 │ 2 │ 3 │
4, 5, 6, => ├───┼───┼───┤
columns=3 │ 4 │ 5 │ 6 │
); ╰───┴───┴───╯
Example 2:
table('Name:', 'Age:',
'Steve', '23',
'Alex', '54',
tablefmt='html');
// returns:
<table>
<tbody>
<tr><td>Name:</td><td>Age:</td></tr>
<tr><td>Steve</td><td>23 </td></tr>
<tr><td>Alex </td><td>54 </td></tr>
</tbody>
</table>
`;
if(columns < 0)
ret;
int col { };
array result = [[]];
foreach(string item in args)
{
if(col == columns)
{
col = 0;
result << [];
}
result[-1] << item;
col++
}
ret Out.table(result, *kwargs, file=false);
}
}
Підсумок
Завдяки бібліотеці stdl, розробники можуть швидко створювати програми на мові Mash Script за допомогою функцій та класів, які надає ця бібліотека. Тут також вже вказані імпорти всіх основних класів. Детальні описи кожного елементу бібліотеки надаються в окремих довгочитах.