4 Input text
This chapter defines input scanning and coordinate counting. Settings are specified here only by their effect on input; chapter 5 defines their syntax. Chapter 6 defines value-reading statements, and chapter 7 defines line patterns and input structure.
4.1 Bytes and physical lines
Implementations MUST scan input as bytes, subject to the
UTF-8 requirements. LF (0a in hexadecimal) alone
ends a physical line. CR LF consists of a CR byte followed by the LF that
ends the line. A lone CR does not end a physical line. Implementations
MUST NOT normalize line endings before scanning or counting positions.
A final LF is OPTIONAL, including for a line-pattern match. This input has CR LF, a lone CR, and no final LF.
id: input-line-endingsoperation: read--- speca: int b: int c: int--- input hex31 0d 0a 32 0d 33--- expected data{"iris": "0.1", "entries": [ {"name": "a", "type": "int", "depth": 0, "value": 1}, {"name": "b", "type": "int", "depth": 0, "value": 2}, {"name": "c", "type": "int", "depth": 0, "value": 3}]}4.2 White space and line blanks
The following byte sets MUST be used independently of the host locale.
| Set | Bytes in hexadecimal | Uses |
|---|---|---|
| Default separators | space 20, tab 09, LF 0a, CR 0d, vertical tab 0b, form feed 0c |
Ordinary token boundaries and initial skipping |
| Line blanks | space 20, tab 09, CR 0d |
Trailing trimming of line text, pattern whitespace, and indentation before comment/stop prefixes |
Vertical tab and form feed separate ordinary words.
id: input-ascii-whitespaceoperation: read--- speca: word b: word c: word--- input hex61 0b 62 0c 63--- expected data{"iris": "0.1", "entries": [ {"name": "a", "type": "string", "depth": 0, "value": "a"}, {"name": "b", "type": "string", "depth": 0, "value": "b"}, {"name": "c", "type": "string", "depth": 0, "value": "c"}]}A rest read MUST first skip separators and applicable comment lines as
in §4.7. It MUST then retain the bytes
through the current physical line, excluding LF and trailing line blanks.
Interior CR, vertical tab, and form feed remain in the value. Added
separators affect initial skipping but do not extend trailing trimming.
id: input-line-blanksoperation: read--- specx: rest--- input hex20 61 6c 70 68 61 0d 62 65 74 61 0b 0c 20 09 0d 0a--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "string", "depth": 0, "value": "alpha\rbeta\u000b\f"}]}Initial skipping before a line pattern uses separators. Within the line,
pattern whitespace MUST use only line blanks. Vertical tab and form feed
can occur within a captured word but do not satisfy pattern whitespace.
Here vertical tab cannot match the space between a and b.
id: input-pattern-blanksoperation: read--- specline "a b"--- input hex61 0b 62 0a--- expected error{"code": "E-LINE-MATCH", "message": "expected a line matching \"a b\"", "input_location": {"origin": "input.bin", "line": 1, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": null, "record_path": null}Unicode whitespace outside the default byte set MUST be ordinary input
unless a setting changes its bytes. The word below contains U+00A0,
NO-BREAK SPACE, between a and b.
id: input-unicode-spaceoperation: read--- specx: word--- input no-final-newlinea b--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "string", "depth": 0, "value": "a b"}]}4.3 Tokens and separators
Without settings, an ordinary token MUST be a maximal nonempty run of bytes
outside the default separator set. A word read returns that token.
The tokens setting MUST make each listed byte a separate one-byte token,
unless that byte is already a separator. It does not define token strings:
tokens "::" makes each colon a token.
id: input-token-bytesoperation: read--- spectokens "::" a: word b: word c: word d: word--- input no-final-newlinea::b--- expected data{"iris": "0.1", "entries": [ {"name": "a", "type": "string", "depth": 0, "value": "a"}, {"name": "b", "type": "string", "depth": 0, "value": ":"}, {"name": "c", "type": "string", "depth": 0, "value": ":"}, {"name": "d", "type": "string", "depth": 0, "value": "b"}]}The separators setting MUST add each listed byte to the separator set.
Separator status MUST take precedence over token status in either setting
order. A later tokens setting MUST NOT remove separator status. Settings
accumulate and affect subsequent execution; they MUST NOT change values
already read.
id: input-separators-winoperation: read--- spectokens "," separators "," tokens "," a: int b: int--- input no-final-newline1,2--- expected data{"iris": "0.1", "entries": [ {"name": "a", "type": "int", "depth": 0, "value": 1}, {"name": "b", "type": "int", "depth": 0, "value": 2}]}id: input-settings-orderoperation: read--- speca: word tokens ";" b: word p: word c: word--- input no-final-newlinea;b x;y--- expected data{"iris": "0.1", "entries": [ {"name": "a", "type": "string", "depth": 0, "value": "a;b"}, {"name": "b", "type": "string", "depth": 0, "value": "x"}, {"name": "p", "type": "string", "depth": 0, "value": ";"}, {"name": "c", "type": "string", "depth": 0, "value": "y"}]}Settings MUST operate byte by byte, including the bytes of multibyte UTF-8 characters. Resulting word/rest values MUST still satisfy §4.10.
These settings govern ordinary token boundaries and initial skipping.
They MUST NOT split the interior of a rest value or replace the separate
capture rules of line patterns.
id: input-line-settingsoperation: read--- spectokens ";" separators "," x: rest--- input no-final-newlinea;b,c--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "string", "depth": 0, "value": "a;b,c"}]}4.4 Integer tokens
An integer token MUST match ASCII [+-]?[0-9]+ and denote a signed 64-bit
integer in the range of §3.4. Conversion
MUST consume the complete token. A leading plus and leading zeros are
accepted; leading zeros do not select octal. Signed zero denotes zero.
These rules apply to scalar, array, and list integer reads.
id: input-integer-spellingsoperation: read--- speca[6]: int--- input no-final-newline+007 -07 -0 0 -9223372036854775808 9223372036854775807--- expected data{"iris": "0.1", "entries": [ {"name": "a", "type": "int", "depth": 1, "value": [7, -7, 0, 0, -9223372036854775808, 9223372036854775807]}]}Hexadecimal, fractions, exponents, digit separators, bare or doubled signs,
and tokens containing NUL MUST be rejected. A lexical failure or an
out-of-range input integer MUST report
E-EXPECTED-VALUE at the token start.
E-INTEGER-OVERFLOW is reserved for arithmetic and value adjustment.
id: input-integer-overflowoperation: read--- specx: int--- input no-final-newline9223372036854775808--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected int, found '9223372036854775808'", "input_location": {"origin": "input.bin", "line": 1, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "x", "record_path": null}id: input-integer-tokenoperation: read--- specx: int--- input no-final-newline1e2--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected int, found '1e2'", "input_location": {"origin": "input.bin", "line": 1, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "x", "record_path": null}id: input-integer-hexoperation: read--- specx:int--- input no-final-newline0x10--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected int, found '0x10'", "input_location": {"origin": "input.bin", "line": 1, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "x", "record_path": null}Token settings change the tokens presented to conversion. A digit made a one-byte token is independently readable as an integer; a sign made a one-byte token is invalid by itself.
4.5 Floating point tokens
A float token MUST match this ASCII decimal form (regular-expression notation):
[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?Conversion MUST consume the complete token and MUST use a decimal point
of . independently of the host locale. Integer-looking tokens, leading
zeros, leading plus, exponents, 1., .5, +.5, and 1.e2 are accepted.
The resulting value type is float even when the value is integral.
id: input-float-spellingsoperation: read--- speca[7]: float--- input no-final-newline+7 -07 1. .5 +.5 1.e2 +2.5E-1--- expected data{"iris": "0.1", "entries": [ {"name": "a", "type": "float", "depth": 1, "value": [7, -7, 1, 0.5, 0.5, 100, 0.25]}]}Hexadecimal, infinity, NaN, missing significand or exponent digits, misplaced
signs, and tokens containing NUL MUST be rejected with
E-EXPECTED-VALUE at the token start.
id: input-float-hexoperation: read--- specx: float--- input no-final-newline0x1p2--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected float, found '0x1p2'", "input_location": {"origin": "input.bin", "line": 1, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "x", "record_path": null}id: input-float-infoperation: read--- specx: float--- input no-final-newlineinf--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected float, found 'inf'", "input_location": {"origin": "input.bin", "line": 1, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "x", "record_path": null}id: input-float-nanoperation: read--- specx: float--- input no-final-newlinenan--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected float, found 'nan'", "input_location": {"origin": "input.bin", "line": 1, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "x", "record_path": null}The exact decimal value MUST be rounded to binary64 using round to nearest,
ties to even. Overflow to infinity MUST report E-EXPECTED-VALUE at the
token start.
id: input-float-overflowoperation: read--- specx: float--- input no-final-newline1e309--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected float, found '1e309'", "input_location": {"origin": "input.bin", "line": 1, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "x", "record_path": null}If the exact decimal value is nonzero but rounds to a subnormal value or
to zero, conversion MUST report E-EXPECTED-VALUE at the token start.
id: input-float-underflowoperation: read--- specx: float--- input no-final-newline5e-324--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected float, found '5e-324'", "input_location": {"origin": "input.bin", "line": 1, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "x", "record_path": null}Exact zero in any spelling, including 0e-9999, MUST be accepted. Values
that round to the smallest normal binary64 value MUST be accepted, even
when their exact decimal magnitude is slightly smaller than that value.
id: input-float-normal-boundaryoperation: read--- speca[2]: float--- input no-final-newline0e-9999 2.2250738585072013e-308--- expected data{"iris": "0.1", "entries": [ {"name": "a", "type": "float", "depth": 1, "value": [0, 2.2250738585072014e-308]}]}The num reading type MUST try integer conversion before float conversion.
For example, 9223372036854775808 fails integer conversion but succeeds
as a float through num. Value construction, promotion, and signed zero
follow §3.5.
4.6 Input positions
Input lines and columns MUST start at 1. A byte's line is one plus the number of preceding LF bytes. Its column is one plus the number of bytes since the preceding LF, or since the start of input if none precedes it. Tabs, CR, vertical tab, and form feed each occupy one column. Each byte of a multibyte UTF-8 character also occupies one column; columns count neither Unicode scalar values nor grapheme clusters.
The first word below occupies two bytes, and the tab occupies one, so the invalid integer starts at column 4.
id: input-byte-columnsoperation: read--- speca: word b: int--- input no-final-newlineé bad--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected int, found 'bad'", "input_location": {"origin": "input.bin", "line": 1, "column": 4}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "b", "record_path": null}A lone CR increments the column. CR LF increments the line only at LF.
id: input-cr-columnsoperation: read--- speca: int b: int--- input hex31 0d 62 61 64--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected int, found 'bad'", "input_location": {"origin": "input.bin", "line": 1, "column": 3}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "b", "record_path": null}id: input-crlf-columnsoperation: read--- speca: int b: int--- input hex31 0d 0a 09 62 61 64--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected int, found 'bad'", "input_location": {"origin": "input.bin", "line": 2, "column": 2}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "b", "record_path": null}End of input has the position immediately after the final byte: after LF, column 1 of the next line; otherwise, one beyond the final byte's column.
id: input-eof-columnsoperation: read--- speca: int b: int--- input hex31 0d 0a--- expected error{"code": "E-EXPECTED-VALUE", "message": "expected int, found end of input", "input_location": {"origin": "input.bin", "line": 2, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "b", "record_path": null}A stop prefix advances the reading position to the physical end of all supplied bytes. A later required read can therefore report end of input beyond the stop line. Chapter 11 defines which current or saved position belongs to each error; an implementation MUST NOT relocate saved check positions to the final cursor. §8.13 defines saved check witnesses and their positions.
4.7 Comment and stop prefixes
Whenever normal skipping is required, implementations MUST first skip separator bytes. Prefixes MUST then be considered only if every byte before the current position on its physical line is a line blank. A matching comment prefix discards the remainder of that physical line and resumes skipping. A matching stop prefix discards all remaining input. Inline occurrences are ordinary data. If comment and stop prefixes both match, comment handling MUST take precedence.
Comparison MUST be case-sensitive and byte-exact. Empty prefixes MUST NOT
match. The boundary class is ASCII [A-Za-z0-9_]. If the final prefix byte
belongs to that class, the following byte MUST be absent or outside that
class for the prefix to match. Otherwise there is no boundary restriction.
Non-ASCII letters do not belong to the class.
Thus END does not match ENDx, END7, or END_, but does match ENDé.
id: input-comment-boundariesoperation: read--- speccomment "END" repeat until eof { x: word }--- input no-final-newlineENDxEND7END_ENDékeep--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "string", "depth": 1, "value": ["ENDx", "END7", "END_", "keep"]}]}An underscore at the end of a prefix still requires a boundary. A
non-ASCII final byte does not: prefix é matches éx.
id: input-prefix-underscoreoperation: read--- speccomment "END_" repeat until eof { x: word }--- input no-final-newlineEND_xkeep--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "string", "depth": 1, "value": ["END_x", "keep"]}]}id: input-prefix-nonasciioperation: read--- speccomment "é" repeat until eof { x: word }--- input no-final-newlineéxkeep--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "string", "depth": 1, "value": ["keep"]}]}Space, tab, and CR indentation permit recognition. A preceding vertical tab, form feed, or added comma separator does not: even after skipping, that byte is not a line blank. A lone CR after data does not start a new physical line. Here the first line is a comment, but the second is data.
id: input-prefix-indentationoperation: read--- speccomment "#" repeat until eof { x: word }--- input hex20 09 0d 23 73 6b 69 70 0a 0b 23 6b 65 65 70 0a--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "string", "depth": 1, "value": ["#keep"]}]}Stops use the same boundary rule. Here ENDé stops reading before later.
id: input-stop-boundariesoperation: read--- specstop "END" repeat until eof { x: word }--- input no-final-newlineENDxEND_ENDélater--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "string", "depth": 1, "value": ["ENDx", "END_"]}]}When both settings match END, the comment consumes only that line.
id: input-comment-before-stopoperation: read--- speccomment "END" stop "END" repeat until eof { x: word }--- input no-final-newlineENDkeep--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "string", "depth": 1, "value": ["keep"]}]}4.8 End of input and trailing input
After successful execution, implementations MUST perform normal skipping
and report E-TRAILING-INPUT if data
remains. Its position is the first remaining data byte. Separators,
comments, and stops therefore apply during this check.
id: input-trailingoperation: read--- specx: int--- input no-final-newline7 junk--- expected error{"code": "E-TRAILING-INPUT", "message": "unexpected input after the end of the spec: 'junk'", "input_location": {"origin": "input.bin", "line": 2, "column": 2}, "spec_location": null, "context": null, "record_path": null}The ignore trailing setting MUST suppress this final check. It MUST NOT
suppress earlier reading errors or make an absent required value readable.
Explicit instance selection also bypasses the final trailing check, as
specified in §11.2.1.
Neither mechanism bypasses input-wide UTF-8 validation.
id: input-ignore-trailingoperation: read--- specx: int ignore trailing--- input no-final-newline7 junk--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "int", "depth": 0, "value": 7}]}4.9 NUL bytes
NUL (00) MUST be treated as a byte, not end of input or a string
terminator. It is neither a default separator nor a line ending. By default,
ordinary word/rest reads MUST retain it; numeric conversion MUST reject a token
containing it. It can be configured as a separator. NUL is valid Unicode;
canonical JSON escapes it as \u0000.
id: input-nuloperation: read--- specx: word--- input hex00 0a--- expected data{"iris": "0.1", "entries": [ {"name": "x", "type": "string", "depth": 0, "value": "\u0000"}]}Line-pattern captures have a separate boundary rule. A word capture without
an immediately following literal MUST stop at NUL: line "{x:word}" fails
to match a, NUL, b. A word capture immediately followed by a literal
uses that literal's first byte as its stopping byte instead. A rest capture
retains NUL. §7.2 defines
the full pattern rules.
4.10 UTF-8 validity
The entire supplied input byte sequence MUST be valid UTF-8. This includes comments, skipped lines, literal portions of pattern matches, bytes after a stop prefix, bytes after a selected instance, and ignored trailing input. This deliberate difference from Gecode 6.5.0 also applies to catalog operations.
Implementations MUST validate the input as one phase after parsing and
resolving the reader spec and rejecting unknown parameters, and before any
statement executes. An input-wide failure MUST report
E-UTF8 at the first byte of the first
ill-formed subsequence, using §4.6. It MUST have null
spec_location, context, and record_path
(profile T). Thus parse/resolve
errors precede unknown parameters, which precede input-wide E-UTF8, which
precedes execution errors. A parse-only operation does not read or validate
input. This validation adds no work charge and leaves the original byte
length unchanged for §10.1.
Iris-only UTF-8 requirement; Gecode accepts these bytes. The invalid byte is in a comment that execution would otherwise skip.
id: input-invalid-utf8-commentoperation: read--- speccomment "#" x: int--- input hex23 ff 0a 37--- expected error{"code": "E-UTF8", "message": "input is not valid UTF-8", "input_location": {"origin": "input.bin", "line": 1, "column": 2}, "spec_location": null, "context": null, "record_path": null}Iris-only UTF-8 requirement; Gecode accepts these bytes. The invalid byte
follows a valid integer in an ignored tail. Validation fails before x
is read.
id: input-invalid-utf8-tailoperation: read--- specx: int ignore trailing--- input hex37 0a ff--- expected error{"code": "E-UTF8", "message": "input is not valid UTF-8", "input_location": {"origin": "input.bin", "line": 2, "column": 1}, "spec_location": null, "context": null, "record_path": null}Each word/rest value actually read MUST also be valid UTF-8, because
byte-wise tokens and separators settings can split a character in valid
input. This check includes scalar, array, and list reads, discarded reads,
and reads in instances traversed without retaining their data. Captures
MUST be checked after a complete pattern match is selected, before committing
its values, including unnamed or discarded captures. Speculative captures
of unsuccessful candidate matches MUST NOT introduce encoding errors.
A value-level failure is a hard reading error, ordered with execution
errors by §11.2. It MUST report E-UTF8 at
the input byte starting the first ill-formed subsequence within the value,
with profile R availability: active reader-spec origin and line, null
reader-spec column, current execution context when present, and null
record_path. These locations are defined by Iris, not supplied by Gecode.
Iris-only UTF-8 requirement; Gecode accepts these bytes. The complete input
is valid UTF-8, but tokens "é" makes each of its two bytes a separate
word. The first word is the truncated byte c3.
id: input-invalid-utf8-splitoperation: read--- spectokens "é" a: word b: word--- input no-final-newlineé--- expected error{"code": "E-UTF8", "message": "string value is not valid UTF-8", "input_location": {"origin": "input.bin", "line": 1, "column": 1}, "spec_location": {"origin": "spec.iris", "line": 1, "column": null}, "context": "a", "record_path": null}Both checks MUST reject malformed continuation sequences, truncated sequences, overlong encodings, surrogate encodings, and encodings above U+10FFFF. For a truncated sequence, the error position is its initial byte. NUL, noncharacters, and U+FEFF MUST be accepted as ordinary characters. Implementations MUST NOT strip a BOM or normalize Unicode. These rules concern input and read values; chapter 5 defines reader-spec source validation and lexing.
id: input-valid-utf8operation: read--- speca: word b: rest--- inputé café--- expected data{"iris": "0.1", "entries": [ {"name": "a", "type": "string", "depth": 0, "value": "é"}, {"name": "b", "type": "string", "depth": 0, "value": "café"}]}