melbourne 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. data/HISTORY +3 -0
  2. data/LICENSE +27 -0
  3. data/README.rdoc +38 -0
  4. data/Rakefile +38 -0
  5. data/VERSION.yml +4 -0
  6. data/ext/melbourne/bstring-license.txt +29 -0
  7. data/ext/melbourne/bstrlib.c +2918 -0
  8. data/ext/melbourne/bstrlib.h +302 -0
  9. data/ext/melbourne/extconf.rb +76 -0
  10. data/ext/melbourne/grammar.cpp +11885 -0
  11. data/ext/melbourne/grammar.hpp +14 -0
  12. data/ext/melbourne/grammar.y +6013 -0
  13. data/ext/melbourne/internal.hpp +137 -0
  14. data/ext/melbourne/lex.c.tab +136 -0
  15. data/ext/melbourne/local_state.hpp +41 -0
  16. data/ext/melbourne/melbourne.cpp +37 -0
  17. data/ext/melbourne/node.hpp +262 -0
  18. data/ext/melbourne/node_types.cpp +245 -0
  19. data/ext/melbourne/node_types.hpp +135 -0
  20. data/ext/melbourne/node_types.rb +190 -0
  21. data/ext/melbourne/quark.cpp +52 -0
  22. data/ext/melbourne/quark.hpp +14 -0
  23. data/ext/melbourne/symbols.cpp +219 -0
  24. data/ext/melbourne/symbols.hpp +116 -0
  25. data/ext/melbourne/var_table.cpp +113 -0
  26. data/ext/melbourne/var_table.hpp +33 -0
  27. data/ext/melbourne/visitor.cpp +1052 -0
  28. data/ext/melbourne/visitor.hpp +20 -0
  29. data/lib/melbourne/ast/constants.rb +128 -0
  30. data/lib/melbourne/ast/control_flow.rb +382 -0
  31. data/lib/melbourne/ast/data.rb +19 -0
  32. data/lib/melbourne/ast/definitions.rb +561 -0
  33. data/lib/melbourne/ast/exceptions.rb +182 -0
  34. data/lib/melbourne/ast/file.rb +15 -0
  35. data/lib/melbourne/ast/grapher.rb +75 -0
  36. data/lib/melbourne/ast/literals.rb +268 -0
  37. data/lib/melbourne/ast/node.rb +21 -0
  38. data/lib/melbourne/ast/operators.rb +117 -0
  39. data/lib/melbourne/ast/self.rb +17 -0
  40. data/lib/melbourne/ast/sends.rb +451 -0
  41. data/lib/melbourne/ast/values.rb +74 -0
  42. data/lib/melbourne/ast/variables.rb +251 -0
  43. data/lib/melbourne/ast.rb +22 -0
  44. data/lib/melbourne/parser.rb +38 -0
  45. data/lib/melbourne/processor.rb +460 -0
  46. data/lib/melbourne.rb +46 -0
  47. data/spec/helpers/ast/node.rb +15 -0
  48. data/spec/helpers/ast/reduced_graph.rb +64 -0
  49. data/spec/lib/parser/alias_spec.rb +97 -0
  50. data/spec/lib/parser/and_spec.rb +63 -0
  51. data/spec/lib/parser/array_spec.rb +157 -0
  52. data/spec/lib/parser/attrasgn_spec.rb +401 -0
  53. data/spec/lib/parser/back_ref_spec.rb +20 -0
  54. data/spec/lib/parser/call_spec.rb +958 -0
  55. data/spec/lib/parser/case_spec.rb +577 -0
  56. data/spec/lib/parser/cdecl_spec.rb +108 -0
  57. data/spec/lib/parser/class_spec.rb +221 -0
  58. data/spec/lib/parser/colon2_spec.rb +13 -0
  59. data/spec/lib/parser/colon3_spec.rb +12 -0
  60. data/spec/lib/parser/const_spec.rb +12 -0
  61. data/spec/lib/parser/cvar_spec.rb +55 -0
  62. data/spec/lib/parser/cvasgn_spec.rb +71 -0
  63. data/spec/lib/parser/cvdecl_spec.rb +31 -0
  64. data/spec/lib/parser/defined_spec.rb +353 -0
  65. data/spec/lib/parser/defn_spec.rb +1409 -0
  66. data/spec/lib/parser/defs_spec.rb +247 -0
  67. data/spec/lib/parser/dot2_spec.rb +29 -0
  68. data/spec/lib/parser/dot3_spec.rb +29 -0
  69. data/spec/lib/parser/dregx_spec.rb +127 -0
  70. data/spec/lib/parser/dstr_spec.rb +453 -0
  71. data/spec/lib/parser/dsym_spec.rb +31 -0
  72. data/spec/lib/parser/dxstr_spec.rb +31 -0
  73. data/spec/lib/parser/ensure_spec.rb +279 -0
  74. data/spec/lib/parser/false_spec.rb +12 -0
  75. data/spec/lib/parser/flip2_spec.rb +138 -0
  76. data/spec/lib/parser/flip3_spec.rb +100 -0
  77. data/spec/lib/parser/for_spec.rb +279 -0
  78. data/spec/lib/parser/gasgn_spec.rb +34 -0
  79. data/spec/lib/parser/gvar_spec.rb +33 -0
  80. data/spec/lib/parser/hash_spec.rb +77 -0
  81. data/spec/lib/parser/iasgn_spec.rb +54 -0
  82. data/spec/lib/parser/if_spec.rb +439 -0
  83. data/spec/lib/parser/iter_spec.rb +2582 -0
  84. data/spec/lib/parser/lasgn_spec.rb +1066 -0
  85. data/spec/lib/parser/lit_spec.rb +75 -0
  86. data/spec/lib/parser/masgn_spec.rb +1970 -0
  87. data/spec/lib/parser/match2_spec.rb +47 -0
  88. data/spec/lib/parser/match3_spec.rb +54 -0
  89. data/spec/lib/parser/match_spec.rb +19 -0
  90. data/spec/lib/parser/module_spec.rb +102 -0
  91. data/spec/lib/parser/nil_spec.rb +13 -0
  92. data/spec/lib/parser/not_spec.rb +39 -0
  93. data/spec/lib/parser/nth_ref_spec.rb +12 -0
  94. data/spec/lib/parser/op_asgn_spec.rb +619 -0
  95. data/spec/lib/parser/or_spec.rb +155 -0
  96. data/spec/lib/parser/postexe_spec.rb +31 -0
  97. data/spec/lib/parser/regex_spec.rb +52 -0
  98. data/spec/lib/parser/rescue_spec.rb +1028 -0
  99. data/spec/lib/parser/return_spec.rb +151 -0
  100. data/spec/lib/parser/sclass_spec.rb +172 -0
  101. data/spec/lib/parser/str_spec.rb +162 -0
  102. data/spec/lib/parser/super_spec.rb +276 -0
  103. data/spec/lib/parser/true_spec.rb +12 -0
  104. data/spec/lib/parser/undef_spec.rb +222 -0
  105. data/spec/lib/parser/until_spec.rb +286 -0
  106. data/spec/lib/parser/valias_spec.rb +12 -0
  107. data/spec/lib/parser/while_spec.rb +458 -0
  108. data/spec/lib/parser/xstr_spec.rb +12 -0
  109. data/spec/lib/parser/yield_spec.rb +202 -0
  110. data/spec/lib/parser/zsuper_spec.rb +101 -0
  111. data/spec/matchers/parse_as.rb +27 -0
  112. data/spec/spec_helper.rb +10 -0
  113. metadata +168 -0
