nadata 0.1.0__py3-none-any.whl

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 (86) hide show
  1. nadata/__init__.py +15 -0
  2. nadata/api.py +894 -0
  3. nadata/cli.py +445 -0
  4. nadata/console.py +486 -0
  5. nadata/core/__init__.py +0 -0
  6. nadata/core/database/__init__.py +38 -0
  7. nadata/core/database/builtins.py +87 -0
  8. nadata/core/database/database.py +958 -0
  9. nadata/core/database/dumper.py +285 -0
  10. nadata/core/database/entity_id.py +142 -0
  11. nadata/core/database/instance.py +706 -0
  12. nadata/core/database/network_index.py +1142 -0
  13. nadata/core/database/page_manager.py +175 -0
  14. nadata/core/database/persistence/__init__.py +28 -0
  15. nadata/core/database/persistence/binary_cells.py +1141 -0
  16. nadata/core/database/persistence/compaction.py +97 -0
  17. nadata/core/database/persistence/dumper.py +798 -0
  18. nadata/core/database/persistence/lazy_instances.py +1537 -0
  19. nadata/core/database/persistence/loader.py +424 -0
  20. nadata/core/database/persistence/record_store.py +228 -0
  21. nadata/core/database/persistence/serialization.py +605 -0
  22. nadata/core/database/query_engine.py +222 -0
  23. nadata/core/database/queryset.py +508 -0
  24. nadata/core/database/reconciliation.py +287 -0
  25. nadata/core/database/slotted_page.py +190 -0
  26. nadata/core/database/spatial_index.py +1080 -0
  27. nadata/core/expressions/__init__.py +44 -0
  28. nadata/core/expressions/autograd.py +2909 -0
  29. nadata/core/expressions/builtins.py +4673 -0
  30. nadata/core/expressions/expression.py +2658 -0
  31. nadata/core/expressions/io_builtins.py +972 -0
  32. nadata/core/expressions/scope.py +336 -0
  33. nadata/core/expressions/statement.py +953 -0
  34. nadata/core/struct/__init__.py +14 -0
  35. nadata/core/struct/struct.py +218 -0
  36. nadata/core/struct/struct_attribute.py +100 -0
  37. nadata/core/struct/struct_method.py +324 -0
  38. nadata/core/types/__init__.py +33 -0
  39. nadata/core/types/bits/__init__.py +0 -0
  40. nadata/core/types/bits/bits.py +686 -0
  41. nadata/core/types/home_types/__init__.py +19 -0
  42. nadata/core/types/home_types/color.py +102 -0
  43. nadata/core/types/home_types/coordinate.py +1008 -0
  44. nadata/core/types/home_types/datetime.py +362 -0
  45. nadata/core/types/home_types/geogrid.py +92 -0
  46. nadata/core/types/home_types/geometry.py +1223 -0
  47. nadata/core/types/home_types/graph.py +0 -0
  48. nadata/core/types/home_types/planet.py +359 -0
  49. nadata/core/types/home_types/sea_level.py +98 -0
  50. nadata/core/types/home_types/vec.py +0 -0
  51. nadata/core/types/types.py +1345 -0
  52. nadata/core/values/__init__.py +14 -0
  53. nadata/core/values/values.py +1568 -0
  54. nadata/parser/__init__.py +0 -0
  55. nadata/parser/expressions/__init__.py +6 -0
  56. nadata/parser/expressions/dependencies.py +318 -0
  57. nadata/parser/expressions/expression_parser.py +993 -0
  58. nadata/parser/expressions/splitter.py +98 -0
  59. nadata/parser/expressions/statement_parser.py +1425 -0
  60. nadata/parser/expressions/tokenizer.py +402 -0
  61. nadata/parser/expressions/type_parser.py +187 -0
  62. nadata/parser/nadata_loader/__init__.py +8 -0
  63. nadata/parser/nadata_loader/loader.py +951 -0
  64. nadata/parser/nastruct_parser/__init__.py +0 -0
  65. nadata/parser/nastruct_parser/declaration.py +105 -0
  66. nadata/parser/nastruct_parser/imports.py +164 -0
  67. nadata/parser/nastruct_parser/nastruct_parser.py +209 -0
  68. nadata/parser/nastruct_parser/parse_attributes.py +149 -0
  69. nadata/parser/nastruct_parser/parse_callables.py +436 -0
  70. nadata/parser/nastruct_parser/parse_expression.py +59 -0
  71. nadata/parser/nastruct_parser/parse_structs.py +206 -0
  72. nadata/parser/nastruct_parser/parser_state.py +84 -0
  73. nadata/parser/nastruct_parser/resolver.py +1412 -0
  74. nadata/parser/nastruct_parser/struct_body_state.py +50 -0
  75. nadata/parser/nastruct_parser/tmp_structs.py +156 -0
  76. nadata/parser/utils/__init__.py +20 -0
  77. nadata/parser/utils/brackets.py +252 -0
  78. nadata/parser/utils/comments_remove.py +149 -0
  79. nadata/parser/utils/identifiers.py +121 -0
  80. nadata/session.py +868 -0
  81. nadata-0.1.0.dist-info/METADATA +191 -0
  82. nadata-0.1.0.dist-info/RECORD +86 -0
  83. nadata-0.1.0.dist-info/WHEEL +5 -0
  84. nadata-0.1.0.dist-info/entry_points.txt +2 -0
  85. nadata-0.1.0.dist-info/licenses/LICENSE +21 -0
  86. nadata-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,402 @@
