Intro
Red использует стек данных для передачи аргументов и возврата результата. Каждое значение в стеке представляет собой коробочную структуру размером 4 указателя платформы и может содержать ссылки на внешние буферы; это означает, что вам нужно создать их и поместить sh в стек, хотя некоторые примитивные типы Red / System (например, logic!
или integer!
) автоматически повышаются, если вы их возвращаете.
Однако в вашем случае использование стека не обязательно, поскольку вы хотите распределять значения непосредственно в блоке. Опыт программирования на низком уровне и знание Red / System с Red runtime API являются необходимыми предпосылками для этой задачи. Итак, давайте рассмотрим ваш пример и go шаг за шагом.
Распаковка
- У вас есть блок, и вы хотите добавить к нему два значения:
123
и "Hello"
. Предположим, вы хотите сделать это из Red / System. Для этого нам нужно написать процедуру. list: []
foo: routine [][...]
Внутри этой процедуры вам нужно получить блок, на который ссылается list
word. Сложный способ сделать это - создать экземпляр символа и найти значение в глобальном контексте по его идентификатору:
list: []
foo: routine [
/local
blk [red-block!]
][
blk: as red-block! _context/get-global symbol/make "list"
]
Передача list
в качестве аргумента была бы более разумной, но я оставлю его как есть для образовательных целей.
Теперь мы хотим добавить 123
к этому блоку. Есть функция block/rs-append
, которая делает именно это, но принимает аргумент в рамке. Итак, нам нужно сначала поместить себя в коробку 123
.
- Это - вот как выглядит упакованное целое число; как видите, это просто 32-битное
123
значение + заголовок слота и отступы. Мы можем создать и инициализировать такую структуру сами: int: stack/push* ; allocate slot on data stack
int/header: TYPE_INTEGER ; set datatype
int/value: 123 ; set value
К счастью, среда выполнения Red уже покрывает это с помощью integer/box
функции, которая принимает Red / System integer!
и возвращает упакованную red-integer!
структуру: integer/box 123
- Теперь нам нужно добавить это целое число в рамку к блоку. Интуитивно мы можем проверить
block.reds
определения и найти block/rs-append
, которое соответствует нашим требованиям: block/rs-append blk as red-value! integer/box 123
В конце этого шага мы имеем:
list: []
foo: routine [
/local
blk [red-block!]
][
blk: as red-block! _context/get-global symbol/make "list"
block/rs-append blk as red-value! integer/box 123
]
Теперь мы хотим добавить строку "Hello"
, но сначала нам нужно ее построить. Красные строки поддерживают UTF-8 и используют внутреннюю кодировку фиксированного размера (1, 2 или 4 байта на символ, в зависимости от максимального размера кодовой точки); это много деталей, которые нужно исправить вручную, поэтому типичный способ создания такой строки - преобразовать ее из c-string!
.
list: []
foo: routine [
/local
blk [red-block!]
str [c-string!]
][
blk: as red-block! _context/get-global symbol/make "list"
block/rs-append blk as red-value! integer/box 123
str: "Hello"
]
Изучая string!
определения времени выполнения типов данных , вы заметите несколько удобных оболочек с префиксом load
; это соглашение, указывающее, что такая функция может использоваться для построения (т.е. «загрузки») высокоуровневого значения Red из низкоуровневых частей Red / System, в нашем случае red-string!
из c-string!
. Поскольку мы хотим построить его в конце блока, мы можем использовать string/load-in
:
str: "Hello"
string/load-in str length? str blk UTF-8
Обратите внимание, что я использую length?
вместо size?
, чтобы исключить байт с завершающим NUL.
Заключение
Вот и все. В конце дня мы можем немного привести код в порядок и проверить, работает ли он вообще:
Red [Note: "compile in release mode (-r flag)"]
list: []
foo: routine [
/local
blk [red-block!]
int [integer!]
str [c-string!]
][
blk: as red-block! _context/get-global symbol/make "list"
int: 123
str: "Hello"
block/rs-append blk as red-value! integer/box int
string/load-in str length? str blk UTF-8
]
foo
probe list
Компиляция этого скрипта в режиме выпуска и выполнение полученного двоичного файла из оболочки дает нам ожидаемый результат :
[123 "Hello"]
Излишне говорить, что все это может показаться новичкам довольно ошеломляющим: хотя и Red, и Red / System имеют приличную документацию и обучающие ресурсы, их объединение посредством взаимодействия во время выполнения - неизведанная территория. Причина в том, что проект развивается, а API еще не стабилизирован, поэтому в настоящий момент не время задокументировать его и отлить дизайнерские решения в камне. Опытные разработчики могут довольно быстро сориентироваться, но для этого требуется solid концептуальное понимание оценочной модели Red - эти основы - то, что вам нужно сначала освоить.
Существует также множество привязок библиотек , из которых вы можете поучиться - судя по исходному примеру, вы пытаетесь создать интерфейс CRUD View поверх SQLite.