UNPKG

3.5 kBPlain TextView Raw
1/*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#import "RCTParserUtils.h"
9
10#import "RCTLog.h"
11
12@implementation RCTParserUtils
13
14BOOL RCTReadChar(const char **input, char c)
15{
16 if (**input == c) {
17 (*input)++;
18 return YES;
19 }
20 return NO;
21}
22
23BOOL RCTReadString(const char **input, const char *string)
24{
25 int i;
26 for (i = 0; string[i] != 0; i++) {
27 if (string[i] != (*input)[i]) {
28 return NO;
29 }
30 }
31 *input += i;
32 return YES;
33}
34
35void RCTSkipWhitespace(const char **input)
36{
37 while (isspace(**input)) {
38 (*input)++;
39 }
40}
41
42static BOOL RCTIsIdentifierHead(const char c)
43{
44 return isalpha(c) || c == '_';
45}
46
47static BOOL RCTIsIdentifierTail(const char c)
48{
49 return isalnum(c) || c == '_';
50}
51
52BOOL RCTParseArgumentIdentifier(const char **input, NSString **string)
53{
54 const char *start = *input;
55
56 do {
57 if (!RCTIsIdentifierHead(**input)) {
58 return NO;
59 }
60 (*input)++;
61
62 while (RCTIsIdentifierTail(**input)) {
63 (*input)++;
64 }
65
66 // allow namespace resolution operator
67 } while (RCTReadString(input, "::"));
68
69 if (string) {
70 *string = [[NSString alloc] initWithBytes:start
71 length:(NSInteger)(*input - start)
72 encoding:NSASCIIStringEncoding];
73 }
74 return YES;
75}
76
77BOOL RCTParseSelectorIdentifier(const char **input, NSString **string)
78{
79 const char *start = *input;
80 if (!RCTIsIdentifierHead(**input)) {
81 return NO;
82 }
83 (*input)++;
84 while (RCTIsIdentifierTail(**input)) {
85 (*input)++;
86 }
87 if (string) {
88 *string = [[NSString alloc] initWithBytes:start
89 length:(NSInteger)(*input - start)
90 encoding:NSASCIIStringEncoding];
91 }
92 return YES;
93}
94
95static BOOL RCTIsCollectionType(NSString *type)
96{
97 static NSSet *collectionTypes;
98 static dispatch_once_t onceToken;
99 dispatch_once(&onceToken, ^{
100 collectionTypes = [[NSSet alloc] initWithObjects:
101 @"NSArray", @"NSSet", @"NSDictionary", nil];
102 });
103 return [collectionTypes containsObject:type];
104}
105
106NSString *RCTParseType(const char **input)
107{
108 NSString *type;
109 RCTParseArgumentIdentifier(input, &type);
110 RCTSkipWhitespace(input);
111 if (RCTReadChar(input, '<')) {
112 RCTSkipWhitespace(input);
113 NSString *subtype = RCTParseType(input);
114 if (RCTIsCollectionType(type)) {
115 if ([type isEqualToString:@"NSDictionary"]) {
116 // Dictionaries have both a key *and* value type, but the key type has
117 // to be a string for JSON, so we only care about the value type
118 if (RCT_DEBUG && ![subtype isEqualToString:@"NSString"]) {
119 RCTLogError(@"%@ is not a valid key type for a JSON dictionary", subtype);
120 }
121 RCTSkipWhitespace(input);
122 RCTReadChar(input, ',');
123 RCTSkipWhitespace(input);
124 subtype = RCTParseType(input);
125 }
126 if (![subtype isEqualToString:@"id"]) {
127 type = [type stringByReplacingCharactersInRange:(NSRange){0, 2 /* "NS" */}
128 withString:subtype];
129 }
130 } else {
131 // It's a protocol rather than a generic collection - ignore it
132 }
133 RCTSkipWhitespace(input);
134 RCTReadChar(input, '>');
135 }
136 RCTSkipWhitespace(input);
137 if (!RCTReadChar(input, '*')) {
138 RCTReadChar(input, '&');
139 }
140 return type;
141}
142
143@end