summary refs log tree commit diff stats
path: root/tests/js/tmangle.nim
blob: c4167ba398ca3096c571bb9629e5d99bb6218283 (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
discard """
  output: '''true
true
true
true
true
true
true'''
"""

# Test not mangled:
block:
  type T = object
    a: int
    b: cstring
  proc test(): bool =
    let obj = T(a: 11, b: "foo")
    {. emit: [result, " = (", obj, ".a == 11);"] .}
    {. emit: [result, " = ", result, " && (", obj, ".b == \"foo\");"] .}
  echo test()

# Test indirect (fields in genAddr):
block:
  type T = object
    a: int
    b: cstring
  var global = T(a: 11, b: "foo")
  proc test(): bool =
    var obj = T(a: 11, b: "foo")
    {. emit: [result, " = (", obj.addr[], "[0].a == 11);"] .}
    {. emit: [result, " = ", result, " && (", obj.addr[], "[0].b == \"foo\");"] .}
    {. emit: [result, " = ", result, " && (", global, "[0].a == 11);"] .}
    {. emit: [result, " = ", result, " && (", global, "[0].b == \"foo\");"] .}
  echo test()

# Test addr of field:
block:
  type T = object
    a: int
    b: cstring
  proc test(): bool =
    var obj = T(a: 11, b: "foo")
    result = obj.a.addr[] == 11
    result = result and obj.b.addr[] == "foo".cstring
  echo test()

# Test reserved words:
block:
  type T = ref object
    `if`: int
    `for`: int
    `==`: cstring
    `&&`: cstring
  proc test(): bool =
    var
      obj1 = T(`if`: 11, `for`: 22, `==`: "foo", `&&`: "bar")
      obj2: T
    new obj2 # Test behaviour for createRecordVarAux.
    result = obj1.`if` == 11
    result = result and obj1.addr[].`for` == 22
    result = result and obj1.`==` == "foo".cstring
    result = result and obj1.`&&`.addr[] == "bar".cstring
    result = result and obj2.`if` == 0
    result = result and obj2.`for` == 0
    result = result and obj2.`==`.isNil()
    result = result and obj2.`&&`.isNil()
  echo test()

# Test codegen for fields with uppercase letters:
block:
  type MyObj = object
    mField: int
  proc test(): bool =
    var a: MyObj
    var b = a
    result = b.mField == 0
  echo test()

# Test tuples
block:
  type T = tuple
    a: int
    b: int
  proc test(): bool =
    var a: T = (a: 1, b: 1)
    result = a.a == 1
    result = result and a.b == 1
  echo test()

# Test importc / exportc fields:
block:
  type T = object
    a: int
    b {. importc: "notB" .}: cstring
  type U = object
    a: int
    b {. exportc: "notB" .}: cstring
  proc test(): bool =
    var
      obj1 = T(a: 11, b: "foo")
      obj2 = U(a: 11, b: "foo")
    {. emit: [result, " = (", obj1, ".a == 11);"] .}
    {. emit: [result, " = ", result, " && (", obj1, ".notB == \"foo\");"] .}
    {. emit: [result, " = (", obj2, ".a == 11);"] .}
    {. emit: [result, " = ", result, " && (", obj2, ".notB == \"foo\");"] .}
  echo test()
span>end()) { raise_error << maybe(Recipe[r].name) << "undefined operation in '" << inst.to_string() << "'\n" << end(); break; } :(replace{} "default:" following "End Primitive Recipe Implementations") default: { const instruction& call_instruction = current_instruction(); if (Recipe.find(current_instruction().operation) == Recipe.end()) { // duplicate from Checks // stop running this instruction immediately ++current_step_index(); continue; } // not a primitive; look up the book of recipes if (Trace_stream) { ++Trace_stream->callstack_depth; trace("trace") << "incrementing callstack depth to " << Trace_stream->callstack_depth << end(); assert(Trace_stream->callstack_depth < 9000); // 9998-101 plus cushion } Current_routine->calls.push_front(call(current_instruction().operation)); // End Call Housekeeping continue; // not done with caller; don't increment current_step_index() } :(scenario calling_undefined_recipe_fails) % Hide_errors = true; recipe main [ foo ] +error: main: undefined operation in 'foo ' :(scenario calling_undefined_recipe_handles_missing_result) % Hide_errors = true; recipe main [ x:number <- foo ] +error: main: undefined operation in 'x:number <- foo ' //:: finally, we need to fix the termination conditions for the run loop :(replace{} "inline bool routine::completed() const") inline bool routine::completed() const { return calls.empty(); } inline const vector<instruction>& routine::steps() const { assert(!calls.empty()); return Recipe[calls.front().running_recipe].steps; } :(before "Running One Instruction") // when we reach the end of one call, we may reach the end of the one below // it, and the one below that, and so on while (current_step_index() >= SIZE(Current_routine->steps())) { // Falling Through End Of Recipe if (Trace_stream) { trace("trace") << "fall-through: exiting " << current_recipe_name() << "; decrementing callstack depth from " << Trace_stream->callstack_depth << end(); --Trace_stream->callstack_depth; assert(Trace_stream->callstack_depth >= 0); } Current_routine->calls.pop_front(); if (Current_routine->calls.empty()) return; // Complete Call Fallthrough // todo: fail if no products returned ++current_step_index(); } :(before "End Includes") #include <stack> using std::stack;