blob: b42ecda1b31aa501fe841668f383059d134949c9 [file] [edit]
#ifndef Py_TOKENIZER_SOURCE_H
#define Py_TOKENIZER_SOURCE_H
#include "Python.h"
typedef Py_ssize_t _PyTok_Off;
/* Half-open byte offsets into a _PyTok_SourceText. */
typedef struct {
_PyTok_Off start;
_PyTok_Off end;
} _PyTok_Span;
/* Lines are 1-based and byte columns are 0-based. */
typedef struct {
int lineno;
int byte_col;
} _PyTok_Loc;
typedef enum {
_PYTOK_AFFINITY_LEFT,
_PYTOK_AFFINITY_RIGHT,
} _PyTok_Affinity;
/* The half-open range includes the terminating newline when present. */
typedef struct {
_PyTok_Off start;
_PyTok_Off end;
unsigned implicit_newline : 1;
unsigned contains_nul : 1;
} _PyTok_Line;
typedef struct {
char *bytes;
_PyTok_Off len;
_PyTok_Off cap;
_PyTok_Off *line_checkpoints;
unsigned char *implicit_lines;
int nlines;
int checkpoints_cap;
Py_ssize_t implicit_cap;
} _PyTok_SourceText;
PyAPI_FUNC(void) _PyTok_SourceInit(_PyTok_SourceText *);
/* Clear invalidates all cursors, spans, and views for the source. */
PyAPI_FUNC(void) _PyTok_SourceClear(_PyTok_SourceText *);
/* Append one nonempty logical line and return its start offset. The input may
contain one newline, as its final byte. An unterminated line must be the
final line. implicit_newline means that the final newline was synthesized.
The input must not point into source storage. */
PyAPI_FUNC(_PyTok_Off) _PyTok_SourceAppendLine(
_PyTok_SourceText *source, const char *bytes, Py_ssize_t len,
int implicit_newline);
/* The returned view is invalidated by SourceAppendLine and SourceClear. */
PyAPI_FUNC(const char *) _PyTok_SourceSpanView(
const _PyTok_SourceText *, _PyTok_Span, Py_ssize_t *);
/* Look up a 1-based line. Empty and newline-terminated sources have an empty
virtual line at EOF. */
PyAPI_FUNC(int) _PyTok_SourceLine(
const _PyTok_SourceText *, int, _PyTok_Line *);
/* Return false for invalid line numbers and the virtual EOF line. */
PyAPI_FUNC(int) _PyTok_SourceLineIsImplicit(
const _PyTok_SourceText *, int);
/* At a line boundary, left affinity selects the preceding line at its end;
right affinity selects the following line at byte column zero. */
PyAPI_FUNC(int) _PyTok_SourceLocation(
const _PyTok_SourceText *, _PyTok_Off, _PyTok_Affinity, _PyTok_Loc *);
static inline _PyTok_Span
_PyTok_SpanFromBounds(_PyTok_Off start, _PyTok_Off end)
{
return (_PyTok_Span){start, end};
}
static inline int
_PyTok_SpanIsValid(_PyTok_Span span)
{
return span.start >= 0 && span.end >= span.start;
}
static inline _PyTok_Off
_PyTok_SourceFindLineEnd(const _PyTok_SourceText *source, _PyTok_Off start)
{
if (source->bytes == NULL || start < 0 || start >= source->len) {
PyErr_SetString(PyExc_SystemError,
"corrupt tokenizer source line index");
return -1;
}
const char *newline = memchr(
source->bytes + start, '\n', source->len - start);
if (newline == NULL) {
PyErr_SetString(PyExc_SystemError,
"corrupt tokenizer source line index");
return -1;
}
return newline - source->bytes + 1;
}
#endif