{"id":163,"date":"2014-09-15T16:40:53","date_gmt":"2014-09-15T16:40:53","guid":{"rendered":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/?p=163"},"modified":"2016-04-04T09:01:47","modified_gmt":"2016-04-04T09:01:47","slug":"writing-simple-primitives","status":"publish","type":"post","link":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/?p=163","title":{"rendered":"Writing simple primitives"},"content":{"rendered":"<p>The language of Orchids includes several primitives, but you may want to add new ones.<\/p>\n<p>The main primitives of Orchids are coded in <code>lang.c<\/code>. Some others are provided by modules.\u00a0 Let us look at a simple example, that of the function <code>int_from_str<\/code>, which converts a string such as <code>\"12\"<\/code> to the corresponding integer (12 here).<!--more--><\/p>\n<p>In writing a primitive, you should first decide of its type.\u00a0 This is a good safeguard again bugs, and will be needed at the end of this post.\u00a0 The <code>int_from_str<\/code> function should take a string (either a string or a virtual string) and return an integer.<\/p>\n<p>We then start to write the primitive.\u00a0 Let us name it <code>issdl_int_from_str<\/code>. We write:<\/p>\n<pre>static void issdl_int_from_str(orchids_t *ctx, state_instance_t *state,\r\n                               void *data)\r\n{\r\n\u00a0 ovm_var_t *str;\r\n\u00a0 ovm_var_t *i;\r\n\r\n<\/pre>\n<p>The\u00a0<code>ctx<\/code>\u00a0parameter holds the general Orchids context, as for most other Orchids functions, and\u00a0<code>state<\/code>\u00a0holds the current state of the machine. \u00a0We shall use the latter mostly to handle the machine&#8217;s stack: all primitives consume their arguments from the stack and push back the result onto the stack. \u00a0I will discuss the\u00a0<code>data<\/code>\u00a0parameter much later in this post, and only briefly.<\/p>\n<p>The variable <code>i<\/code> will eventually hold the result. As I said, our primitive will take its arguments from the Orchids stack. \u00a0We get the value of our unique\u00a0argument, from the stack, into <code>str<\/code>\u00a0as follows:<\/p>\n<pre>\u00a0\u00a0 str = (ovm_var_t *)STACK_ELT(ctx-&gt;ovm_stack, 1);<\/pre>\n<p>Here <code>ctx-&gt;ovm_stack<\/code> is the stack of the Orchids virtual machine.\u00a0 We get our arguments from the stack.\u00a0 We shall also need to pop the arguments from the stack and push the result back, see below.\u00a0 For now, we just read elements from the stack using the <code>STACK_ELT<\/code> macro.<\/p>\n<p>In case we had several arguments, you should pay attention to the fact that <code>STACK_ELT(ctx-&gt;ovm_stack, 1)<\/code> returns the <em>last<\/em> argument.\u00a0 <code>STACK_ELT(ctx-&gt;ovm_stack, 2)<\/code> returns the next-to-last argument, and so on. For example, to obtain the three arguments of a 3 argument function, you should write <code>arg3 = (ovm_var_t *)STACK_ELT(ctx-&gt;ovm_stack, 1); arg2 = (ovm_var_t *)STACK_ELT(ctx-&gt;ovm_stack, 2); arg1 = (ovm_var_t *)STACK_ELT(ctx-&gt;ovm_stack, 3);<\/code>.<\/p>\n<p>There is another macro (<code>STACK_POP<\/code>) that allows you to read the element at the top of the stack and pop it at the same time.\u00a0 Don&#8217;t use it unless you really know what you do.\u00a0 The nice thing about <code>STACK_ELT<\/code> is that, since it keeps the element read on the stack, it won&#8217;t be freed by the <a title=\"Garbage collection\" href=\"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/?p=18\">garbage-collector<\/a>: anything on the stack is considered in use, and won&#8217;t be freed.<\/p>\n<p>&nbsp;<\/p>\n<hr \/>\n<p>&nbsp;<\/p>\n<p>Now we convert the string to an integer, using the <code>orchids_atoi<\/code> function. This works just like <code>atoi<\/code>, except the string need not be 0-terminated. Recall that Orchids strings are given with an explicit length.<\/p>\n<p>Before we do so, though, we must check that <code>str<\/code> is not <code>NULL<\/code>. Indeed, any argument may be <code>NULL<\/code>, as a result of a run-time error typically (division by zero, type error, etc.)<\/p>\n<p>We therefore write:<\/p>\n<pre>  if (str==NULL)\r\n    {\r\nerr:\r\n      DebugLog(DF_OVM, DS_DEBUG, \"issdl_int_from_str(): param error\\n\");\r\n      STACK_DROP(ctx-&gt;ovm_stack, 1);\r\n      PUSH_VALUE(ctx, NULL);\r\n    }\r\n<\/pre>\n<p>The call to the macro <code>DebugLog<\/code> is not necessary, but helps in case of bugs.<\/p>\n<p>(By the way, this is not the actual code. I modified it so as to make it easier to explain how you <em>could<\/em> write it.)<\/p>\n<p>Note that even though this is an error case, we still have to pop the argument from the stack, using <code>STACK_DROP<\/code>, and push a value: here, <code>NULL<\/code>, since we ran into an error.<\/p>\n<p>If we had been given three arguments, we should have called <code>STACK_DROP(ctx-&gt;ovm_stack, 3)<\/code>, as you might expect.<\/p>\n<p>&nbsp;<\/p>\n<hr \/>\n<p>&nbsp;<\/p>\n<p>We also explicit check the type.\u00a0 This is not needed, since Orchids embeds a static type-checker that guarantees that the function will only ever be called with the right type.\u00a0 I will do as though we needed to check the type at run-time (this switch is anyway needed to handle the difference between real and virtual strings, I will discuss this below):<\/p>\n<pre>  else switch (TYPE(str))\r\n    {\r\n      long value;\r\n\r\n      case T_STR:\r\n        value = orchids_atoi(STR(str), STRLEN(str));\r\n<\/pre>\n<p>We now build an Orchids integer value, pop the stack, and push the resulting value:<\/p>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0   i = ovm_int_new(ctx-&gt;gc_ctx, value);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0   STACK_DROP(ctx-&gt;ovm_stack, 1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0   PUSH_VALUE(ctx,i);\r\n        break;<\/pre>\n<p>Let me stress another point.\u00a0 Since the argument to <code>int_from_str<\/code> is meant to be a string, it can actually be either a <a title=\"The ovm_str_t type\" href=\"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/?p=50\">real string<\/a> or a <a title=\"The ovm_vstr_t type\" href=\"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/?p=53\">virtual string<\/a>, and <em>both<\/em> cases must be handled, with results that should look identical to the outside observer.\u00a0 So we proceed and do\u00a0the same thing for virtual strings:<\/p>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0 case T_VSTR:\r\n        value = orchids_atoi(VSTR(str), VSTRLEN(str));\r\n        i = ovm_int_new(ctx-&gt;gc_ctx, value);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0   STACK_DROP(ctx-&gt;ovm_stack, 1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0   PUSH_VALUE(ctx,i);\r\n        break;\r\n      default:\r\n        goto err; \/\/ No need to duplicate code\r\n    }\r\n}<\/pre>\n<p>The code of our primitive is ready.<\/p>\n<p>&nbsp;<\/p>\n<hr \/>\n<p>&nbsp;<\/p>\n<p>The final step is to make sure that Orchids <em>knows<\/em> about our primitive.\u00a0 We must link it into Orchids&#8217; virtual machine.\u00a0 There are several ways to do that.<\/p>\n<ul>\n<li>If you are writing an Orchids module, the simplest way is probably to call <code>register_lang_function<\/code> in your module&#8217;s preconfig code. Here, write:\n<pre>register_lang_function(ctx, issdl_int_from_str, \"int_from_str\",\r\n                       1, int_of_str_sigs,\r\n                       m_unknown_1,\r\n                       \"convert a string to the integer it represents in decimal.\"\r\n                       NULL);\r\n<\/pre>\n<p>where <code>ctx<\/code> is the Orchids context, <code>issdl_int_from_str<\/code> is our function, <code>m_unknown_1<\/code> is a function pointer that instructs Orchids about the monotonicity of the <code>int_of_str_sigs<\/code> function, <code>\"int_from_str\"<\/code> is the name by which we wish to call it in Orchids signatures, <code>1<\/code> is its expected number of arguments,\u00a0<code>int_of_str_sigs<\/code> is required for static type-checking (see below), the final string is a documentation string, and the final parameter (here,\u00a0<code>NULL<\/code>) will be passed as the\u00a0<code>data<\/code>\u00a0argument to\u00a0<code>issdl_int_from_str<\/code>. \u00a0(The latter is useful, for example, if you write a new primitive in a module, and you wish to use module-specific data in your primitive: pass the relevant\u00a0<code>mod_entry_t *<\/code>\u00a0data to\u00a0<code>register_lang_function()\u00a0<\/code>instead of\u00a0<code>NULL<\/code>; in the primitive, cast back its\u00a0<code>data<\/code>\u00a0argument to\u00a0<code>mod_entry_t *mod<\/code>, and obtain your private, module-specific data as\u00a0<code>mod-&gt;config<\/code>, say.)<\/p>\n<p>For the purposes of static type-checking,\u00a0<code>int_of_str_sigs<\/code> is an array of possible type signatures for our function.\u00a0 Our function has only one intended signature, namely it should map strings to ints.\u00a0 Here is this signature, as a C declaration:<\/p>\n<pre>static type_t *int_of_str_sig[] = { &amp;t_int, &amp;t_str };<\/pre>\n<p>The structs <code>t_int<\/code> and <code>t_str<\/code> are predefined, and mean <code>int<\/code> and <code>string<\/code> (either real or virtual), respectively.\u00a0 Beware that the return type comes <em>first<\/em>, followed by the list of argument types.\u00a0 There should be exactly <em>n<\/em>+1 pointers in this array, where <em>n<\/em> is the arity of the function.<br \/>\nFinally, we need to provide <code>register_lang_function()<\/code> with an <em>array<\/em> of possible type signatures, so the array we pass it as 5th argument is:<\/p>\n<pre>static type_t **int_of_str_sigs[] = { int_of_str_sig, NULL };<\/pre>\n<p>This is a <code>NULL-<\/code>terminated array of signatures. This kind of complication is needed for functions that have several signatures, such as comparison functions for example, whose array of signatures is:<\/p>\n<pre>static type_t **cmp_sigs[] = {\r\n  int_cmp_sig, uint_cmp_sig, ipv4_cmp_sig, ipv6_cmp_sig,\r\n  str_cmp_sig, bstr_cmp_sig, ctime_cmp_sig, timeval_cmp_sig,\r\n  float_cmp_sig, NULL\r\n};\r\n<\/pre>\n<\/li>\n<li>If you wish to add it to the code of Orchids, it is probably simpler to add it as a new row in the <code>issdl_function_g<\/code> table of known functions, in <code>lang.c<\/code>, say:\n<pre>  { issdl_int_from_str, <em>id<\/em>, \"int_from_str\", 1, int_of_str_sigs, m_unknown_1,\r\n    \"convert a string to the integer it represents in decimal.\", NULL },\r\n<\/pre>\n<p>The <em>id<\/em> field is unused. It was probably meant to be some sort of unique identification number, but does not serve any purpose actually.<\/li>\n<\/ul>\n<p>That&#8217;s it!\u00a0 Now you can use code such as <code>$x = int_from_str($y);<\/code> in your Orchids signatures.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The language of Orchids includes several primitives, but you may want to add new ones. The main primitives of Orchids are coded in lang.c. Some others are provided by modules.\u00a0 Let us look at a simple example, that of the function int_from_str, which converts a string such as &#8220;12&#8221; to the corresponding integer (12 here).<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-163","post","type-post","status-publish","format-standard","hentry","category-virtual-machine"],"_links":{"self":[{"href":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/index.php?rest_route=\/wp\/v2\/posts\/163","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=163"}],"version-history":[{"count":14,"href":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/index.php?rest_route=\/wp\/v2\/posts\/163\/revisions"}],"predecessor-version":[{"id":298,"href":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/index.php?rest_route=\/wp\/v2\/posts\/163\/revisions\/298"}],"wp:attachment":[{"href":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=163"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=163"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/projects.lsv.ens-paris-saclay.fr\/orchidsdev\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=163"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}