Как передать значение из красного / системного в красный?

Мне нужно передать значение, которое я генерирую в Red/System, в Red. Я обнаружил документы, но не нашел примера, как им пользоваться. Вот мой код:

Red []

#system [   
    data!: alias struct! [
        a   [integer!]
        b   [c-string!]
    ] 

    data: declare data!

    _foo: func [return: [data!]]
    [
        data/a: 123
        data/b: "Hello"
        return data
    ]

]

sqlite: context
 [

    my-red-block: []; I want to place here: 123 "Hello"

    foo: routine [
        /local
        x [data!]
    ]
    [
        x: _foo
        ; next line do now work
        ; push my-red-block x/a
    ]
 ]

view [button "Select" [sqlite/foo]] 

my-red-block вот красный block которую я хочу заполнить данными из Red/System part.

https://github.com/meijeru/red.specs-public/blob/master/specs.adoc

1 ответ

Решение

вступление

Красный использует стек данных для передачи аргументов и возврата результата. Каждое значение в стеке представляет собой коробочную структуру размером 4 указателя платформы и может содержать ссылки на внешние буферы; это означает, что вам необходимо создать их и поместить в стек, хотя некоторые примитивные типы Red/System (например,logic! или integer!) продвигаются автоматически, если вы их вернете.

Однако в вашем случае использование стека не обязательно, поскольку вы хотите распределять значения непосредственно в блоке. Опыт низкоуровневого программирования и знание Red/System с Red Runtime API являются необходимыми предпосылками для выполнения этой задачи. Итак, давайте рассмотрим ваш пример шаг за шагом.

Распаковка

  1. У вас есть блок, и вы хотите добавить к нему два значения, 123 а также "Hello". Предположим, вы хотите сделать это из Red/System. Для этого нам нужно написать процедуру.
    list: []
    foo: routine [][...]
    
  2. Внутри этой процедуры вам необходимо получить блок, на который ссылается listслово. Сложный способ сделать это - создать экземпляр символа и найти значение в глобальном контексте по его идентификатору:

    list: []
    
    foo: routine [
        /local
            blk [red-block!]
    ][
        blk: as red-block! _context/get-global symbol/make "list"
    ]
    

    Проходящий list в качестве аргумента было бы более разумным, но я оставлю его как есть в образовательных целях.

  3. Теперь мы хотим добавить 123в этот блок. Естьblock/rs-appendфункция, которая делает именно это, но принимает аргумент в рамке. Итак, нам нужно боксировать123 мы в первую очередь.

    1. Вот как выглядит упакованное целое число; как видите, это просто 32-битный123значение + заголовок слота и отступ. Мы можем сами построить и инициализировать такую ​​структуру:
      int: stack/push*         ; allocate slot on data stack
      int/header: TYPE_INTEGER ; set datatype
      int/value: 123           ; set value
      
      К счастью, среда выполнения Red уже покрывает это integer/box функция, которая принимает Красный / Системный integer! и возвращает упакованный red-integer! структура:
      integer/box 123
      
    2. Теперь нам нужно добавить это целое число в рамку к блоку. Интуитивно мы можем проверить 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
    ]
    
  4. Теперь мы хотим добавить "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 еще не стабилизирован, поэтому в настоящий момент не время задокументировать его и отразить проектные решения. Однако опытные разработчики могут довольно быстро сориентироваться, но для этого требуется твердое концептуальное понимание оценочной модели Red - эти основы - это то, что вам нужно освоить в первую очередь.

Также существует множество привязок библиотек, из которых вы можете поучиться - судя по исходному примеру, вы пытаетесь создать интерфейс CRUD View поверх SQLite.

Другие вопросы по тегам