gqlite 1.5.1 → 1.7.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. checksums.yaml +4 -4
  2. data/ext/Cargo.toml +10 -4
  3. data/ext/db-index/Cargo.toml +29 -0
  4. data/ext/db-index/src/hnsw/error.rs +66 -0
  5. data/ext/db-index/src/hnsw/graph_store.rs +272 -0
  6. data/ext/db-index/src/hnsw/id.rs +36 -0
  7. data/ext/db-index/src/hnsw/implementation.rs +1517 -0
  8. data/ext/db-index/src/hnsw/kernels.rs +1228 -0
  9. data/ext/db-index/src/hnsw/metric.rs +244 -0
  10. data/ext/db-index/src/hnsw/scalar.rs +72 -0
  11. data/ext/db-index/src/hnsw/simple_store.rs +140 -0
  12. data/ext/db-index/src/hnsw/store.rs +472 -0
  13. data/ext/db-index/src/hnsw/vector.rs +105 -0
  14. data/ext/db-index/src/hnsw/vectors.rs +568 -0
  15. data/ext/db-index/src/hnsw.rs +42 -0
  16. data/ext/db-index/src/lib.rs +3 -0
  17. data/ext/gqlitedb/Cargo.toml +19 -9
  18. data/ext/gqlitedb/benches/common/pokec.rs +62 -2
  19. data/ext/gqlitedb/benches/pokec_divan.rs +66 -2
  20. data/ext/gqlitedb/benches/pokec_iai.rs +60 -3
  21. data/ext/gqlitedb/release.toml +2 -2
  22. data/ext/gqlitedb/src/aggregators/arithmetic.rs +3 -1
  23. data/ext/gqlitedb/src/aggregators/containers.rs +1 -1
  24. data/ext/gqlitedb/src/aggregators/stats.rs +21 -12
  25. data/ext/gqlitedb/src/capi.rs +1 -1
  26. data/ext/gqlitedb/src/compiler/expression_analyser.rs +28 -20
  27. data/ext/gqlitedb/src/compiler/variables_manager.rs +97 -29
  28. data/ext/gqlitedb/src/compiler.rs +505 -225
  29. data/ext/gqlitedb/src/connection.rs +149 -11
  30. data/ext/gqlitedb/src/consts.rs +1 -2
  31. data/ext/gqlitedb/src/error.rs +123 -61
  32. data/ext/gqlitedb/src/functions/common.rs +39 -2
  33. data/ext/gqlitedb/src/functions/math.rs +8 -3
  34. data/ext/gqlitedb/src/functions/path.rs +48 -11
  35. data/ext/gqlitedb/src/functions/value.rs +1 -1
  36. data/ext/gqlitedb/src/functions.rs +23 -7
  37. data/ext/gqlitedb/src/graph.rs +1 -9
  38. data/ext/gqlitedb/src/interpreter/evaluators.rs +968 -130
  39. data/ext/gqlitedb/src/interpreter/instructions.rs +39 -2
  40. data/ext/gqlitedb/src/lib.rs +5 -4
  41. data/ext/gqlitedb/src/planner.rs +329 -0
  42. data/ext/gqlitedb/src/prelude.rs +3 -3
  43. data/ext/gqlitedb/src/store/pgrx.rs +1 -1
  44. data/ext/gqlitedb/src/store/postgres.rs +735 -7
  45. data/ext/gqlitedb/src/store/redb/hnsw_store.rs +702 -0
  46. data/ext/gqlitedb/src/store/redb/index.rs +274 -0
  47. data/ext/gqlitedb/src/store/redb.rs +1268 -113
  48. data/ext/gqlitedb/src/store/sqlbase/sqlmetadata.rs +28 -0
  49. data/ext/gqlitedb/src/store/sqlbase/sqlstore.rs +103 -0
  50. data/ext/gqlitedb/src/store/sqlbase.rs +146 -16
  51. data/ext/gqlitedb/src/store/sqlite.rs +569 -5
  52. data/ext/gqlitedb/src/store/vector_extract.rs +56 -0
  53. data/ext/gqlitedb/src/store.rs +123 -3
  54. data/ext/gqlitedb/src/tests/compiler.rs +207 -10
  55. data/ext/gqlitedb/src/tests/connection/postgres.rs +38 -3
  56. data/ext/gqlitedb/src/tests/connection/redb.rs +23 -0
  57. data/ext/gqlitedb/src/tests/connection/sqlite.rs +31 -0
  58. data/ext/gqlitedb/src/tests/connection.rs +61 -1
  59. data/ext/gqlitedb/src/tests/evaluators.rs +162 -7
  60. data/ext/gqlitedb/src/tests/parser.rs +54 -23
  61. data/ext/gqlitedb/src/tests/planner.rs +511 -0
  62. data/ext/gqlitedb/src/tests/store/postgres.rs +7 -0
  63. data/ext/gqlitedb/src/tests/store/redb.rs +8 -0
  64. data/ext/gqlitedb/src/tests/store/sqlite.rs +8 -0
  65. data/ext/gqlitedb/src/tests/store/vector_index/postgres.rs +182 -0
  66. data/ext/gqlitedb/src/tests/store/vector_index/redb.rs +386 -0
  67. data/ext/gqlitedb/src/tests/store/vector_index/sqlite.rs +166 -0
  68. data/ext/gqlitedb/src/tests/store/vector_index.rs +2313 -0
  69. data/ext/gqlitedb/src/tests/store.rs +78 -14
  70. data/ext/gqlitedb/src/tests/templates/ast.rs +92 -16
  71. data/ext/gqlitedb/src/tests/templates/programs.rs +14 -7
  72. data/ext/gqlitedb/src/tests.rs +15 -9
  73. data/ext/gqlitedb/src/utils.rs +6 -1
  74. data/ext/gqlitedb/src/value/compare.rs +61 -3
  75. data/ext/gqlitedb/src/value.rs +136 -7
  76. data/ext/gqlitedb/templates/sql/postgres/metadata_delete.sql +1 -0
  77. data/ext/gqlitedb/templates/sql/postgres/node_select.sql +1 -1
  78. data/ext/gqlitedb/templates/sql/sqlite/metadata_delete.sql +1 -0
  79. data/ext/gqliterb/src/lib.rs +53 -8
  80. data/ext/gqlparser/Cargo.toml +25 -0
  81. data/ext/gqlparser/README.MD +9 -0
  82. data/ext/gqlparser/benches/pokec_divan.rs +34 -0
  83. data/ext/gqlparser/src/common.rs +69 -0
  84. data/ext/gqlparser/src/gqls/ast.rs +69 -0
  85. data/ext/gqlparser/src/gqls/constraint.rs +79 -0
  86. data/ext/gqlparser/src/gqls/error.rs +22 -0
  87. data/ext/gqlparser/src/gqls/parser.rs +813 -0
  88. data/ext/gqlparser/src/gqls/prelude.rs +8 -0
  89. data/ext/gqlparser/src/gqls/properties.rs +115 -0
  90. data/ext/gqlparser/src/gqls/resolve.rs +207 -0
  91. data/ext/gqlparser/src/gqls.rs +265 -0
  92. data/ext/gqlparser/src/lib.rs +7 -0
  93. data/ext/gqlparser/src/oc/ast.rs +680 -0
  94. data/ext/gqlparser/src/oc/error.rs +172 -0
  95. data/ext/gqlparser/src/oc/lexer.rs +429 -0
  96. data/ext/gqlparser/src/oc/parser/tests.rs +2284 -0
  97. data/ext/gqlparser/src/oc/parser.rs +2005 -0
  98. data/ext/gqlparser/src/oc.rs +33 -0
  99. data/ext/gqlparser/src/prelude.rs +3 -0
  100. data/ext/graphcore/Cargo.toml +1 -0
  101. data/ext/graphcore/src/error.rs +26 -0
  102. data/ext/graphcore/src/graph.rs +177 -51
  103. data/ext/graphcore/src/lib.rs +4 -2
  104. data/ext/graphcore/src/open_cypher.rs +12 -0
  105. data/ext/graphcore/src/table.rs +50 -2
  106. data/ext/graphcore/src/timestamp.rs +127 -104
  107. data/ext/graphcore/src/value/tensor.rs +739 -0
  108. data/ext/graphcore/src/value/value_map.rs +1 -1
  109. data/ext/graphcore/src/value.rs +343 -19
  110. metadata +90 -22
  111. data/ext/gqlitedb/src/parser/ast.rs +0 -604
  112. data/ext/gqlitedb/src/parser/parser_impl.rs +0 -1213
  113. data/ext/gqlitedb/src/parser.rs +0 -4
