I need to pass the value that I generate in Red/System to Red. I discovered docs but did not find an example of how to use it. Here is my code:
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
here is Red block
that I want to fill with data from Red/System part.
https://github.com/meijeru/red.specs-public/blob/master/specs.adoc#routine-type
Intro
Red uses data stack to pass arguments and return the result. Each value on the stack is a boxed structure 4 platform pointers in size and may contain references to external buffers; this means that you need to construct them and push them on a stack, although some primitive Red/System types (like e.g.
logic!
orinteger!
) are promoted automatically if you return them.In your case, however, usage of the stack is not necessary, as you want to allocate values directly in a block. Experience with low-level programming and knowledge of Red/System with Red runtime API are the essential prerequisites for this task. So let's take your example and go through it step by step.
Unpacking
123
and"Hello"
. Suppose you want to do that from Red/System. For that, we need to write a routine.Inside this routine, you need to get hold of the block referenced by
list
word. The hard way to do that is to instantiate a symbol and look up the value in global context by its ID:Passing
list
as an argument would be more reasonable, but I'll keep it as-is for educational purposes.Now we want to append
123
to this block. There'sblock/rs-append
function that does exactly that, but it accepts a boxed argument. So we need to box123
ourselves first.123
value + slot header and padding. We can construct and initialize such structure ourselves: Fortunately, Red runtime already covers that withinteger/box
function that takes a Red/Systeminteger!
and returns a boxedred-integer!
struct:block.reds
definitions and findblock/rs-append
that matches our requirements: At the end of this step, we have:Now we want to append a
"Hello"
string, but first we need to construct it. Red strings support UTF-8 and use fixed-size internal encoding (1, 2 or 4 bytes per character, depending on the maximum codepoint size); that's a lot of details to get right manually, so the typical way of constructing such string is by converting it fromc-string!
.Examining
string!
datatype runtime definitions you will notice some handy wrappers prefixed withload
; this is a convention indicating that such function can be used to construct (i.e. "load") high-level Red value from low-level Red/System parts, in our casered-string!
fromc-string!
. Since we want to construct it at the tail of a block, we can usestring/load-in
:Note that I use
length?
instead ofsize?
to exclude NUL-terminated byte.Conclusion
This is it. At the end of the day we can tidy the code a little bit and check if it works at all:
Compiling this script in release mode and executing the resulting binary from the shell gives us the expected result:
Needless to say, this all might look quite overwhelming to newcomers: while both Red and Red/System have decent documentation and learning resources, their bridging via runtime interaction is uncharted territory. The reason for that is because the project is evolving and the API is not yet stabilized, so, at the moment, it's not the right time to document it and cast the design decisions in stone. Experienced developers can get their bearings pretty quickly though, but that requires a solid conceptual understanding of Red's evaluation model -- these basics are what you need to master first.
There's also a plethora of library bindings that you can learn from -- judging by the original example, you are trying to make a CRUD View interface on top of SQLite.