summary refs log tree commit diff stats
path: root/tests/stdlib/trstgen.nim
blob: c702ccc2a8ff81eba5ac7a06dfbc6cd80f4d45b1 (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# tests for rstgen module.

import ../../lib/packages/docutils/rstgen
import unittest

suite "YAML syntax highlighting":
  test "Basics":
    let input = """.. code-block:: yaml
    %YAML 1.2
    ---
    a string: string
    a list:
      - item 1
      - item 2
    a map:
    ? key
    : value
    ..."""
    let output = rstTohtml(input, {}, defaultConfig())
    assert output == """<pre class = "listing"><span class="Directive">%YAML 1.2</span>
<span class="Keyword">---</span>
<span class="StringLit">a string</span><span class="Punctuation">:</span> <span class="StringLit">string</span>
<span class="StringLit">a list</span><span class="Punctuation">:</span>
  <span class="Punctuation">-</span> <span class="StringLit">item 1</span>
  <span class="Punctuation">-</span> <span class="StringLit">item 2</span>
<span class="StringLit">a map</span><span class="Punctuation">:</span>
<span class="Punctuation">?</span> <span class="StringLit">key</span>
<span class="Punctuation">:</span> <span class="StringLit">value</span>
<span class="Keyword">...</span></pre>"""
  
  test "Block scalars":
    let input = """.. code-block:: yaml
    a literal block scalar: |
      some text
      # not a comment
     # a comment, since less indented
      # another comment
    a folded block scalar: >2
       some text
      # not a comment since indented as specified
     # a comment
    another literal block scalar:
      |+ # comment after header
     allowed, since more indented than parent"""
    let output = rstToHtml(input, {}, defaultConfig())
    assert output == """<pre class = "listing"><span class="StringLit">a literal block scalar</span><span class="Punctuation">:</span> <span class="Command">|</span><span class="Command"></span><span class="LongStringLit">
  some text
  # not a comment
 </span><span class="Comment"># a comment, since less indented</span>
  <span class="Comment"># another comment</span>
<span class="StringLit">a folded block scalar</span><span class="Punctuation">:</span> <span class="Command">&gt;2</span><span class="Command"></span><span class="LongStringLit">
   some text
  # not a comment since indented as specified
 </span><span class="Comment"># a comment</span>
<span class="StringLit">another literal block scalar</span><span class="Punctuation">:</span>
  <span class="Command">|+</span> <span class="Comment"># comment after header</span><span class="LongStringLit">
 allowed, since more indented than parent</span></pre>"""
 
  test "Directives":
    let input = """.. code-block:: yaml
    %YAML 1.2
    ---
    %not a directive
    ...
    %a directive
    ...
    a string
    % not a directive
    ...
    %TAG ! !foo:"""
    let output = rstToHtml(input, {}, defaultConfig())
    assert output == """<pre class = "listing"><span class="Directive">%YAML 1.2</span>
<span class="Keyword">---</span>
<span class="StringLit">%not a directive</span>
<span class="Keyword">...</span>
<span class="Directive">%a directive</span>
<span class="Keyword">...</span>
<span class="StringLit">a string</span>
<span class="StringLit">% not a directive</span>
<span class="Keyword">...</span>
<span class="Directive">%TAG ! !foo:</span></pre>"""

  test "Flow Style and Numbers":
    let input = """.. code-block:: yaml
    {
      "quoted string": 42,
      'single quoted string': false,
      [ list, "with", 'entries' ]: 73.32e-73,
      more numbers: [-783, 11e78],
      not numbers: [ 42e, 0023, +32.37, 8 ball]
    }"""
    let output = rstToHtml(input, {}, defaultConfig())
    assert output == """<pre class = "listing"><span class="Punctuation">{</span>
  <span class="StringLit">&quot;</span><span class="StringLit">quoted string&quot;</span><span class="Punctuation">:</span> <span class="DecNumber">42</span><span class="Punctuation">,</span>
  <span class="StringLit">'single quoted string'</span><span class="Punctuation">:</span> <span class="StringLit">false</span><span class="Punctuation">,</span>
  <span class="Punctuation">[</span> <span class="StringLit">list</span><span class="Punctuation">,</span> <span class="StringLit">&quot;</span><span class="StringLit">with&quot;</span><span class="Punctuation">,</span> <span class="StringLit">'entries'</span> <span class="Punctuation">]</span><span class="Punctuation">:</span> <span class="FloatNumber">73.32e-73</span><span class="Punctuation">,</span>
  <span class="StringLit">more numbers</span><span class="Punctuation">:</span> <span class="Punctuation">[</span><span class="DecNumber">-783</span><span class="Punctuation">,</span> <span class="FloatNumber">11e78</span><span class="Punctuation">]</span><span class="Punctuation">,</span>
  <span class="StringLit">not numbers</span><span class="Punctuation">:</span> <span class="Punctuation">[</span> <span class="StringLit">42e</span><span class="Punctuation">,</span> <span class="StringLit">0023</span><span class="Punctuation">,</span> <span class="StringLit">+32.37</span><span class="Punctuation">,</span> <span class="StringLit">8 ball</span><span class="Punctuation">]</span>
<span class="Punctuation">}</span></pre>"""
  
  test "Anchors, Aliases, Tags":
    let input = """.. code-block:: yaml
    --- !!map
    !!str string: !<tag:yaml.org,2002:int> 42
    ? &anchor !!seq []:
    : !localtag foo
    alias: *anchor
    """
    let output = rstToHtml(input, {}, defaultConfig())
    assert output == """<pre class = "listing"><span class="Keyword">---</span> <span class="TagStart">!!map</span>
<span class="TagStart">!!str</span> <span class="StringLit">string</span><span class="Punctuation">:</span> <span class="TagStart">!&lt;tag:yaml.org,2002:int&gt;</span> <span class="DecNumber">42</span>
<span class="Punctuation">?</span> <span class="Label">&amp;anchor</span> <span class="TagStart">!!seq</span> <span class="Punctuation">[</span><span class="Punctuation">]</span><span class="Punctuation">:</span>
<span class="Punctuation">:</span> <span class="TagStart">!localtag</span> <span class="StringLit">foo</span>
<span class="StringLit">alias</span><span class="Punctuation">:</span> <span class="Reference">*anchor</span></pre>"""

  test "Edge cases":
    let input = """.. code-block:: yaml
    ...
     %a string:
      a:string:not:a:map
    ...
    not a list:
      -2
      -3
      -4
    example.com/not/a#comment:
      ?not a map key
    """
    let output = rstToHtml(input, {}, defaultConfig())
    assert output == """<pre class = "listing"><span class="Keyword">...</span>
 <span class="StringLit">%a string</span><span class="Punctuation">:</span>
  <span class="StringLit">a:string:not:a:map</span>
<span class="Keyword">...</span>
<span class="StringLit">not a list</span><span class="Punctuation">:</span>
  <span class="DecNumber">-2</span>
  <span class="DecNumber">-3</span>
  <span class="DecNumber">-4</span>
<span class="StringLit">example.com/not/a#comment</span><span class="Punctuation">:</span>
  <span class="StringLit">?not a map key</span></pre>"""
span> //: writes to address 0 always loudly fail :(scenario store_to_0_fails) % Hide_errors = true; def main [ 1:address:num <- copy 0 1:address:num/lookup <- copy 34 ] -mem: storing 34 in location 0 +error: can't write to location 0 in '1:address:num/lookup <- copy 34' //: attempts to /lookup address 0 always loudly fail :(scenario lookup_0_fails) % Hide_errors = true; def main [ 1:address:num <- copy 0 2:num <- copy 1:address:num/lookup ] +error: main: tried to /lookup 0 in '2:num <- copy 1:address:num/lookup' :(code) void canonize(reagent& x) { if (is_literal(x)) return; // Begin canonize(x) Lookups while (has_property(x, "lookup")) lookup_memory(x); } void lookup_memory(reagent& x) { if (!x.type || x.type->atom || x.type->left->value != get(Type_ordinal, "address")) { raise << maybe(current_recipe_name()) << "tried to /lookup '" << x.original_string << "' but it isn't an address\n" << end(); return; } // compute value if (x.value == 0) { raise << maybe(current_recipe_name()) << "tried to /lookup 0\n" << end(); return; } lookup_memory_core(x, /*check_for_null*/true); } void lookup_memory_core(reagent& x, bool check_for_null) { if (x.value == 0) return; trace(9999, "mem") << "location " << x.value << " is " << no_scientific(get_or_insert(Memory, x.value)) << end(); x.set_value(get_or_insert(Memory, x.value)); drop_from_type(x, "address"); if (x.value) { trace(9999, "mem") << "skipping refcount at " << x.value << end(); x.set_value(x.value+1); // skip refcount } else if (check_for_null) { if (Current_routine) raise << maybe(current_recipe_name()) << "tried to /lookup 0 in '" << to_original_string(current_instruction()) << "'\n" << end(); else raise << "tried to /lookup 0\n" << end(); } drop_one_lookup(x); } void test_lookup_address_skips_refcount() { reagent x("*x:address:num"); x.set_value(34); // unsafe put(Memory, 34, 1000); lookup_memory(x); CHECK_TRACE_CONTENTS("mem: skipping refcount at 1000"); CHECK_EQ(x.value, 1001); } void test_lookup_zero_address_does_not_skip_refcount() { Hide_errors = true; reagent x("*x:address:num"); x.set_value(34); // unsafe put(Memory, 34, 0); lookup_memory(x); CHECK_TRACE_DOESNT_CONTAIN("mem: skipping refcount at 0"); CHECK_EQ(x.value, 0); } :(before "End Preprocess types_strictly_match(reagent to, reagent from)") if (!canonize_type(to)) return false; if (!canonize_type(from)) return false; :(before "End Preprocess is_mu_array(reagent r)") if (!canonize_type(r)) return false; :(before "End Preprocess is_mu_address(reagent r)") if (!canonize_type(r)) return false; :(before "End Preprocess is_mu_number(reagent r)") if (!canonize_type(r)) return false; :(before "End Preprocess is_mu_boolean(reagent r)") if (!canonize_type(r)) return false; :(before "End Preprocess is_mu_character(reagent r)") if (!canonize_type(r)) return false; :(after "Update product While Type-checking Merge") if (!canonize_type(product)) continue; :(before "End Compute Call Ingredient") canonize_type(ingredient); :(before "End Preprocess NEXT_INGREDIENT product") canonize_type(product); :(before "End Check RETURN Copy(lhs, rhs) canonize_type(lhs); canonize_type(rhs); :(before "Compute Container Size(reagent rcopy)") if (!canonize_type(rcopy)) return; :(before "Compute Container Size(element, full_type)") assert(!has_property(element, "lookup")); :(before "Compute Exclusive Container Size(element, full_type)") assert(!has_property(element, "lookup")); :(code) bool canonize_type(reagent& r) { while (has_property(r, "lookup")) { if (!r.type || r.type->atom || !r.type->left || !r.type->left->atom || r.type->left->value != get(Type_ordinal, "address")) { raise << "cannot perform lookup on '" << r.name << "' because it has non-address type " << to_string(r.type) << '\n' << end(); return false; } drop_from_type(r, "address"); drop_one_lookup(r); } return true; } void drop_one_lookup(reagent& r) { for (vector<pair<string, string_tree*> >::iterator p = r.properties.begin(); p != r.properties.end(); ++p) { if (p->first == "lookup") { r.properties.erase(p); return; } } assert(false); } //: Tedious fixup to support addresses in container/array instructions of previous layers. //: Most instructions don't require fixup if they use the 'ingredients' and //: 'products' variables in run_current_routine(). :(scenario get_indirect) def main [ 1:address:point <- copy 10/unsafe # 10 reserved for refcount 11:num <- copy 34 12:num <- copy 35 2:num <- get 1:address:point/lookup, 0:offset ] +mem: storing 34 in location 2 :(scenario get_indirect2) def main [ 1:address:point <- copy 10/unsafe # 10 reserved for refcount 11:num <- copy 34 12:num <- copy 35 2:address:num <- copy 20/unsafe 2:address:num/lookup <- get 1:address:point/lookup, 0:offset ] +mem: storing 34 in location 21 :(scenario include_nonlookup_properties) def main [ 1:address:point <- copy 10/unsafe # 10 reserved for refcount 11:num <- copy 34 12:num <- copy 35 2:num <- get 1:address:point/lookup/foo, 0:offset ] +mem: storing 34 in location 2 :(after "Update GET base in Check") if (!canonize_type(base)) break; :(after "Update GET product in Check") if (!canonize_type(product)) break; :(after "Update GET base in Run") canonize(base); :(scenario put_indirect) def main [ 1:address:point <- copy 10/unsafe # 10 reserved for refcount 11:num <- copy 34 12:num <- copy 35 1:address:point/lookup <- put 1:address:point/lookup, 0:offset, 36 ] +mem: storing 36 in location 11 :(after "Update PUT base in Check") if (!canonize_type(base)) break; :(after "Update PUT offset in Check") if (!canonize_type(offset)) break; :(after "Update PUT base in Run") canonize(base); :(scenario put_product_error_with_lookup) % Hide_errors = true; def main [ 1:address:point <- copy 10/unsafe # 10 reserved for refcount 11:num <- copy 34 12:num <- copy 35 1:address:point <- put 1:address:point/lookup, x:offset, 36 ] +error: main: product of 'put' must be first ingredient '1:address:point/lookup', but got '1:address:point' :(before "End PUT Product Checks") reagent/*copy*/ p = inst.products.at(0); if (!canonize_type(p)) break; // error raised elsewhere reagent/*copy*/ i = inst.ingredients.at(0); if (!canonize_type(i)) break; // error raised elsewhere if (!types_strictly_match(p, i)) { raise << maybe(get(Recipe, r).name) << "product of 'put' must be first ingredient '" << inst.ingredients.at(0).original_string << "', but got '" << inst.products.at(0).original_string << "'\n" << end(); break; } :(scenario new_error) % Hide_errors = true; def main [ 1:num/raw <- new number:type ] +error: main: product of 'new' has incorrect type: '1:num/raw <- new number:type' :(after "Update NEW product in Check") canonize_type(product); :(scenario copy_array_indirect) def main [ # 10 reserved for refcount 11:array:num:3 <- create-array 12:num <- copy 14 13:num <- copy 15 14:num <- copy 16 1:address:array:num <- copy 10/unsafe 2:array:num <- copy 1:address:array:num/lookup ] +mem: storing 3 in location 2 +mem: storing 14 in location 3 +mem: storing 15 in location 4 +mem: storing 16 in location 5 :(scenario create_array_indirect) def main [ 1000:num/raw <- copy 1 # pretend refcount 1:address:array:num:3 <- copy 1000/unsafe # pretend allocation 1:address:array:num:3/lookup <- create-array ] +mem: storing 3 in location 1001 :(after "Update CREATE_ARRAY product in Check") if (!canonize_type(product)) break; :(after "Update CREATE_ARRAY product in Run") canonize(product); :(scenario index_indirect) def main [ # 10 reserved for refcount 11:array:num:3 <- create-array 12:num <- copy 14 13:num <- copy 15 14:num <- copy 16 1:address:array:num <- copy 10/unsafe 2:num <- index 1:address:array:num/lookup, 1 ] +mem: storing 15 in location 2 :(before "Update INDEX base in Check") if (!canonize_type(base)) break; :(before "Update INDEX index in Check") if (!canonize_type(index)) break; :(before "Update INDEX product in Check") if (!canonize_type(product)) break; :(before "Update INDEX base in Run") canonize(base); :(before "Update INDEX index in Run") canonize(index); :(scenario put_index_indirect) def main [ # 10 reserved for refcount 11:array:num:3 <- create-array 12:num <- copy 14 13:num <- copy 15 14:num <- copy 16 1:address:array:num <- copy 10/unsafe 1:address:array:num/lookup <- put-index 1:address:array:num/lookup, 1, 34 ] +mem: storing 34 in location 13 :(scenario put_index_indirect_2) def main [ 1:array:num:3 <- create-array 2:num <- copy 14 3:num <- copy 15 4:num <- copy 16 5:address:num <- copy 10/unsafe # 10 reserved for refcount 11:num <- copy 1 1:array:num:3 <- put-index 1:array:num:3, 5:address:num/lookup, 34 ] +mem: storing 34 in location 3 :(scenario put_index_product_error_with_lookup) % Hide_errors = true; def main [ # 10 reserved for refcount 11:array:num:3 <- create-array 12:num <- copy 14 13:num <- copy 15 14:num <- copy 16 1:address:array:num <- copy 10/unsafe 1:address:array:num <- put-index 1:address:array:num/lookup, 1, 34 ] +error: main: product of 'put-index' must be first ingredient '1:address:array:num/lookup', but got '1:address:array:num' :(before "End PUT_INDEX Product Checks") reagent/*copy*/ p = inst.products.at(0); if (!canonize_type(p)) break; // error raised elsewhere reagent/*copy*/ i = inst.ingredients.at(0); if (!canonize_type(i)) break; // error raised elsewhere if (!types_strictly_match(p, i)) { raise << maybe(get(Recipe, r).name) << "product of 'put-index' must be first ingredient '" << inst.ingredients.at(0).original_string << "', but got '" << inst.products.at(0).original_string << "'\n" << end(); break; } :(scenario dilated_reagent_in_static_array) def main [ {1: (array (address number) 3)} <- create-array 5:address:num <- new number:type {1: (array (address number) 3)} <- put-index {1: (array (address number) 3)}, 0, 5:address:num *5:address:num <- copy 34 6:num <- copy *5:address:num ] +run: creating array of size 4 +mem: storing 34 in location 6 :(before "Update PUT_INDEX base in Check") if (!canonize_type(base)) break; :(before "Update PUT_INDEX index in Check") if (!canonize_type(index)) break; :(before "Update PUT_INDEX value in Check") if (!canonize_type(value)) break; :(before "Update PUT_INDEX base in Run") canonize(base); :(before "Update PUT_INDEX index in Run") canonize(index); :(scenario length_indirect) def main [ # 10 reserved for refcount 11:array:num:3 <- create-array 12:num <- copy 14 13:num <- copy 15 14:num <- copy 16 1:address:array:num <- copy 10/unsafe 2:num <- length 1:address:array:num/lookup ] +mem: storing 3 in location 2 :(before "Update LENGTH array in Check") if (!canonize_type(array)) break; :(before "Update LENGTH array in Run") canonize(array); :(scenario maybe_convert_indirect) def main [ # 10 reserved for refcount 11:number-or-point <- merge 0/number, 34 1:address:number-or-point <- copy 10/unsafe 2:num, 3:bool <- maybe-convert 1:address:number-or-point/lookup, i:variant ] +mem: storing 1 in location 3 +mem: storing 34 in location 2 :(scenario maybe_convert_indirect_2) def main [ # 10 reserved for refcount 11:number-or-point <- merge 0/number, 34 1:address:number-or-point <- copy 10/unsafe 2:address:num <- copy 20/unsafe 2:address:num/lookup, 3:bool <- maybe-convert 1:address:number-or-point/lookup, i:variant ] +mem: storing 1 in location 3 +mem: storing 34 in location 21 :(scenario maybe_convert_indirect_3) def main [ # 10 reserved for refcount 11:number-or-point <- merge 0/number, 34 1:address:number-or-point <- copy 10/unsafe 2:address:bool <- copy 20/unsafe 3:num, 2:address:bool/lookup <- maybe-convert 1:address:number-or-point/lookup, i:variant ] +mem: storing 1 in location 21 +mem: storing 34 in location 3 :(before "Update MAYBE_CONVERT base in Check") if (!canonize_type(base)) break; :(before "Update MAYBE_CONVERT product in Check") if (!canonize_type(product)) break; :(before "Update MAYBE_CONVERT status in Check") if (!canonize_type(status)) break; :(before "Update MAYBE_CONVERT base in Run") canonize(base); :(before "Update MAYBE_CONVERT product in Run") canonize(product); :(before "Update MAYBE_CONVERT status in Run") canonize(status); :(scenario merge_exclusive_container_indirect) def main [ 1:address:number-or-point <- copy 10/unsafe 1:address:number-or-point/lookup <- merge 0/number, 34 ] # skip 10 for refcount +mem: storing 0 in location 11 +mem: storing 34 in location 12 :(before "Update size_mismatch Check for MERGE(x) canonize(x); //: abbreviation for '/lookup': a prefix '*' :(scenario lookup_abbreviation) def main [ 1:address:number <- copy 10/unsafe # 10 reserved for refcount 11:number <- copy 34 3:number <- copy *1:address:number ] +parse: ingredient: {1: ("address" "number"), "lookup": ()} +mem: storing 34 in location 3 :(before "End Parsing reagent") { while (starts_with(name, "*")) { name.erase(0, 1); properties.push_back(pair<string, string_tree*>("lookup", NULL)); } if (name.empty()) raise << "illegal name '" << original_string << "'\n" << end(); } //:: helpers for debugging :(before "End Primitive Recipe Declarations") _DUMP, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "$dump", _DUMP); :(before "End Primitive Recipe Implementations") case _DUMP: { reagent/*copy*/ after_canonize = current_instruction().ingredients.at(0); canonize(after_canonize); cerr << maybe(current_recipe_name()) << current_instruction().ingredients.at(0).name << ' ' << no_scientific(current_instruction().ingredients.at(0).value) << " => " << no_scientific(after_canonize.value) << " => " << no_scientific(get_or_insert(Memory, after_canonize.value)) << '\n'; break; } //: grab an address, and then dump its value at intervals //: useful for tracking down memory corruption (writing to an out-of-bounds address) :(before "End Globals") int Bar = -1; :(before "End Primitive Recipe Declarations") _BAR, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "$bar", _BAR); :(before "End Primitive Recipe Implementations") case _BAR: { if (current_instruction().ingredients.empty()) { if (Bar != -1) cerr << Bar << ": " << no_scientific(get_or_insert(Memory, Bar)) << '\n'; else cerr << '\n'; } else { reagent/*copy*/ tmp = current_instruction().ingredients.at(0); canonize(tmp); Bar = tmp.value; } break; }