summary refs log tree commit diff stats
path: root/lib/system/timers.nim
blob: ffb0f7716dec104d2bf7533bf0d2f8bdb36901e8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#
#
#            Nim's Runtime Library
#        (c) Copyright 2012 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## Timer support for the realtime GC. Based on
## `<https://github.com/jckarter/clay/blob/master/compiler/hirestimer.cpp>`_

type
  Ticks = distinct int64
  Nanos = int64

when defined(windows):

  proc QueryPerformanceCounter(res: var Ticks) {.
    importc: "QueryPerformanceCounter", stdcall, dynlib: "kernel32".}
  proc QueryPerformanceFrequency(res: var int64) {.
    importc: "QueryPerformanceFrequency", stdcall, dynlib: "kernel32".}

  proc getTicks(): Ticks {.inline.} =
    QueryPerformanceCounter(result)

  proc `-`(a, b: Ticks): Nanos =
    var frequency: int64
    QueryPerformanceFrequency(frequency)
    var performanceCounterRate = 1e+9'f64 / float64(frequency)

    result = Nanos(float64(a.int64 - b.int64) * performanceCounterRate)

elif defined(macosx) and not defined(emscripten):
  type
    MachTimebaseInfoData {.pure, final,
        importc: "mach_timebase_info_data_t",
        header: "<mach/mach_time.h>".} = object
      numer, denom: int32 # note: `uint32` in sources

  proc mach_absolute_time(): uint64 {.importc, header: "<mach/mach_time.h>".}
  proc mach_timebase_info(info: var MachTimebaseInfoData) {.importc,
    header: "<mach/mach_time.h>".}

  proc getTicks(): Ticks {.inline.} =
    result = Ticks(mach_absolute_time())

  var timeBaseInfo: MachTimebaseInfoData
  mach_timebase_info(timeBaseInfo)

  proc `-`(a, b: Ticks): Nanos =
    result = (a.int64 - b.int64) * timeBaseInfo.numer div timeBaseInfo.denom

