# json.parser

> A module of json_mlake's API.

## Functions

### `parse_string_scalar`

```mojo
def parse_string_scalar(s: String, start: Int) -> Value
```

Parse a string value.

### `parse_number_scalar`

```mojo
def parse_number_scalar(s: String, start: Int) -> Value
```

Parse a number value.

### `loads`

```mojo
def loads[target: StringSpan[ImmStaticOrigin] = StringSpan("cpu")](var s: String) -> Value
```

Deserialize JSON string to a Value (like Python's json.loads).

The parsed document owns its input, so `s` is taken by value. Pass
a string you no longer need with `^` and it is moved rather than
copied.

Example:
var data = loads('{"name": "Alice"}')
var data = loads[target="gpu"](large_json)  # GPU for large files.
var data = loads[target="cpu-simdjson"](s)  # Use simdjson FFI.

Parameters:

- `target`: Parsing target/backend. Options: "cpu" (default, pure Mojo),
    "cpu-simdjson" (FFI), or "gpu" (for large files).

Args:

- `s`: JSON string to parse.

```mojo
def loads[target: StringSpan[ImmStaticOrigin] = StringSpan("cpu")](bytes: Span[UInt8]) -> Value
```

Deserialize JSON bytes to a Value.

The same parse as the string form, for callers that already hold
bytes: a file buffer, a `List[UInt8]`, or a slice of a larger
document. The bytes are copied once into the document that backs
the returned `Value`, instead of being turned into a `String` by
the caller and copied again on the way in.

The bytes are checked for well-formed UTF-8 before anything else.
They have to be: `String` carries that as an invariant, so handing
it ill-formed bytes is undefined behaviour and trips an assertion
under `-D ASSERT=all`. An ill-formed input raises here instead,
which is the same outcome the parser would have reached for a
string, reported earlier and by position.

Example:
var data = loads(buffer.as_bytes()).

Parameters:

- `target`: Parsing target/backend. Options: "cpu" (default, pure Mojo),
    "cpu-simdjson" (FFI), or "gpu" (for large files).

Args:

- `bytes`: JSON text to parse.

```mojo
def loads[target: StringSpan[ImmStaticOrigin] = StringSpan("cpu")](var s: String, config: ParserConfig) -> Value
```

Deserialize JSON with custom configuration.

Example:
var data = loads('{"a": 1} // comment', ParserConfig(allow_comments=True)).

Parameters:

- `target`: "cpu" (default), "cpu-simdjson", or "gpu".

Args:

- `s`: JSON string to parse.
- `config`: Parser configuration (allow_comments, allow_trailing_comma, max_depth).

```mojo
def loads[target: StringSpan[ImmStaticOrigin] = StringSpan("cpu"), format: StringSpan[ImmStaticOrigin] = StringSpan("json")](var s: String) -> List[Value]
```

Deserialize NDJSON string to a list of Values.

Example:
var values = loads[format="ndjson"]('{"a":1}\n{"a":2}').

Parameters:

- `target`: "cpu" (default), "cpu-simdjson", or "gpu".
- `format`: Must be "ndjson" for this overload.

Args:

- `s`: NDJSON string (one JSON value per line).

```mojo
def loads[lazy: Bool](s: String) -> LazyValue
```

Create a lazy JSON value for on-demand parsing (CPU only).

Example:
var lazy = loads[lazy=True](huge_json)
var name = lazy.get("/users/0/name")  # Only parses this path.

Note:
Lazy parsing is CPU-only. For GPU, use `loads[target="gpu"]` directly.

Parameters:

- `lazy`: Must be True (required, no default).

Args:

- `s`: JSON string.

### `load`

```mojo
def load[target: StringSpan[ImmStaticOrigin] = StringSpan("cpu")](mut f: FileHandle) -> Value
```

Deserialize JSON from file to a Value (like Python's json.load).

Example:
with open("data.json", "r") as f:
    var data = load(f).

Parameters:

- `target`: "cpu" (default), "cpu-simdjson", or "gpu".

Args:

- `f`: FileHandle to read JSON from.

```mojo
def load[target: StringSpan[ImmStaticOrigin] = StringSpan("cpu")](mut f: FileHandle, config: ParserConfig) -> Value
```

Deserialize JSON from file with custom configuration.

Parameters:

- `target`: "cpu" (default), "cpu-simdjson", or "gpu".

Args:

- `f`: FileHandle to read JSON from.
- `config`: Parser configuration.

```mojo
def load[target: StringSpan[ImmStaticOrigin] = StringSpan("cpu")](path: String) -> Value
```

Load JSON/NDJSON from file path. Auto-detects format from extension.

Example:
var data = load("config.json")           # Returns object/value.
var items = load("data.ndjson")          # Returns array of values.
var big = load[target="gpu"]("large.json").

Parameters:

- `target`: "cpu" (default), "cpu-simdjson", or "gpu".

Args:

- `path`: Path to .json or .ndjson file.

```mojo
def load[target: StringSpan[ImmStaticOrigin] = StringSpan("cpu"), format: StringSpan[ImmStaticOrigin] = StringSpan("json")](path: String) -> List[Value]
```

Load NDJSON from file path -> `List[Value]` (matches `loads[format='ndjson']`).

Example:
var events = load[format="ndjson"]("logs.ndjson")
for event in events:
    print(event["msg"].string_value()).

Note:
This overload returns `List[Value]`, matching
`loads[format='ndjson']`. The plain-extension auto-detection
(`load("x.ndjson") -> Value`) still works for backward
compatibility but wraps the records in an array Value; new
code should prefer this typed overload.

Parameters:

- `target`: "cpu" (default), "cpu-simdjson", or "gpu".
- `format`: Must be "ndjson" for this overload.

Args:

- `path`: Path to a `.ndjson` file.

```mojo
def load[streaming: Bool](path: String) -> StreamingParser
```

Stream large files line by line (CPU only, for memory efficiency).

Example:
var parser = load[streaming=True]("huge.ndjson")
while parser.has_next():
    var item = parser.next()
parser.close().

Note:
Streaming is CPU-only (for memory efficiency, not speed).
For GPU speed on files that fit in memory, use `load[target="gpu"]("file.ndjson")`.

Parameters:

- `streaming`: Must be True.

Args:

- `path`: Path to NDJSON file.