@@ -0,0 +1,172 @@
1
+ #[derive(Debug, PartialEq, Clone)]
2
+ pub struct TokensVec(pub(crate) Vec<super::lexer::Token>);
3
+
4
+ impl From<Vec<super::lexer::Token>> for TokensVec
5
+ {
6
+ fn from(value: Vec<super::lexer::Token>) -> Self
7
+ {
8
+ Self(value)
9
+ }
10
+ }
11
+
12
+ #[derive(Debug, PartialEq, Clone)]
13
+ #[allow(missing_docs)]
14
+ #[non_exhaustive]
15
+ pub enum ErrorKind
16
+ {
17
+ LexError,
18
+ FloatingPointOverflow,
19
+ IntegerOverflow,
20
+ MalformedInteger,
21
+ MalformedFloatingPoint,
22
+ ExpectedTokens(TokensVec),
23
+ UnexpectedToken,
24
+ ConflictingEdgeDirections,
25
+ PathAcceptSingleEdge,
26
+ RequiresDirectedEdge,
27
+ NoSingleRelationshipType,
28
+ MixedUnionOperators,
29
+ VariableNotFound,
30
+ }
31
+
32
+ pub(crate) fn parse_int_error_to_error_kind(e: std::num::ParseIntError) -> ErrorKind
33
+ {
34
+ match e.kind()
35
+ {
36
+ std::num::IntErrorKind::Empty | std::num::IntErrorKind::InvalidDigit =>
37
+ {
38
+ ErrorKind::MalformedInteger
39
+ }
40
+ std::num::IntErrorKind::PosOverflow | std::num::IntErrorKind::NegOverflow =>
41
+ {
42
+ ErrorKind::IntegerOverflow
43
+ }
44
+ _ => unreachable!(),
45
+ }
46
+ }
47
+
48
+ #[derive(Debug, PartialEq, Clone)]
49
+ pub struct Error
50
+ {
51
+ pub(crate) kind: ErrorKind,
52
+ pub(crate) span: std::ops::Range<usize>,
53
+ }
54
+
55
+ impl Error
56
+ {
57
+ pub fn span(&self) -> &std::ops::Range<usize>
58
+ {
59
+ &self.span
60
+ }
61
+ pub fn error_kind(&self) -> &ErrorKind
62
+ {
63
+ &self.kind
64
+ }
65
+ pub fn nice_error_string(&self, source: &str) -> String
66
+ {
67
+ let error_message = format!("{}", self);
68
+ let error_span = self.span();
69
+ let error_snippet = &source[error_span.clone()];
70
+ format!(
71
+ "Error at {}..{}: '{error_snippet}': {error_message}",
72
+ error_span.start, error_span.end
73
+ )
74
+ }
75
+ pub(crate) fn new(kind: ErrorKind, span: std::ops::Range<usize>) -> Self
76
+ {
77
+ Self { kind, span }
78
+ }
79
+ pub(crate) fn from_parse_int_error(
80
+ e: std::num::ParseIntError,
81
+ span: std::ops::Range<usize>,
82
+ ) -> Self
83
+ {
84
+ match e.kind()
85
+ {
86
+ std::num::IntErrorKind::Empty | std::num::IntErrorKind::InvalidDigit =>
87
+ {
88
+ Self::new(ErrorKind::MalformedInteger, span)
89
+ }
90
+ std::num::IntErrorKind::PosOverflow | std::num::IntErrorKind::NegOverflow =>
91
+ {
92
+ Self::new(ErrorKind::IntegerOverflow, span)
93
+ }
94
+ _ => unreachable!(),
95
+ }
96
+ }
97
+ }
98
+
99
+ ccutils::assert_impl_all!(Error: std::error::Error);
100
+
101
+ impl std::error::Error for Error {}
102
+
103
+ impl std::fmt::Display for Error
104
+ {
105
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
106
+ {
107
+ match &self.kind
108
+ {
109
+ ErrorKind::LexError => write!(f, "LexError at {}..{}.", self.span.start, self.span.end),
110
+ ErrorKind::FloatingPointOverflow => write!(
111
+ f,
112
+ "FloatingPointOverflow: is too large to fit in a floating-point number at {}..{}.",
113
+ self.span.start, self.span.end
114
+ ),
115
+ ErrorKind::IntegerOverflow => write!(
116
+ f,
117
+ "IntegerOverflow: is too large to fit in an integer at {}..{}.",
118
+ self.span.start, self.span.end
119
+ ),
120
+ ErrorKind::MalformedInteger => write!(
121
+ f,
122
+ "MalformedInteger: is not a valid integer at {}..{}.",
123
+ self.span.start, self.span.end
124
+ ),
125
+ ErrorKind::MalformedFloatingPoint => write!(
126
+ f,
127
+ "MalformedFloatingPoint: is not a valid floating-point number at {}..{}.",
128
+ self.span.start, self.span.end
129
+ ),
130
+ ErrorKind::ExpectedTokens(expected) => write!(
131
+ f,
132
+ "ExpectedTokens: expected one of {:?} at {}..{}.",
133
+ expected.0, self.span.start, self.span.end
134
+ ),
135
+ ErrorKind::UnexpectedToken => write!(
136
+ f,
137
+ "UnexpectedToken: unexpected token at {}..{}.",
138
+ self.span.start, self.span.end
139
+ ),
140
+ ErrorKind::ConflictingEdgeDirections => write!(
141
+ f,
142
+ "ConflictingEdgeDirections: conflicting edge directions at {}..{}.",
143
+ self.span.start, self.span.end
144
+ ),
145
+ ErrorKind::PathAcceptSingleEdge => write!(
146
+ f,
147
+ "PathAcceptSingleEdge: path patterns must consist of a single edge at {}..{}.",
148
+ self.span.start, self.span.end
149
+ ),
150
+ ErrorKind::RequiresDirectedEdge => write!(
151
+ f,
152
+ "RequiresDirectedEdge: path patterns must consist of directed edges at {}..{}.",
153
+ self.span.start, self.span.end
154
+ ),
155
+ ErrorKind::NoSingleRelationshipType => write!(
156
+ f,
157
+ "NoSingleRelationshipType: edge patterns must have exactly one relationship type at {}..{}.",
158
+ self.span.start, self.span.end
159
+ ),
160
+ ErrorKind::MixedUnionOperators => write!(
161
+ f,
162
+ "MixedUnionOperators: cannot mix UNION and UNION ALL in the same query at {}..{}.",
163
+ self.span.start, self.span.end
164
+ ),
165
+ ErrorKind::VariableNotFound => write!(
166
+ f,
167
+ "VariableNotFound: variable in SEARCH clause not found in MATCH pattern at {}..{}.",
168
+ self.span.start, self.span.end
169
+ ),
170
+ }
171
+ }
172
+ }
@@ -0,0 +1,429 @@
1
+ use logos::Logos;
2
+
3
+ use super::{Error, Result};
4
+
5
+ #[derive(Logos, Debug, PartialEq, Clone, Copy)]
6
+ #[logos(skip r"[ \t\n\r]+")]
7
+ pub(crate) enum Token
8
+ {
9
+ #[regex(r"//[^\n\r]*", logos::skip, allow_greedy = true)]
10
+ Comment,
11
+
12
+ #[token("and", ignore(case))]
13
+ And,
14
+ #[token("all", ignore(case))]
15
+ All,
16
+ #[token("as", ignore(case))]
17
+ As,
18
+ #[token("asc", ignore(case))]
19
+ #[token("ascending", ignore(case))]
20
+ Asc,
21
+ #[token("by", ignore(case))]
22
+ By,
23
+ #[token("call", ignore(case))]
24
+ Call,
25
+ #[token("desc", ignore(case))]
26
+ #[token("descending", ignore(case))]
27
+ Desc,
28
+ #[token("create", ignore(case))]
29
+ Create,
30
+ #[token("delete", ignore(case))]
31
+ Delete,
32
+ #[token("detach", ignore(case))]
33
+ Detach,
34
+ #[token("drop", ignore(case))]
35
+ Drop,
36
+ #[token("exists", ignore(case))]
37
+ Exists,
38
+ #[token("for", ignore(case))]
39
+ For,
40
+ #[token("false", ignore(case))]
41
+ False,
42
+ #[token("graph", ignore(case))]
43
+ Graph,
44
+ #[token("if", ignore(case))]
45
+ If,
46
+ #[token("index", ignore(case))]
47
+ Index,
48
+ #[token("in", ignore(case))]
49
+ In,
50
+ #[token("is", ignore(case))]
51
+ Is,
52
+ #[token("limit", ignore(case))]
53
+ Limit,
54
+ #[token("match", ignore(case))]
55
+ Match,
56
+ #[token("merge", ignore(case))]
57
+ Merge,
58
+ #[token("remove", ignore(case))]
59
+ Remove,
60
+ #[token("return", ignore(case))]
61
+ Return,
62
+ #[token("score", ignore(case))]
63
+ Score,
64
+ #[token("search", ignore(case))]
65
+ Search,
66
+ #[token("set", ignore(case))]
67
+ Set,
68
+ #[token("not", ignore(case))]
69
+ Not,
70
+ #[token("null", ignore(case))]
71
+ Null,
72
+ #[token("or", ignore(case))]
73
+ Or,
74
+ #[token("on", ignore(case))]
75
+ On,
76
+ #[token("order", ignore(case))]
77
+ Order,
78
+ #[token("optional", ignore(case))]
79
+ Optional,
80
+ #[token("options", ignore(case))]
81
+ Options,
82
+ #[token("skip", ignore(case))]
83
+ Skip,
84
+ #[token("true", ignore(case))]
85
+ True,
86
+ #[token("union", ignore(case))]
87
+ Union,
88
+ #[token("update", ignore(case))]
89
+ Update,
90
+ #[token("unwind", ignore(case))]
91
+ Unwind,
92
+ #[token("use", ignore(case))]
93
+ Use,
94
+ #[token("vector", ignore(case))]
95
+ Vector,
96
+ #[token("with", ignore(case))]
97
+ With,
98
+ #[token("where", ignore(case))]
99
+ Where,
100
+ #[token("xor", ignore(case))]
101
+ Xor,
102
+ #[token("=")]
103
+ Equal,
104
+ #[token("<>")]
105
+ Different,
106
+ #[token("<=")]
107
+ LessEqual,
108
+ #[token(">=")]
109
+ GreaterEqual,
110
+ #[token("->")]
111
+ RightArrow,
112
+ #[token("<-")]
113
+ LeftArrow,
114
+ #[token("<")]
115
+ Less,
116
+ #[token(">")]
117
+ Greater,
118
+ #[token("-")]
119
+ Minus,
120
+ #[token("+")]
121
+ Plus,
122
+ #[token("/")]
123
+ Slash,
124
+ #[token("%")]
125
+ Percent,
126
+ #[token("^")]
127
+ Caret,
128
+ #[token("..")]
129
+ DotDot,
130
+ #[token(".")]
131
+ Dot,
132
+ #[token("*")]
133
+ Star,
134
+ #[token("+=")]
135
+ PlusEqual,
136
+ #[token(",")]
137
+ Comma,
138
+ #[token("(")]
139
+ StartParenthesis,
140
+ #[token(")")]
141
+ EndParenthesis,
142
+ #[token("{")]
143
+ StartBrace,
144
+
145
+ #[token("}")]
146
+ EndBrace,
147
+ #[token("[")]
148
+ StartBracket,
149
+ #[token("]")]
150
+ EndBracket,
151
+ #[token(":")]
152
+ Colon,
153
+ #[token(";")]
154
+ Semi,
155
+ #[token("|")]
156
+ Pipe,
157
+ #[regex(r"\$[a-zA-Z0-9_]+")]
158
+ ParameterName,
159
+ #[regex(r"[a-zA-Z_][a-zA-Z0-9_]*")]
160
+ Identifier,
161
+ #[regex(r"0[xX][0-9a-fA-F]+")]
162
+ HexaDecimal,
163
+ #[regex(r"0[oO][0-7]+")]
164
+ OctaDecimal,
165
+ #[regex(r"[1-9]\d*|0")]
166
+ Integer,
167
+ #[regex(r"(?:0|[1-9]\d*)\.(?:\d*|\d*[eE][+-]?\d+)?")]
168
+ #[regex(r"(?:0|[1-9]\d*)[eE][+-]?\d+")]
169
+ #[regex(r"\.\d+(?:[eE][+-]?\d+)?")]
170
+ Number,
171
+ #[regex(r"[+-]?(?:0|[1-9]\d*)\.\.")]
172
+ IntegerDotDot,
173
+ #[regex(r#""([^"\\\x00-\x1F]|\\.)*""#)]
174
+ #[regex(r#"'([^'\\\x00-\x1F]|\\.)*'"#)]
175
+ #[regex(r#"`([^`\\\x00-\x1F]|\\.)*`"#)]
176
+ String,
177
+ }
178
+
179
+ impl Token
180
+ {
181
+ pub(crate) fn is_keyword(&self) -> bool
182
+ {
183
+ matches!(
184
+ self,
185
+ Token::And
186
+ | Token::As
187
+ | Token::Asc
188
+ | Token::By
189
+ | Token::Call
190
+ | Token::Desc
191
+ | Token::Create
192
+ | Token::Delete
193
+ | Token::Detach
194
+ | Token::Drop
195
+ | Token::Exists
196
+ | Token::For
197
+ | Token::False
198
+ | Token::Graph
199
+ | Token::If
200
+ | Token::Index
201
+ | Token::In
202
+ | Token::Is
203
+ | Token::Limit
204
+ | Token::Match
205
+ | Token::Merge
206
+ | Token::Not
207
+ | Token::Null
208
+ | Token::On
209
+ | Token::Or
210
+ | Token::Order
211
+ | Token::Optional
212
+ | Token::Options
213
+ | Token::Return
214
+ | Token::Score
215
+ | Token::Search
216
+ | Token::Set
217
+ | Token::Skip
218
+ | Token::True
219
+ | Token::Union
220
+ | Token::Update
221
+ | Token::Unwind
222
+ | Token::Use
223
+ | Token::Vector
224
+ | Token::With
225
+ | Token::Where
226
+ | Token::Xor
227
+ )
228
+ }
229
+ }
230
+
231
+ #[derive(Debug, PartialEq, Clone)]
232
+ pub(crate) struct Spanned<T>
233
+ {
234
+ pub(crate) value: T,
235
+ pub(crate) span: std::ops::Range<usize>,
236
+ }
237
+
238
+ pub(crate) type SpannedToken = Spanned<Token>;
239
+
240
+ pub(crate) fn tokenize(input: &str) -> Result<Vec<SpannedToken>>
241
+ {
242
+ let mut tokens = Vec::new();
243
+ let mut lexer = Token::lexer(input);
244
+ while let Some(token) = lexer.next()
245
+ {
246
+ tokens.push(Spanned {
247
+ value: token.map_err(|_| Error::new(crate::oc::error::ErrorKind::LexError, lexer.span()))?,
248
+ span: lexer.span(),
249
+ });
250
+ }
251
+ Ok(tokens)
252
+ }
253
+
254
+ #[cfg(test)]
255
+ mod tests
256
+ {
257
+ use crate::oc::lexer::{Spanned, Token, tokenize};
258
+
259
+ #[test]
260
+ fn test_oc_lexer_float()
261
+ {
262
+ assert_eq!(
263
+ tokenize(".1e-5").unwrap(),
264
+ vec![Spanned {
265
+ value: Token::Number,
266
+ span: 0..5
267
+ }]
268
+ );
269
+ assert_eq!(
270
+ tokenize("1.").unwrap(),
271
+ vec![Spanned {
272
+ value: Token::Number,
273
+ span: 0..2
274
+ }]
275
+ );
276
+ assert_eq!(
277
+ tokenize("1.0").unwrap(),
278
+ vec![Spanned {
279
+ value: Token::Number,
280
+ span: 0..3
281
+ }]
282
+ );
283
+ assert_eq!(
284
+ tokenize("1.0e3").unwrap(),
285
+ vec![Spanned {
286
+ value: Token::Number,
287
+ span: 0..5
288
+ }]
289
+ );
290
+ assert_eq!(
291
+ tokenize("2E-01").unwrap(),
292
+ vec![Spanned {
293
+ value: Token::Number,
294
+ span: 0..5
295
+ }]
296
+ );
297
+ }
298
+ #[test]
299
+ fn test_oc_lexer_int()
300
+ {
301
+ assert_eq!(
302
+ tokenize("123").unwrap(),
303
+ vec![Spanned {
304
+ value: Token::Integer,
305
+ span: 0..3
306
+ }]
307
+ );
308
+ assert_eq!(
309
+ tokenize("0x123").unwrap(),
310
+ vec![Spanned {
311
+ value: Token::HexaDecimal,
312
+ span: 0..5
313
+ }]
314
+ );
315
+ assert_eq!(
316
+ tokenize("0o123").unwrap(),
317
+ vec![Spanned {
318
+ value: Token::OctaDecimal,
319
+ span: 0..5
320
+ }]
321
+ );
322
+ assert_eq!(
323
+ tokenize("0o1000000000000000000000").unwrap(),
324
+ vec![Spanned {
325
+ value: Token::OctaDecimal,
326
+ span: 0..24
327
+ }]
328
+ );
329
+ }
330
+ #[test]
331
+ fn test_oc_lexer_range_access()
332
+ {
333
+ assert_eq!(
334
+ tokenize("arr[1..2]").unwrap(),
335
+ vec![
336
+ Spanned {
337
+ value: Token::Identifier,
338
+ span: 0..3
339
+ },
340
+ Spanned {
341
+ value: Token::StartBracket,
342
+ span: 3..4
343
+ },
344
+ Spanned {
345
+ value: Token::IntegerDotDot,
346
+ span: 4..7
347
+ },
348
+ Spanned {
349
+ value: Token::Integer,
350
+ span: 7..8
351
+ },
352
+ Spanned {
353
+ value: Token::EndBracket,
354
+ span: 8..9
355
+ },
356
+ ]
357
+ );
358
+ }
359
+ #[test]
360
+ fn test_oc_lexer_return_carriages()
361
+ {
362
+ // Test Windows line endings
363
+ assert_eq!(
364
+ tokenize("a\r\nb").unwrap(),
365
+ vec![
366
+ Spanned {
367
+ value: Token::Identifier,
368
+ span: 0..1
369
+ },
370
+ Spanned {
371
+ value: Token::Identifier,
372
+ span: 3..4
373
+ },
374
+ ]
375
+ );
376
+
377
+ // Test Unix/Linux line endings
378
+ assert_eq!(
379
+ tokenize("a\nb").unwrap(),
380
+ vec![
381
+ Spanned {
382
+ value: Token::Identifier,
383
+ span: 0..1
384
+ },
385
+ Spanned {
386
+ value: Token::Identifier,
387
+ span: 2..3
388
+ },
389
+ ]
390
+ );
391
+
392
+ // Test Old Mac OS line endings
393
+ assert_eq!(
394
+ tokenize("a\rb").unwrap(),
395
+ vec![
396
+ Spanned {
397
+ value: Token::Identifier,
398
+ span: 0..1
399
+ },
400
+ Spanned {
401
+ value: Token::Identifier,
402
+ span: 2..3
403
+ },
404
+ ]
405
+ );
406
+ }
407
+
408
+ #[test]
409
+ fn test_oc_lexer_strings()
410
+ {
411
+ assert_eq!(
412
+ tokenize(r#""12", "foo""#).unwrap(),
413
+ vec![
414
+ Spanned {
415
+ value: Token::String,
416
+ span: 0..4
417
+ },
418
+ Spanned {
419
+ value: Token::Comma,
420
+ span: 4..5
421
+ },
422
+ Spanned {
423
+ value: Token::String,
424
+ span: 7..12
425
+ },
426
+ ]
427
+ );
428
+ }
429
+ }