elif defined(posixRealtime):
  type
    Clockid {.importc: "clockid_t", header: "<time.h>", final.} = object

    TimeSpec {.importc: "struct timespec", header: "<time.h>",
               final, pure.} = object ## struct timespec
      tv_sec: int  ## Seconds.
      tv_nsec: int ## Nanoseconds.

  var
    CLOCK_REALTIME {.importc: "CLOCK_REALTIME", header: "<time.h>".}: Clockid

  proc clock_gettime(clkId: Clockid, tp: var Timespec) {.
    importc: "clock_gettime", header: "<time.h>".}

  proc getTicks(): Ticks =
    var t: Timespec
    clock_gettime(CLOCK_REALTIME, t)
    result = Ticks(int64(t.tv_sec) * 1000000000'i64 + int64(t.tv_nsec))

  proc `-`(a, b: Ticks): Nanos {.borrow.}

else:
  # fallback Posix implementation:
  when not declared(Time):
    when defined(linux):
      type Time = clong
    else:
      type Time = int

  type
    Timeval {.importc: "struct timeval", header: "<sys/select.h>",
               final, pure.} = object ## struct timeval
      tv_sec: Time  ## Seconds.
      tv_usec: clong ## Microseconds.

  proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
    importc: "gettimeofday", header: "<sys/time.h>".}

  proc getTicks(): Ticks =
    var t: Timeval
    posix_gettimeofday(t)
    result = Ticks(int64(t.tv_sec) * 1000_000_000'i64 +
                    int64(t.tv_usec) * 1000'i64)

  proc `-`(a, b: Ticks): Nanos {.borrow.}
span>> &lt;- </span>add <span class="Constant">1</span><span class="Delimiter">,</span> <span class="Constant">12</span>:num ] <span class="traceContains">+mem: storing 3 in location 13</span> <span class="Delimiter">:(scenario next_ingredient_missing)</span> <span class="muRecipe">def</span> main [ f ] <span class="muRecipe">def</span> f [ _<span class="Delimiter">,</span> <span class="Constant">12</span>:num<span class="Special"> &lt;- </span>next-ingredient ] <span class="traceContains">+mem: storing 0 in location 12</span> <span class="Delimiter">:(before &quot;End call Fields&quot;)</span> vector&lt;vector&lt;<span class="Normal">double</span>&gt; &gt; ingredient_atoms<span class="Delimiter">;</span> vector&lt;reagent&gt; ingredients<span class="Delimiter">;</span> <span class="Normal">int</span> next_ingredient_to_process<span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End call Constructor&quot;)</span> next_ingredient_to_process = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Delimiter">:(before &quot;End Call Housekeeping&quot;)</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; SIZE<span class="Delimiter">(</span>ingredients<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span class="Delimiter">{</span> current_call<span class="Delimiter">().</span>ingredient_atoms<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span> reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> ingredient = call_instruction<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">);</span> <span class="Comment">// End Compute Call Ingredient</span> current_call<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>ingredient<span class="Delimiter">);</span> <span class="Comment">// End Populate Call Ingredient</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span> NEXT_INGREDIENT<span class="Delimiter">,</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span> put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;next-ingredient&quot;</span><span class="Delimiter">,</span> NEXT_INGREDIENT<span class="Delimiter">);</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span> <span class="Normal">case</span> NEXT_INGREDIENT: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Delimiter">{</span> raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'next-ingredient' didn't expect any ingredients in '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span> <span class="Normal">case</span> NEXT_INGREDIENT: <span class="Delimiter">{</span> assert<span class="Delimiter">(</span>!Current_routine<span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>empty<span class="Delimiter">());</span> <span class="Normal">if</span> <span class="Delimiter">(</span>current_call<span class="Delimiter">().</span>next_ingredient_to_process &lt; SIZE<span class="Delimiter">(</span>current_call<span class="Delimiter">().</span>ingredient_atoms<span class="Delimiter">))</span> <span class="Delimiter">{</span> reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> product = current_instruction<span class="Delimiter">().</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> <span class="Comment">// End Preprocess NEXT_INGREDIENT product</span> <span class="Normal">if</span> <span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">()</span> == <span class="Constant">&quot;main&quot;</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Comment">// no ingredient types since the call might be implicit; assume ingredients are always strings</span> <span class="Comment">// todo: how to test this?</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!is_mu_text<span class="Delimiter">(</span>product<span class="Delimiter">))</span> raise &lt;&lt; <span class="Constant">&quot;main: wrong type for ingredient '&quot;</span> &lt;&lt; product<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Delimiter">}</span> <span class="Normal">else</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!types_coercible<span class="Delimiter">(</span>product<span class="Delimiter">,</span> current_call<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>current_call<span class="Delimiter">().</span>next_ingredient_to_process<span class="Delimiter">)))</span> <span class="Delimiter">{</span> raise &lt;&lt; maybe<span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;wrong type for ingredient '&quot;</span> &lt;&lt; product<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Comment">// End next-ingredient Type Mismatch Error</span> <span class="Delimiter">}</span> products<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span> current_call<span class="Delimiter">().</span>ingredient_atoms<span class="Delimiter">.</span>at<span class="Delimiter">(</span>current_call<span class="Delimiter">().</span>next_ingredient_to_process<span class="Delimiter">));</span> assert<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>products<span class="Delimiter">)</span> == <span class="Constant">1</span><span class="Delimiter">);</span> products<span class="Delimiter">.</span>resize<span class="Delimiter">(</span><span class="Constant">2</span><span class="Delimiter">);</span> <span class="Comment">// push a new vector</span> products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">);</span> ++current_call<span class="Delimiter">().</span>next_ingredient_to_process<span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">else</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>products<span class="Delimiter">)</span> &lt; <span class="Constant">2</span><span class="Delimiter">)</span> raise &lt;&lt; maybe<span class="Delimiter">(</span>current_recipe_name<span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;no ingredient to save in '&quot;</span> &lt;&lt; current_instruction<span class="Delimiter">().</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Normal">if</span> <span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>products<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Identifier">break</span><span class="Delimiter">;</span> products<span class="Delimiter">.</span>resize<span class="Delimiter">(</span><span class="Constant">2</span><span class="Delimiter">);</span> <span class="Comment">// pad the first product with sufficient zeros to match its type</span> <span class="Normal">int</span> size = size_of<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">));</span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Constant">0</span><span class="Delimiter">;</span> i &lt; size<span class="Delimiter">;</span> ++i<span class="Delimiter">)</span> products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> <span class="Delimiter">}</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(scenario next_ingredient_fail_on_missing)</span> <span class="Special">% Hide_errors = true;</span> <span class="muRecipe">def</span> main [ f ] <span class="muRecipe">def</span> f [ <span class="Constant">11</span>:num<span class="Special"> &lt;- </span>next-ingredient ] <span class="traceContains">+error: f: no ingredient to save in '11:num'</span> <span class="Delimiter">:(scenario rewind_ingredients)</span> <span class="muRecipe">def</span> main [ f <span class="Constant">2</span> ] <span class="muRecipe">def</span> f [ <span class="Constant">12</span>:num<span class="Special"> &lt;- </span>next-ingredient <span class="Comment"># consume ingredient</span> _<span class="Delimiter">,</span> <span class="Constant">1</span>:<span class="Normal">bool</span><span class="Special"> &lt;- </span>next-ingredient <span class="Comment"># will not find any ingredients</span> rewind-ingredients <span class="Constant">13</span>:num<span class="Delimiter">,</span> <span class="Constant">2</span>:<span class="Normal">bool</span><span class="Special"> &lt;- </span>next-ingredient <span class="Comment"># will find ingredient again</span> ] <span class="traceContains">+mem: storing 2 in location 12</span> <span class="traceContains">+mem: storing 0 in location 1</span> <span class="traceContains">+mem: storing 2 in location 13</span> <span class="traceContains">+mem: storing 1 in location 2</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span> REWIND_INGREDIENTS<span class="Delimiter">,</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span> put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;rewind-ingredients&quot;</span><span class="Delimiter">,</span> REWIND_INGREDIENTS<span class="Delimiter">);</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span> <span class="Normal">case</span> REWIND_INGREDIENTS: <span class="Delimiter">{</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span> <span class="Normal">case</span> REWIND_INGREDIENTS: <span class="Delimiter">{</span> current_call<span class="Delimiter">().</span>next_ingredient_to_process = <span class="Constant">0</span><span class="Delimiter">;</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(scenario ingredient)</span> <span class="muRecipe">def</span> main [ f <span class="Constant">1</span><span class="Delimiter">,</span> <span class="Constant">2</span> ] <span class="muRecipe">def</span> f [ <span class="Constant">12</span>:num<span class="Special"> &lt;- </span>ingredient <span class="Constant">1</span> <span class="Comment"># consume second ingredient first</span> <span class="Constant">13</span>:num<span class="Delimiter">,</span> <span class="Constant">1</span>:<span class="Normal">bool</span><span class="Special"> &lt;- </span>next-ingredient <span class="Comment"># next-ingredient tries to scan past that</span> ] <span class="traceContains">+mem: storing 2 in location 12</span> <span class="traceContains">+mem: storing 0 in location 1</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span> INGREDIENT<span class="Delimiter">,</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span> put<span class="Delimiter">(</span>Recipe_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;ingredient&quot;</span><span class="Delimiter">,</span> INGREDIENT<span class="Delimiter">);</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span> <span class="Normal">case</span> INGREDIENT: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> != <span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'ingredient' expects exactly one ingredient, but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">if</span> <span class="Delimiter">(</span>!is_literal<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">))</span> &amp;&amp; !is_mu_number<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span> raise &lt;&lt; maybe<span class="Delimiter">(</span>get<span class="Delimiter">(</span>Recipe<span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'ingredient' expects a literal ingredient, but got '&quot;</span> &lt;&lt; inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string &lt;&lt; <span class="Constant">&quot;'</span><span class="cSpecial">\n</span><span class="Constant">&quot;</span> &lt;&lt; end<span class="Delimiter">();</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span> <span class="Normal">case</span> INGREDIENT: <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">static_cast</span>&lt;<span class="Normal">int</span>&gt;<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">))</span> &lt; SIZE<span class="Delimiter">(</span>current_call<span class="Delimiter">().</span>ingredient_atoms<span class="Delimiter">))</span> <span class="Delimiter">{</span> current_call<span class="Delimiter">().</span>next_ingredient_to_process = ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> products<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span> current_call<span class="Delimiter">().</span>ingredient_atoms<span class="Delimiter">.</span>at<span class="Delimiter">(</span>current_call<span class="Delimiter">().</span>next_ingredient_to_process<span class="Delimiter">));</span> assert<span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>products<span class="Delimiter">)</span> == <span class="Constant">1</span><span class="Delimiter">);</span> products<span class="Delimiter">.</span>resize<span class="Delimiter">(</span><span class="Constant">2</span><span class="Delimiter">);</span> <span class="Comment">// push a new vector</span> products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">);</span> ++current_call<span class="Delimiter">().</span>next_ingredient_to_process<span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Normal">else</span> <span class="Delimiter">{</span> <span class="Normal">if</span> <span class="Delimiter">(</span>SIZE<span class="Delimiter">(</span>current_instruction<span class="Delimiter">().</span>products<span class="Delimiter">)</span> &gt; <span class="Constant">1</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> products<span class="Delimiter">.</span>resize<span class="Delimiter">(</span><span class="Constant">2</span><span class="Delimiter">);</span> products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> <span class="Comment">// todo: will fail noisily if we try to read a compound value</span> products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">);</span> <span class="Delimiter">}</span> <span class="Delimiter">}</span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Delimiter">}</span> <span class="Comment">//: a particularly common array type is the text, or address:array:character</span> <span class="Delimiter">:(code)</span> <span class="Normal">bool</span> is_mu_text<span class="Delimiter">(</span>reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> x<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span class="Comment">// End Preprocess is_mu_text(reagent x)</span> <span class="Identifier">return</span> x<span class="Delimiter">.</span>type &amp;&amp; !x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>atom &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>atom &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>value == get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;address&quot;</span><span class="Delimiter">)</span> &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right &amp;&amp; !x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>atom &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>left<span class="Delimiter">-&gt;</span>value == get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;array&quot;</span><span class="Delimiter">)</span> &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>atom &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>right<span class="Delimiter">-&gt;</span>value == get<span class="Delimiter">(</span>Type_ordinal<span class="Delimiter">,</span> <span class="Constant">&quot;character&quot;</span><span class="Delimiter">);</span> <span class="Delimiter">}</span> </pre> </body> </html> <!-- vim: set foldmethod=manual : -->