1
+ """
2
+ Tokenizer for Nadata expressions and declarations.
3
+
4
+ Converts raw source text into a flat list of typed tokens, handling string
5
+ literals with escapes, numeric literals, identifiers, keywords, operators, and
6
+ punctuation. Used by the expression parser and the declaration splitters.
7
+ """
8
+
9
+ # Import Modules
10
+ from __future__ import annotations
11
+ from dataclasses import dataclass
12
+ from enum import Enum
13
+ from typing import Optional
14
+
15
+
16
+ class TokenType(Enum):
17
+ """
18
+ Enumeration of the token types produced by the Tokenizer.
19
+ """
20
+
21
+ IDENTIFIER = "identifier"
22
+ KEYWORD = "keyword"
23
+ INT = "int"
24
+ FLOAT = "float"
25
+ STRING = "string"
26
+ OPERATOR = "operator"
27
+ PUNCTUATION = "punctuation"
28
+ EOF = "eof"
29
+
30
+
31
+ @dataclass
32
+ class Token:
33
+ """
34
+ Single lexical token with its position in the source text.
35
+
36
+ Attributes:
37
+ token_type (TokenType): Category of the token.
38
+ value (str): Decoded token value (escapes resolved for strings).
39
+ position (int): Index of the first source character of the token.
40
+ end_position (int): Index just after the last source character.
41
+ """
42
+
43
+ token_type: TokenType
44
+ value: str
45
+ position: int
46
+ end_position: int
47
+
48
+
49
+ # Language keywords (logical operators are keyword-only per the specification)
50
+ KEYWORDS: frozenset[str] = frozenset({
51
+ "class", "fn", "if", "elif", "else", "return",
52
+ "true", "false", "and", "or", "xor", "nand", "not",
53
+ "for", "while", "break", "continue", "in",
54
+ "try", "catch", "raise",
55
+ })
56
+
57
+ # Two-character operators, checked before single-character ones
58
+ MULTI_CHAR_OPERATORS: tuple[str, ...] = (
59
+ "==", "!=", "<=", ">=", "->",
60
+ "::", "+=", "-=", "*=", "/=", "%=", "++", "--",
61
+ )
62
+
63
+ # Single-character operator symbols
64
+ SINGLE_CHAR_OPERATORS: str = "+-*/%<>=!"
65
+
66
+ # Punctuation characters
67
+ PUNCTUATION_CHARS: str = ".,:;()[]{}"
68
+
69
+ # Escape character used inside string literals
70
+ ESCAPE_CHAR: str = "\\"
71
+
72
+ # Supported escape sequence decodings inside string literals
73
+ ESCAPE_MAPPINGS: dict[str, str] = {
74
+ '"': '"',
75
+ "\\": "\\",
76
+ "n": "\n",
77
+ "t": "\t",
78
+ }
79
+
80
+
81
+ class Tokenizer:
82
+ """
83
+ Converts source text into a list of typed tokens in a single left-to-right
84
+ scan. Comments are expected to have been removed beforehand.
85
+ """
86
+
87
+ def __init__(self, content: str) -> None:
88
+ """
89
+ Initializes the Tokenizer instance.
90
+
91
+ Args:
92
+ content (str): Comment-free source text to tokenize.
93
+ """
94
+
95
+ self.content: str = content
96
+ self.cursor: int = 0
97
+ self.token_start: int = 0
98
+
99
+ def tokenize(self) -> list[Token]:
100
+ """
101
+ Tokenizes the whole content into a token list.
102
+
103
+ Returns:
104
+ list[Token]: Tokens in source order, terminated by an EOF token.
105
+
106
+ Raises:
107
+ SyntaxError: On unterminated strings, invalid escapes, or
108
+ unexpected characters.
109
+ """
110
+
111
+ tokens: list[Token] = []
112
+
113
+ # Scan until the end of the content
114
+ while self.cursor < len(self.content):
115
+
116
+ # Skip insignificant whitespace between tokens
117
+ if self.content[self.cursor].isspace():
118
+ self.cursor += 1
119
+ continue
120
+
121
+ previous_cursor: int = self.cursor
122
+
123
+ tokens.append(self._scan_next_token())
124
+
125
+ # Guard against non-advancing scans (would loop forever)
126
+ if self.cursor <= previous_cursor:
127
+ raise RuntimeError(
128
+ f"Tokenizer failed to advance at index {previous_cursor}"
129
+ )
130
+
131
+ # Terminate with an EOF token for the parser convenience
132
+ tokens.append(Token(
133
+ token_type=TokenType.EOF,
134
+ value="",
135
+ position=len(self.content),
136
+ end_position=len(self.content)
137
+ ))
138
+
139
+ return tokens
140
+
141
+ def _scan_next_token(self) -> Token:
142
+ """
143
+ Scans a single token starting at the current cursor.
144
+
145
+ Returns:
146
+ Token: The next token.
147
+
148
+ Raises:
149
+ SyntaxError: If no token can start at the cursor.
150
+ """
151
+
152
+ char: str = self.content[self.cursor]
153
+
154
+ # Dispatch on the first character
155
+ if char == "\"":
156
+ return self._scan_string()
157
+
158
+ if char.isdigit():
159
+ return self._scan_number()
160
+
161
+ if char.isalpha() or char == "_":
162
+ return self._scan_identifier()
163
+
164
+ if self.content[self.cursor:self.cursor + 2] in MULTI_CHAR_OPERATORS:
165
+ return self._scan_multi_char_operator()
166
+
167
+ if char in SINGLE_CHAR_OPERATORS:
168
+ self.token_start = self.cursor
169
+ self.cursor += 1
170
+
171
+ return self._make_token(token_type=TokenType.OPERATOR, value=char)
172
+
173
+ if char in PUNCTUATION_CHARS:
174
+ self.token_start = self.cursor
175
+ self.cursor += 1
176
+
177
+ return self._make_token(token_type=TokenType.PUNCTUATION, value=char)
178
+
179
+ raise SyntaxError(
180
+ f"Unexpected character '{char}' at index {self.cursor}"
181
+ )
182
+
183
+ def _make_token(self, token_type: TokenType, value: Optional[str] = None) -> Token:
184
+ """
185
+ Builds a token spanning the characters consumed so far.
186
+
187
+ Args:
188
+ token_type (TokenType): Category of the token.
189
+ value (Optional[str], optional): Decoded token value. Defaults to
190
+ None (sliced from the source text).
191
+
192
+ Returns:
193
+ Token: The built token.
194
+ """
195
+
196
+ # Default value is the raw source slice (used by numbers, identifiers...)
197
+ if value is None:
198
+ value = self.content[self.token_start:self.cursor]
199
+
200
+ token: Token = Token(
201
+ token_type=token_type,
202
+ value=value,
203
+ position=self.token_start,
204
+ end_position=self.cursor
205
+ )
206
+
207
+ return token
208
+
209
+ def _scan_string(self) -> Token:
210
+ """
211
+ Scans a double quoted string literal with escape decoding.
212
+
213
+ Returns:
214
+ Token: The STRING token with the decoded value.
215
+
216
+ Raises:
217
+ SyntaxError: On unterminated strings or invalid escape sequences.
218
+ """
219
+
220
+ self.token_start = self.cursor
221
+ self.cursor += 1
222
+
223
+ decoded: list[str] = []
224
+
225
+ # Consume characters until the closing quote
226
+ while self.cursor < len(self.content) and self.content[self.cursor] != "\"":
227
+
228
+ # Handle escape sequences
229
+ if self.content[self.cursor] == ESCAPE_CHAR:
230
+ decoded.append(self._consume_escape())
231
+ continue
232
+
233
+ # Raw newline inside a string is a syntax error
234
+ if self.content[self.cursor] == "\n":
235
+ raise SyntaxError(
236
+ f"Unterminated string literal starting at index {self.token_start}"
237
+ )
238
+
239
+ decoded.append(self.content[self.cursor])
240
+ self.cursor += 1
241
+
242
+ # Check the string is terminated
243
+ if self.cursor >= len(self.content):
244
+ raise SyntaxError(
245
+ f"Unterminated string literal starting at index {self.token_start}"
246
+ )
247
+
248
+ # Consume the closing quote
249
+ self.cursor += 1
250
+
251
+ return self._make_token(token_type=TokenType.STRING, value="".join(decoded))
252
+
253
+ def _consume_escape(self) -> str:
254
+ """
255
+ Consumes a backslash escape sequence at the cursor.
256
+
257
+ Returns:
258
+ str: The decoded character.
259
+
260
+ Raises:
261
+ SyntaxError: If the escape sequence is invalid.
262
+ """
263
+
264
+ # Check the escaped character exists
265
+ if self.cursor + 1 >= len(self.content):
266
+ raise SyntaxError(
267
+ f"Unterminated escape sequence at index {self.cursor}"
268
+ )
269
+
270
+ escaped_char: str = self.content[self.cursor + 1]
271
+
272
+ # Check the escape is supported
273
+ if escaped_char not in ESCAPE_MAPPINGS:
274
+ raise SyntaxError(
275
+ f"Invalid escape sequence '\\{escaped_char}' at index {self.cursor}"
276
+ )
277
+
278
+ self.cursor += 2
279
+
280
+ return ESCAPE_MAPPINGS[escaped_char]
281
+
282
+ def _scan_number(self) -> Token:
283
+ """
284
+ Scans an integer or float numeric literal.
285
+
286
+ Floats include fractional parts ('1.5') and scientific notation
287
+ ('1e6', '3.5e-2', '1.5E+3'). The exponent is only consumed when a
288
+ complete 'e[+|-]<digits>' sequence follows, so '1.5e' keeps the
289
+ float and leaves 'e' for later postfix handling.
290
+
291
+ Returns:
292
+ Token: The INT or FLOAT token.
293
+
294
+ Raises:
295
+ SyntaxError: On malformed fractional parts.
296
+ """
297
+
298
+ self.token_start = self.cursor
299
+
300
+ # Consume integer digits
301
+ while self.cursor < len(self.content) and self.content[self.cursor].isdigit():
302
+ self.cursor += 1
303
+
304
+ # Check for a fractional part (a '.' followed by a digit)
305
+ has_fraction: bool = (
306
+ self.cursor + 1 < len(self.content)
307
+ and self.content[self.cursor] == "."
308
+ and self.content[self.cursor + 1].isdigit()
309
+ )
310
+
311
+ if has_fraction:
312
+ self.cursor += 1
313
+
314
+ # Consume fractional digits
315
+ while self.cursor < len(self.content) and self.content[self.cursor].isdigit():
316
+ self.cursor += 1
317
+
318
+ # Check for a complete exponent ('e'/'E', optional sign, digits)
319
+ has_exponent: bool = self._scan_exponent()
320
+
321
+ if has_fraction or has_exponent:
322
+ return self._make_token(token_type=TokenType.FLOAT)
323
+
324
+ # A '.' not followed by a digit belongs to a later postfix token
325
+ # (e.g. member access on a float literal like '1.5.method()')
326
+ return self._make_token(token_type=TokenType.INT)
327
+
328
+ def _scan_exponent(self) -> bool:
329
+ """
330
+ Scans an optional scientific-notation exponent at the cursor.
331
+
332
+ Consumes 'e'/'E', an optional sign, and at least one digit only
333
+ when the full sequence is present; otherwise leaves the cursor
334
+ untouched.
335
+
336
+ Returns:
337
+ bool: True if a complete exponent was consumed.
338
+ """
339
+
340
+ cursor: int = self.cursor
341
+
342
+ # Exponent marker
343
+ if cursor >= len(self.content) or self.content[cursor] not in "eE":
344
+ return False
345
+
346
+ cursor += 1
347
+
348
+ # Optional sign
349
+ if cursor < len(self.content) and self.content[cursor] in "+-":
350
+ cursor += 1
351
+
352
+ # At least one digit is required for a valid exponent
353
+ if cursor >= len(self.content) or not self.content[cursor].isdigit():
354
+ return False
355
+
356
+ while cursor < len(self.content) and self.content[cursor].isdigit():
357
+ cursor += 1
358
+
359
+ self.cursor = cursor
360
+
361
+ return True
362
+
363
+ def _scan_identifier(self) -> Token:
364
+ """
365
+ Scans an identifier or keyword.
366
+
367
+ Returns:
368
+ Token: The IDENTIFIER or KEYWORD token.
369
+ """
370
+
371
+ self.token_start = self.cursor
372
+
373
+ # Consume identifier characters
374
+ while (
375
+ self.cursor < len(self.content)
376
+ and (self.content[self.cursor].isalnum() or self.content[self.cursor] == "_")
377
+ ):
378
+ self.cursor += 1
379
+
380
+ value: str = self.content[self.token_start:self.cursor]
381
+
382
+ # Distinguish keywords from plain identifiers
383
+ token_type: TokenType = (
384
+ TokenType.KEYWORD if value in KEYWORDS else TokenType.IDENTIFIER
385
+ )
386
+
387
+ return self._make_token(token_type=token_type, value=value)
388
+
389
+ def _scan_multi_char_operator(self) -> Token:
390
+ """
391
+ Scans a two-character operator at the cursor.
392
+
393
+ Returns:
394
+ Token: The OPERATOR token.
395
+ """
396
+
397
+ self.token_start = self.cursor
398
+ operator: str = self.content[self.cursor:self.cursor + 2]
399
+
400
+ self.cursor += 2
401
+
402
+ return self._make_token(token_type=TokenType.OPERATOR, value=operator)
@@ -0,0 +1,187 @@
1
+ """
2
+ Type annotation parsing for Nadata.
3
+
4
+ Provides the TmpType intermediate representation (a type name with nested
5
+ children) and the TypeParser converting a raw annotation string into it.
6
+ Shared by the .nastruct and .nadata parsers so types are parsed once into
7
+ structural data instead of being carried as raw strings.
8
+ """
9
+
10
+ # Import Modules
11
+ from __future__ import annotations
12
+ from dataclasses import dataclass, field
13
+ from typing import Any
14
+
15
+ from nadata.parser.expressions.tokenizer import Token, TokenType, Tokenizer
16
+
17
+
18
+ @dataclass
19
+ class TmpType:
20
+ """
21
+ Intermediate representation of a parsed type annotation.
22
+
23
+ A simple type (e.g. 'Str') has no children; a generic type (e.g.
24
+ 'Array[Entity]') has its name plus one child per type argument.
25
+
26
+ Attributes:
27
+ name (str): Type constructor name (e.g. 'Str', 'Array', 'Dict').
28
+ children (list[TmpType]): Type arguments for generic types.
29
+ """
30
+
31
+ name: str
32
+ children: list[TmpType] = field(default_factory=list)
33
+
34
+ def to_dict(self) -> dict[str, Any]:
35
+ """
36
+ Converts the type to a plain JSON serializable dict.
37
+
38
+ Returns:
39
+ dict[str, Any]: Dict with 'name' and recursive 'children'.
40
+ """
41
+
42
+ return {
43
+ "name": self.name,
44
+ "children": [child.to_dict() for child in self.children],
45
+ }
46
+
47
+ def collect_names(self) -> set[str]:
48
+ """
49
+ Collects every type constructor name of the tree.
50
+
51
+ Returns:
52
+ set[str]: This type name plus all nested children names.
53
+ """
54
+
55
+ names: set[str] = {self.name}
56
+
57
+ for child in self.children:
58
+ names |= child.collect_names()
59
+
60
+ return names
61
+
62
+ def __repr__(self) -> str:
63
+ """
64
+ Returns string representation of the TmpType.
65
+
66
+ Returns:
67
+ str: Annotation style representation (e.g. 'Array[Entity]').
68
+ """
69
+
70
+ if not self.children:
71
+ return self.name
72
+
73
+ children_text: str = ", ".join(repr(child) for child in self.children)
74
+
75
+ return f"{self.name}[{children_text}]"
76
+
77
+
78
+ class TypeParser:
79
+ """
80
+ Parses a token stream into a TmpType tree.
81
+ """
82
+
83
+ def __init__(self, tokens: list[Token]) -> None:
84
+ """
85
+ Initializes the TypeParser instance.
86
+
87
+ Args:
88
+ tokens (list[Token]): Token stream to parse (terminated by EOF).
89
+ """
90
+
91
+ self.tokens: list[Token] = tokens
92
+ self.cursor: int = 0
93
+
94
+ @classmethod
95
+ def parse_text(cls, text: str) -> TmpType:
96
+ """
97
+ Tokenizes and parses a raw type annotation in one step.
98
+
99
+ Args:
100
+ text (str): Raw type annotation (e.g. 'Array[Entity]').
101
+
102
+ Returns:
103
+ TmpType: Parsed type tree.
104
+
105
+ Raises:
106
+ SyntaxError: On malformed or empty annotations.
107
+ """
108
+
109
+ tokens: list[Token] = Tokenizer(content=text).tokenize()
110
+
111
+ parsed_type: TmpType
112
+ cursor: int
113
+ parsed_type, cursor = cls(tokens=tokens).parse_type_at(cursor=0)
114
+
115
+ # Check nothing remains after the type
116
+ if tokens[cursor].token_type != TokenType.EOF:
117
+ raise SyntaxError(
118
+ f"Unexpected token '{tokens[cursor].value}' in type '{text}'"
119
+ )
120
+
121
+ return parsed_type
122
+
123
+ def parse_type_at(self, cursor: int) -> tuple[TmpType, int]:
124
+ """
125
+ Parses a single type starting at the given token cursor.
126
+
127
+ Args:
128
+ cursor (int): Token index to start parsing from.
129
+
130
+ Returns:
131
+ tuple[TmpType, int]: The parsed type and the new cursor.
132
+
133
+ Raises:
134
+ SyntaxError: On malformed type annotations.
135
+ """
136
+
137
+ token: Token = self.tokens[cursor]
138
+
139
+ # A dimension literal (e.g. the 3 in 'Tensor[Float32, 3, 4]') is a
140
+ # valid type argument and is carried as its digit-string name
141
+ if token.token_type == TokenType.INT:
142
+ cursor += 1
143
+
144
+ return TmpType(name=token.value), cursor
145
+
146
+ # A type starts with its constructor name
147
+ if token.token_type != TokenType.IDENTIFIER:
148
+ raise SyntaxError(
149
+ f"Expected a type name but found '{token.value}' "
150
+ f"at index {token.position}"
151
+ )
152
+
153
+ name: str = token.value
154
+ cursor += 1
155
+
156
+ children: list[TmpType] = []
157
+
158
+ # Parse the optional generic argument list '[...]'
159
+ if (
160
+ self.tokens[cursor].token_type == TokenType.PUNCTUATION
161
+ and self.tokens[cursor].value == "["
162
+ ):
163
+ cursor += 1
164
+
165
+ # Parse comma separated type arguments
166
+ while True:
167
+ child: TmpType
168
+ child, cursor = self.parse_type_at(cursor=cursor)
169
+ children.append(child)
170
+
171
+ current: Token = self.tokens[cursor]
172
+
173
+ # Continue on comma, close on bracket
174
+ if current.token_type == TokenType.PUNCTUATION and current.value == ",":
175
+ cursor += 1
176
+ continue
177
+
178
+ if current.token_type == TokenType.PUNCTUATION and current.value == "]":
179
+ cursor += 1
180
+ break
181
+
182
+ raise SyntaxError(
183
+ f"Expected ',' or ']' in type arguments of '{name}' "
184
+ f"but found '{current.value}' at index {current.position}"
185
+ )
186
+
187
+ return TmpType(name=name, children=children), cursor
@@ -0,0 +1,8 @@
1
+ """
2
+ Data loader for Nadata .nadata files.
3
+
4
+ See loader.py for the implementation of the NaDataLoader and its passes.
5
+ """
6
+
7
+ # Import Modules
8
+ from nadata.parser.nadata_loader.loader import NaDataLoader, StructRuntimeBinding