@@ -0,0 +1,245 @@
1
+ /* This file is generated by node_types.rb. Do not edit. */
2
+
3
+ #include "node_types.hpp"
4
+
5
+ namespace melbourne {
6
+
7
+ static const char node_types[] = {
8
+ "method\0"
9
+ "fbody\0"
10
+ "cfunc\0"
11
+ "scope\0"
12
+ "block\0"
13
+ "if\0"
14
+ "case\0"
15
+ "when\0"
16
+ "opt_n\0"
17
+ "while\0"
18
+ "until\0"
19
+ "iter\0"
20
+ "for\0"
21
+ "break\0"
22
+ "next\0"
23
+ "redo\0"
24
+ "retry\0"
25
+ "begin\0"
26
+ "rescue\0"
27
+ "resbody\0"
28
+ "ensure\0"
29
+ "and\0"
30
+ "or\0"
31
+ "not\0"
32
+ "masgn\0"
33
+ "lasgn\0"
34
+ "dasgn\0"
35
+ "dasgn_curr\0"
36
+ "gasgn\0"
37
+ "iasgn\0"
38
+ "cdecl\0"
39
+ "cvasgn\0"
40
+ "cvdecl\0"
41
+ "op_asgn1\0"
42
+ "op_asgn2\0"
43
+ "op_asgn_and\0"
44
+ "op_asgn_or\0"
45
+ "call\0"
46
+ "fcall\0"
47
+ "vcall\0"
48
+ "super\0"
49
+ "zsuper\0"
50
+ "array\0"
51
+ "zarray\0"
52
+ "hash\0"
53
+ "return\0"
54
+ "yield\0"
55
+ "lvar\0"
56
+ "dvar\0"
57
+ "gvar\0"
58
+ "ivar\0"
59
+ "const\0"
60
+ "cvar\0"
61
+ "nth_ref\0"
62
+ "back_ref\0"
63
+ "match\0"
64
+ "match2\0"
65
+ "match3\0"
66
+ "lit\0"
67
+ "str\0"
68
+ "dstr\0"
69
+ "xstr\0"
70
+ "dxstr\0"
71
+ "evstr\0"
72
+ "dregx\0"
73
+ "dregx_once\0"
74
+ "args\0"
75
+ "argscat\0"
76
+ "argspush\0"
77
+ "splat\0"
78
+ "to_ary\0"
79
+ "svalue\0"
80
+ "block_arg\0"
81
+ "block_pass\0"
82
+ "defn\0"
83
+ "defs\0"
84
+ "alias\0"
85
+ "valias\0"
86
+ "undef\0"
87
+ "class\0"
88
+ "module\0"
89
+ "sclass\0"
90
+ "colon2\0"
91
+ "colon3\0"
92
+ "cref\0"
93
+ "dot2\0"
94
+ "dot3\0"
95
+ "flip2\0"
96
+ "flip3\0"
97
+ "attrset\0"
98
+ "self\0"
99
+ "nil\0"
100
+ "true\0"
101
+ "false\0"
102
+ "defined\0"
103
+ "newline\0"
104
+ "postexe\0"
105
+ "dmethod\0"
106
+ "bmethod\0"
107
+ "memo\0"
108
+ "ifunc\0"
109
+ "dsym\0"
110
+ "attrasgn\0"
111
+ "regex\0"
112
+ "fixnum\0"
113
+ "number\0"
114
+ "hexnum\0"
115
+ "binnum\0"
116
+ "octnum\0"
117
+ "float\0"
118
+ "negate\0"
119
+ "last\0"
120
+ "file\0"
121
+ "end_data\0"
122
+ };
123
+
124
+ static const unsigned short node_types_offsets[] = {
125
+ 0,
126
+ 7,
127
+ 13,
128
+ 19,
129
+ 25,
130
+ 31,
131
+ 34,
132
+ 39,
133
+ 44,
134
+ 50,
135
+ 56,
136
+ 62,
137
+ 67,
138
+ 71,
139
+ 77,
140
+ 82,
141
+ 87,
142
+ 93,
143
+ 99,
144
+ 106,
145
+ 114,
146
+ 121,
147
+ 125,
148
+ 128,
149
+ 132,
150
+ 138,
151
+ 144,
152
+ 150,
153
+ 161,
154
+ 167,
155
+ 173,
156
+ 179,
157
+ 186,
158
+ 193,
159
+ 202,
160
+ 211,
161
+ 223,
162
+ 234,
163
+ 239,
164
+ 245,
165
+ 251,
166
+ 257,
167
+ 264,
168
+ 270,
169
+ 277,
170
+ 282,
171
+ 289,
172
+ 295,
173
+ 300,
174
+ 305,
175
+ 310,
176
+ 315,
177
+ 321,
178
+ 326,
179
+ 334,
180
+ 343,
181
+ 349,
182
+ 356,
183
+ 363,
184
+ 367,
185
+ 371,
186
+ 376,
187
+ 381,
188
+ 387,
189
+ 393,
190
+ 399,
191
+ 410,
192
+ 415,
193
+ 423,
194
+ 432,
195
+ 438,
196
+ 445,
197
+ 452,
198
+ 462,
199
+ 473,
200
+ 478,
201
+ 483,
202
+ 489,
203
+ 496,
204
+ 502,
205
+ 508,
206
+ 515,
207
+ 522,
208
+ 529,
209
+ 536,
210
+ 541,
211
+ 546,
212
+ 551,
213
+ 557,
214
+ 563,
215
+ 571,
216
+ 576,
217
+ 580,
218
+ 585,
219
+ 591,
220
+ 599,
221
+ 607,
222
+ 615,
223
+ 623,
224
+ 631,
225
+ 636,
226
+ 642,
227
+ 647,
228
+ 656,
229
+ 662,
230
+ 669,
231
+ 676,
232
+ 683,
233
+ 690,
234
+ 697,
235
+ 703,
236
+ 710,
237
+ 715,
238
+ 720
239
+ };
240
+
241
+ const char *get_node_type_string(enum node_type nt) {
242
+ return node_types + node_types_offsets[nt];
243
+ }
244
+
245
+ }; // namespace melbourne
@@ -0,0 +1,135 @@
1
+ #ifndef MEL_NODE_TYPES_HPP
2
+ #define MEL_NODE_TYPES_HPP
3
+ /* This file is generated by node_types.rb. Do not edit. */
4
+
5
+ #ifdef __cplusplus
6
+ extern "C" {
7
+ #endif
8
+
9
+ namespace melbourne {
10
+
11
+ enum node_type {
12
+ NODE_METHOD,
13
+ NODE_FBODY,
14
+ NODE_CFUNC,
15
+ NODE_SCOPE,
16
+ NODE_BLOCK,
17
+ NODE_IF,
18
+ NODE_CASE,
19
+ NODE_WHEN,
20
+ NODE_OPT_N,
21
+ NODE_WHILE,
22
+ NODE_UNTIL,
23
+ NODE_ITER,
24
+ NODE_FOR,
25
+ NODE_BREAK,
26
+ NODE_NEXT,
27
+ NODE_REDO,
28
+ NODE_RETRY,
29
+ NODE_BEGIN,
30
+ NODE_RESCUE,
31
+ NODE_RESBODY,
32
+ NODE_ENSURE,
33
+ NODE_AND,
34
+ NODE_OR,
35
+ NODE_NOT,
36
+ NODE_MASGN,
37
+ NODE_LASGN,
38
+ NODE_DASGN,
39
+ NODE_DASGN_CURR,
40
+ NODE_GASGN,
41
+ NODE_IASGN,
42
+ NODE_CDECL,
43
+ NODE_CVASGN,
44
+ NODE_CVDECL,
45
+ NODE_OP_ASGN1,
46
+ NODE_OP_ASGN2,
47
+ NODE_OP_ASGN_AND,
48
+ NODE_OP_ASGN_OR,
49
+ NODE_CALL,
50
+ NODE_FCALL,
51
+ NODE_VCALL,
52
+ NODE_SUPER,
53
+ NODE_ZSUPER,
54
+ NODE_ARRAY,
55
+ NODE_ZARRAY,
56
+ NODE_HASH,
57
+ NODE_RETURN,
58
+ NODE_YIELD,
59
+ NODE_LVAR,
60
+ NODE_DVAR,
61
+ NODE_GVAR,
62
+ NODE_IVAR,
63
+ NODE_CONST,
64
+ NODE_CVAR,
65
+ NODE_NTH_REF,
66
+ NODE_BACK_REF,
67
+ NODE_MATCH,
68
+ NODE_MATCH2,
69
+ NODE_MATCH3,
70
+ NODE_LIT,
71
+ NODE_STR,
72
+ NODE_DSTR,
73
+ NODE_XSTR,
74
+ NODE_DXSTR,
75
+ NODE_EVSTR,
76
+ NODE_DREGX,
77
+ NODE_DREGX_ONCE,
78
+ NODE_ARGS,
79
+ NODE_ARGSCAT,
80
+ NODE_ARGSPUSH,
81
+ NODE_SPLAT,
82
+ NODE_TO_ARY,
83
+ NODE_SVALUE,
84
+ NODE_BLOCK_ARG,
85
+ NODE_BLOCK_PASS,
86
+ NODE_DEFN,
87
+ NODE_DEFS,
88
+ NODE_ALIAS,
89
+ NODE_VALIAS,
90
+ NODE_UNDEF,
91
+ NODE_CLASS,
92
+ NODE_MODULE,
93
+ NODE_SCLASS,
94
+ NODE_COLON2,
95
+ NODE_COLON3,
96
+ NODE_CREF,
97
+ NODE_DOT2,
98
+ NODE_DOT3,
99
+ NODE_FLIP2,
100
+ NODE_FLIP3,
101
+ NODE_ATTRSET,
102
+ NODE_SELF,
103
+ NODE_NIL,
104
+ NODE_TRUE,
105
+ NODE_FALSE,
106
+ NODE_DEFINED,
107
+ NODE_NEWLINE,
108
+ NODE_POSTEXE,
109
+ NODE_DMETHOD,
110
+ NODE_BMETHOD,
111
+ NODE_MEMO,
112
+ NODE_IFUNC,
113
+ NODE_DSYM,
114
+ NODE_ATTRASGN,
115
+ NODE_REGEX,
116
+ NODE_FIXNUM,
117
+ NODE_NUMBER,
118
+ NODE_HEXNUM,
119
+ NODE_BINNUM,
120
+ NODE_OCTNUM,
121
+ NODE_FLOAT,
122
+ NODE_NEGATE,
123
+ NODE_LAST,
124
+ NODE_FILE,
125
+ NODE_END_DATA
126
+ };
127
+
128
+ const char *get_node_type_string(enum node_type nt);
129
+
130
+ }; // namespace melbourne
131
+
132
+ #ifdef __cplusplus
133
+ } /* extern "C" */
134
+ #endif
135
+ #endif
@@ -0,0 +1,190 @@
1
+ node_types = %w{
2
+ method
3
+ fbody
4
+ cfunc
5
+ scope
6
+ block
7
+ if
8
+ case
9
+ when
10
+ opt_n
11
+ while
12
+ until
13
+ iter
14
+ for
15
+ break
16
+ next
17
+ redo
18
+ retry
19
+ begin
20
+ rescue
21
+ resbody
22
+ ensure
23
+ and
24
+ or
25
+ not
26
+ masgn
27
+ lasgn
28
+ dasgn
29
+ dasgn_curr
30
+ gasgn
31
+ iasgn
32
+ cdecl
33
+ cvasgn
34
+ cvdecl
35
+ op_asgn1
36
+ op_asgn2
37
+ op_asgn_and
38
+ op_asgn_or
39
+ call
40
+ fcall
41
+ vcall
42
+ super
43
+ zsuper
44
+ array
45
+ zarray
46
+ hash
47
+ return
48
+ yield
49
+ lvar
50
+ dvar
51
+ gvar
52
+ ivar
53
+ const
54
+ cvar
55
+ nth_ref
56
+ back_ref
57
+ match
58
+ match2
59
+ match3
60
+ lit
61
+ str
62
+ dstr
63
+ xstr
64
+ dxstr
65
+ evstr
66
+ dregx
67
+ dregx_once
68
+ args
69
+ argscat
70
+ argspush
71
+ splat
72
+ to_ary
73
+ svalue
74
+ block_arg
75
+ block_pass
76
+ defn
77
+ defs
78
+ alias
79
+ valias
80
+ undef
81
+ class
82
+ module
83
+ sclass
84
+ colon2
85
+ colon3
86
+ cref
87
+ dot2
88
+ dot3
89
+ flip2
90
+ flip3
91
+ attrset
92
+ self
93
+ nil
94
+ true
95
+ false
96
+ defined
97
+ newline
98
+ postexe
99
+ dmethod
100
+ bmethod
101
+ memo
102
+ ifunc
103
+ dsym
104
+ attrasgn
105
+ regex
106
+ fixnum
107
+ number
108
+ hexnum
109
+ binnum
110
+ octnum
111
+ float
112
+ negate
113
+ last
114
+ file
115
+ end_data
116
+ }
117
+
118
+ File.open("node_types.cpp", "w") do |f|
119
+ f.puts <<EOF
120
+ /* This file is generated by node_types.rb. Do not edit. */
121
+
122
+ #include "node_types.hpp"
123
+
124
+ namespace melbourne {
125
+
126
+ static const char node_types[] = {
127
+ EOF
128
+
129
+ node_types.each do |type|
130
+ f.puts(" \"#{type}\\0\"")
131
+ end
132
+
133
+ f.puts(" };")
134
+ f.puts
135
+
136
+ f.puts(" static const unsigned short node_types_offsets[] = {")
137
+ offset = 0
138
+
139
+ node_types.each_with_index do |type, index|
140
+ f.puts(",") if index > 0
141
+ f.write(" #{offset}")
142
+ offset += node_types[index].length + 1
143
+ end
144
+
145
+ f.puts <<EOF
146
+
147
+ };
148
+
149
+ const char *get_node_type_string(enum node_type nt) {
150
+ return node_types + node_types_offsets[nt];
151
+ }
152
+
153
+ }; // namespace melbourne
154
+ EOF
155
+ end
156
+
157
+ File.open("node_types.hpp", "w") do |f|
158
+ f.puts <<EOF
159
+ #ifndef MEL_NODE_TYPES_HPP
160
+ #define MEL_NODE_TYPES_HPP
161
+ /* This file is generated by node_types.rb. Do not edit. */
162
+
163
+ #ifdef __cplusplus
164
+ extern "C" {
165
+ #endif
166
+
167
+ namespace melbourne {
168
+
169
+ enum node_type {
170
+ EOF
171
+
172
+ node_types.each_with_index do |type, index|
173
+ f.puts(",") if index > 0
174
+ f.write(" NODE_#{type.upcase}")
175
+ end
176
+
177
+ f.puts <<EOF
178
+
179
+ };
180
+
181
+ const char *get_node_type_string(enum node_type nt);
182
+
183
+ }; // namespace melbourne
184
+
185
+ #ifdef __cplusplus
186
+ } /* extern "C" */
187
+ #endif
188
+ #endif
189
+ EOF
190
+ end
@@ -0,0 +1,52 @@
1
+ #include "quark.hpp"
2
+ #include <tr1/unordered_map>
3
+ #include <vector>
4
+ #include <string.h>
5
+
6
+ using namespace melbourne;
7
+
8
+ struct ConstCharHash {
9
+ size_t operator() (const char* value) const {
10
+ size_t length = strlen(value);
11
+ size_t hash = 0;
12
+ for (size_t i = 0; i < length; i++) {
13
+ hash = hash * 5 + value[i];
14
+ }
15
+ return hash;
16
+ }
17
+ };
18
+
19
+ struct ConstCharEqualTo {
20
+ bool operator() ( const char* lhs, const char* rhs) const {
21
+ return strcmp(lhs, rhs) == 0;
22
+ }
23
+ };
24
+
25
+ typedef std::tr1::unordered_map<const char*, int, ConstCharHash, ConstCharEqualTo> quark_map;
26
+ typedef std::vector<const char*> quark_vector;
27
+
28
+ static quark_map quark_indexes;
29
+ static quark_vector quarks;
30
+
31
+ quark melbourne::quark_from_string(const char* str) {
32
+ if (str == NULL)
33
+ return QUARK_NOT_FOUND;
34
+
35
+ /* attempt to find it in our cache */
36
+ quark_map::iterator it = quark_indexes.find(str);
37
+ if (it != quark_indexes.end())
38
+ return it->second;
39
+
40
+ /* otherwise, we need to duplicate and store the string */
41
+ const char* new_quark = strdup(str);
42
+ quarks.push_back(new_quark);
43
+ size_t index = quarks.size() - 1;
44
+ quark_indexes.insert(quark_map::value_type(new_quark,index));
45
+ return index;
46
+ }
47
+
48
+ const char* melbourne::quark_to_string(quark q) {
49
+ if (q >= quarks.size())
50
+ return NULL;
51
+ return quarks[q];
52
+ }
@@ -0,0 +1,14 @@
1
+ #ifndef MEL_QUARK_HPP
2
+ #define MEL_QUARK_HPP
3
+
4
+ #include <cstddef>
5
+
6
+ namespace melbourne {
7
+ typedef size_t quark;
8
+ enum {QUARK_NOT_FOUND = ~0L};
9
+
10
+ quark quark_from_string(const char* str);
11
+ const char* quark_to_string(const quark quark);
12
+ }
13
+ #endif
14
+