Как передать блок с контекстом в рутину? - PullRequest
0 голосов
/ 17 июня 2020

Продолжаю изучать Red / System. И теперь я пытаюсь понять, как передать слово с контекстом для работы.

Вот мой код:

Red [Note: "compile in release mode (-r flag)"]

mycontext: context [
    list: []
]

foo: routine [
    blk 
    /local        
    int [integer!]
    str [c-string!]
][
    blk: as red-block! _context/get-any <CONTEXTHERE> symbol/make "list" ; ?? <CONTEXTHERE>
    int: 123
    str: "Hello"

    block/rs-append blk as red-value! integer/box int
    string/load-in str length? str blk UTF-8
]

foo mycontext ; passing context to foo
probe mycontext

Этот код не работает, потому что список помещен в mycontext. Пример передачи list без контекста можно найти здесь

Я пробовал разные подходы, но каждый раз получал ошибку.

https://github.com/red/red/blob/master/runtime/datatypes/structures.reds#L188

1 Ответ

2 голосов
/ 17 июня 2020

Во-первых, спецификация типа вашей подпрограммы неверна (об этом сообщает сообщение об ошибке):

Compiling to native code...
*** Compilation Error: invalid definition for function exec/foo: [
    blk [red-red-block!]
    /local
    int [integer!]
    str [c-string!]
]

Компилятор автоматически ставит префикс red-* для аргументов подпрограммы, поэтому правильная спецификация должна быть:

foo: routine [
    blk [block!]
    /local        
        int [integer!]
        str [c-string!]
][
    ...
]

Во-вторых, это тоже неверно; вы передаете object!, а не block!:

*** Compilation Error: datatype not allowed

Это означает, что нужно написать:

foo: routine [
    obj [object!]
    /local        
        int [integer!]
        str [c-string!]
][
    ...
]

Теперь, как я понимаю, вы хотите получить удерживать этот пустой блок, на который ссылается list, и добавлять к нему значения. Для этого требуется контекстный узел

obj/ctx

и идентификатор символа

symbol/make "list"

Имея два на месте, мы можем позвонить на _context/get-any:

foo: routine [
    obj [object!]
    /local
        blk [red-block!]
        int [integer!]
        str [c-string!]
][
    blk: as red-block! _context/get-any symbol/make "list" obj/ctx
    int: 123
    str: "Hello"

    block/rs-append blk as red-value! integer/box int
    string/load-in str length? str blk UTF-8
]

Альтернативным решением было бы построить значение word! с использованием word/load и вызвать object/rs-select:

foo: routine [
    obj [object!]
    /local
        blk [red-block!]
        int [integer!]
        str [c-string!]
][
    blk: as red-block! object/rs-select obj as red-value! word/load "list"
    int: 123
    str: "Hello"

    block/rs-append blk as red-value! integer/box int
    string/load-in str length? str blk UTF-8
]

Оба подхода дают ожидаемый результат:

make object! [
    list: [123 "Hello"]
]

Лично я бы не стал не усложняйте ситуацию так сильно и просто передайте блок в вашу рутину:

mycontext: context [
    list: []
]

foo: routine [
    blk [block!]
    /local
        int [red-integer!]
        str [c-string!]
][
    str: "Hello"
    int: as red-integer! stack/push*
    int/header: TYPE_INTEGER
    int/value: 123

    block/rs-append blk as red-value! int
    string/load-in str length? str blk UTF-8
]

foo mycontext/list
probe mycontext
...