Scope and ownership
링크Literals write values directly in source. This chapter covers their spellings, type families, escapes, interpolation, and template tags.
Lexical structure owns identifiers, token separation, comments, and source positions.
Expressions and operators owns unary signs and grouping. Types owns general compatibility and inference. Concurrency owns the behavior of concurrent and its timeout. Library entries own conversion functions and operations on template values.
Integers and floats
링크DecimalDigit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;BinaryDigit = "0" | "1" ;HexDigit = DecimalDigit | "a" | "b" | "c" | "d" | "e" | "f" ;DecimalDigits = DecimalDigit ("_"? DecimalDigit)* ;BinaryDigits = BinaryDigit ("_"? BinaryDigit)* ;HexDigits = HexDigit ("_"? HexDigit)* ;IntegerLiteral = DecimalDigits| "0x" HexDigits| "0b" BinaryDigits ;FloatLiteral = DecimalDigits "." DecimalDigits ;
This manually transcribed excerpt describes numeric tokens in language mode 5.21. Adjacent elements belong to the same token. It omits operator grammar and contextual type rules.
Integer spellings
An integer literal uses one of these radix forms.
| Radix | Prefix | Digits |
|---|---|---|
| 10 | none | 0123456789 |
| 16 | 0x | 0123456789abcdef |
| 2 | 0b | 01 |
Radix prefixes and hexadecimal letters are lowercase. An uppercase spelling produces TPZ2001 during parsing.
A leading - is a unary expression operator applied to a literal.
이유
Decimal notation expresses magnitudes while binary and hexadecimal notation expose groups of bits. Changing the case of a radix prefix or hexadecimal digit changes neither the value nor the chosen radix. Lowercase removes that spelling choice while preserving the different purposes of the radix forms. A shared integer type keeps arithmetic independent of the chosen radix.
Numeric digit separators
In a numeric digit run, _ separates two digits of the selected radix. The run starts and ends with a digit and cannot contain repeated separators. Parsing a malformed numeric token produces TPZ2001.
이유
Digit separators make long magnitudes easier to read. Requiring a digit on each side prevents separators from becoming prefixes or suffixes.
Integer values and the signed range
An integer literal has a literal type compatible with int. Values range from - through 9223372036854775807. The signed minimum is accepted as -. An out-of-range integer value produces TPZ5001 during checking.
이유
A fixed signed range gives integer values the same bounds across hosts. Rejecting an unrepresentable literal prevents silent truncation before the program runs.
Decimal float spellings and types
A float literal has decimal digits on both sides of .. Exponent notation is rejected as a malformed numeric token with TPZ2001 during parsing. A float literal has a literal type compatible with float.
이유
A decimal point distinguishes a floating literal from an integer literal. Digits on both sides separate it from member and range punctuation. Positional decimal spelling matches finite-float rendering, which expands the shortest decimal representation into positional notation. Excluding exponent notation keeps source and display on that shared convention. The values use binary64.
Decimal float rounding, overflow, and signed zero
Decimal float literals round to the nearest binary64 value. An exact tie selects the value with an even final significand bit. Overflow produces infinity. Underflow can produce a subnormal value or zero. Unary minus retains the sign of zero. Interpolation writes the infinities as inf and -, and the two zeros as 0. and -. Decimal spelling still requires a point with digits on both sides; exponent spelling is rejected.
이유
Binary64 gives floating literals a common numeric representation. Defined rounding and signed zero make boundary values reproducible across the literal and arithmetic paths.
Booleans, null, and unit
링크BooleanLiteral = "true" | "false" ;NullLiteral = "null" ;UnitLiteral = "(" ")" ;
Parentheses containing an expression belong to the expression grammar.
Boolean, null, and unit types
| Spelling | Type |
|---|---|
true | boolean literal type compatible with bool |
false | boolean literal type compatible with bool |
null | null literal type |
() | unit type () |
이유
Boolean values, absence, and unit represent distinct concepts. Their separate types prevent an absent value or a completed action from becoming an implicit Boolean.
For null compatibility, the contextual typing of None(), and restrictions on the binding name None, see Types and Bindings and scope.
Duration literals
링크DurationLiteral = DecimalDigits DurationUnit ;DurationUnit = "ms" | "s" | "m" ;
DecimalDigits is defined in the numeric grammar above.
Concurrency owns the complete concurrent expression and timeout behavior.
Duration literals are ordinary values
A duration literal attaches a lowercase ms, s, m suffix to a decimal integer magnitude. It denotes an ordinary Duration value, including in bindings, function arguments and results, parenthesized expressions, and concurrent(timeout: .. Duration has no type arguments and does not implicitly convert to or from int or float. The same literal conversion and range checks apply in every expression position. Operations follow the Duration values rule.
Arithmetic, comparison, display, and toMillis follow Duration operations.
이유
A unit suffix states the time scale beside the magnitude. The same literal denotes Duration in an ordinary expression and in a timeout; binding or parenthesizing that value does not change its admission. Duration remains distinct from numeric types so an integer cannot silently acquire a time unit.
Duration values and operations
| Suffix | Unit | Milliseconds per unit |
|---|---|---|
ms | millisecond | 1 |
s | second | 1000 |
m | minute | 60000 |
A Duration stores from 0 through 18446744073709551615 milliseconds. An out-of-range duration literal produces TPZ5001 during checking.
Two Duration values support addition and subtraction. Multiplication takes a Duration and an int in either order, as in d * n and n * d. Construct a duration from an integer with 1ms * n. Duration has no division and no function for converting a number to Duration.
Eq compares millisecond counts for equality. Order compares those counts numerically. Display produces a decimal millisecond literal such as 1500ms, which reads back as the same value. to returns the millisecond count. Duration has no JSON capability in 6.0.
An overflowing sum or product, a subtraction below zero, any negative integer multiplier, or a millisecond count outside the int range stops with runtime TPZ4004. These faults follow the fault cleanup rule.
Runtime range failures use TPZ4004. Timeout evaluation follows concurrent deadlines.
이유
Every Duration stores milliseconds, so operations use one unit. A literal and integer multiplication provide one way to construct a duration from a number. The millisecond display reads back as the same value.
Length literals
링크LengthLiteral = DecimalMagnitude LengthUnit ;DecimalMagnitude = DecimalDigits ("." DecimalDigits)? ;LengthUnit = "pt" | "mm" | "cm" | "in" | "em" ;
DecimalDigits is defined in the numeric grammar above.
Length spellings and types
A length literal attaches its lowercase unit directly to a decimal integer or decimal fraction. Radix and exponent notation are not length-literal forms.
| Suffix | Literal type |
|---|---|
pt | Length<Pt> |
mm | Length<Mm> |
cm | Length<Cm> |
in | Length<In> |
em | Length<Em> |
The suffix determines the compiler-owned length type. Literal formation rejects an unrepresentable result with TPZ5001 during checking.
이유
Typed units let page dimensions and font-relative dimensions enter layout APIs directly. Keeping em distinct from physical lengths prevents a font size from being assumed implicitly.
Length conversions and arithmetic belong to their API entries. See Pending contracts for precision and exact literal endpoints.
Length rounding and literal boundaries
A Length literal is converted from its exact decimal value, including its sign. It rounds to the nearest multiple of the unit step below. An exact midpoint selects the even multiple.
| Unit | Step in that unit | Minimum input, included | Upper input limit, excluded |
|---|---|---|---|
pt | 1/65536 | -18446744073709551617/131072 | 18446744073709551615/131072 |
mm | 127/23592960 | -2342736497361113055359/47185920 | 156182433157407537007/3145728 |
cm | 127/235929600 | -2342736497361113055359/471859200 | 156182433157407537007/31457280 |
in | 1/4718592 | -18446744073709551617/9437184 | 6148914691236517205/3145728 |
em | 1/65536 | -18446744073709551617/131072 | 18446744073709551615/131072 |
The fractions are exact mathematical values. Write a decimal value followed immediately by its unit in source. A literal outside this interval produces TPZ5001 during checking. Equality and the public unit-conversion methods observe the rounded result.
이유
Exact decimal conversion fixes a document dimension before layout. A shared point grid aligns physical unit conversions, and ties-to-even rounding avoids directional bias at exact midpoints.
Strings and interpolation
링크StringLiteral = SingleLineString | MultilineString ;SingleLineString = '"' SingleLinePart* '"' ;MultilineString = '"""' MultilinePart* '"""' ;SingleLinePart = SingleLineText | Escape | Interpolation ;MultilinePart = MultilineText | Escape | Interpolation ;Escape = '\' ("n" | "r" | "t" | '\' | '"' | "{" | "}") ;Interpolation = "{" Expression "}" ;
SingleLineText and MultilineText are scanner-delimited text runs. A physical LF, CRLF, or CR is a line break. Inside a single-line string, text and interpolation reject physical line breaks. Multiline text uses them for opening removal and indentation, then stores LF. Escapes and inserted string values retain their carriage returns.
String delimiters and interpolation
| String form | Opening and closing delimiter |
|---|---|
| single-line | " |
| multiline | """ |
An unescaped { begins interpolation containing an expression followed by }. An empty interpolation produces TPZ2001 during parsing.
이유
Interpolation joins evaluated values with literal text through one string grammar. Multiline delimiters allow document text to retain visible line structure in source.
String escape values
Single-line and multiline strings use these escapes, including strings tagged r, sh, sql.
| Escape | Value | Code point |
|---|---|---|
\n | line feed | U+000A |
\r | carriage return | U+000D |
\t | tab | U+0009 |
\\ | backslash | U+005C |
\" | quotation mark | U+0022 |
\{ | opening brace | U+007B |
\} | closing brace | U+007D |
An unknown escape produces TPZ0004 during lexing for every tag. Write an escaped backslash when a literal backslash is intended.
이유
One escape grammar gives a backslash the same meaning in strings and every template tag. Explicit escapes distinguish delimiters from text.
Single-line string boundaries
A single-line string cannot cross a physical LF, CRLF, or CR line break, including inside interpolation. Crossing one produces TPZ0003 during lexing. An escaped carriage return or a carriage return in an inserted string remains character data.
이유
A physical line break ends an unfinished single-line string before later source is consumed as text. Equivalent file line endings must produce the same rejection.
String literal and interpolation types
Ordinary strings use the following type selection.
| Interpolation | Type |
|---|---|
| absent | string literal type |
| present | string |
이유
A fixed literal has a known value that type checking can retain. Interpolation depends on evaluated expressions, so its result uses the general string type.
ByteBuffer interpolation
Interpolating a value whose type contains Byte in a string or tagged template produces TPZ5001 during checking.
이유
ByteBuffer is mutable storage rather than text. Rejecting its implicit display keeps byte decoding and the choice of character encoding explicit.
See Pending contracts for value formatting, evaluation order, and the number of evaluations.
Ordinary string interpolation order and conversion
In an ordinary string, each interpolation expression is evaluated once in source order. A nested interpolation completes before the next outer expression. The value then uses the standard renderer, with no automatic call to a user-defined show method. Inserted spaces and newlines remain unchanged.
| Value family | Conversion |
|---|---|
| Scalars | Strings insert their text. Integers and floats use numeric text. Booleans, null, and unit use their literal spellings. |
| Arrays and structural records | Elements and named fields render recursively, separated by commas. |
| Option and Result | The constructor name surrounds the rendered payload. None has no payload. |
| Nominal values | Records, enum variants, and newtypes retain their nominal identity and recursively render their contents. |
| Collections and ranges | Map and Set use their standard collection displays. Ranges show their endpoints and optional step. |
| Functions and resources | Functions, files, namespaces, and opaque values use their standard display labels. |
| Library values | Bytes use hexadecimal text. Path, Regex, Date, URL, BigInt, Decimal, and other built-in values use their standard representations. |
| Templates | Display a summary with the tag and counts of parts and values. |
A value whose type contains Byte produces TPZ5001 during checking, including inside arrays, records, unions, and nominal fields.
이유
Evaluating each expression once in source order makes effects predictable. Preserving inserted whitespace lets document content determine its own line and spacing structure.
Preserved Unicode string data
Literal text, inserted strings, and template text preserve their Unicode scalar sequence after the specified escape, physical-line-break, indentation, and blank-line processing. They do not apply Unicode normalization or remove Default_Ignorable_Code_Point scalars. Composed and decomposed text can therefore produce different UTF-8 bytes. A name inside an interpolation follows the identifier rules because it is part of the expression.
이유
Text values may carry externally supplied spelling, file contents, or protocol bytes. Implicit Unicode normalization or removal of invisible scalars would lose that data. Names use NFC to give bindings a canonical source spelling. A string preserves its scalar sequence after the separately specified source-text transformations.
Multiline strings
링크Multiline opening line break
In a multiline string, one physical LF, CRLF, or CR line break immediately after the opening delimiter is removed from the value. CRLF is one line break.
이유
Removing the opening line break lets a document text block start on the line after its delimiter without adding an empty first line.
Multiline closing indentation
When the closing delimiter follows spaces and tabs on its own line, that exact prefix is removed from each nonblank text line. Physical LF, CRLF, and CR each start a new line for this check. A nonblank line without that prefix produces TPZ0006 during lexing. The closing indentation is also removed.
이유
Removing the closing delimiter prefix separates source indentation from document indentation. Checking every physical line-ending form prevents file conversion from bypassing the indentation check.
Multiline newline values
Physical LF, CRLF, and CR line breaks in multiline text become LF. CRLF becomes one LF. A newline before the closing indentation remains in the value. Normalization applies to source text before escape decoding and value insertion. An escaped carriage return or a carriage return in an inserted string remains character data. Interpolation expressions use the source expression grammar.
이유
Treating physical LF, CRLF, and CR alike keeps document text stable when a file changes line-ending format. Escapes and inserted values preserve intentional carriage-return data.
Whitespace and interpolation in multiline strings
A multiline source text line containing just spaces (U+0020) and tabs (U+0009) contributes an empty line. Its line break remains. This applies with or without closing indentation, in ordinary and tagged strings. Removal happens before escape decoding and value insertion. Escaped and inserted whitespace remains data. Nonblank indentation compares the exact source prefix, without expanding tabs. An interpolated value cannot supply missing indentation. A prefix mismatch produces TPZ0006 during lexing. Physical LF, CRLF, and CR start new text lines and become LF in the string value.
이유
Blank source lines remain empty when an editor changes their indentation. This keeps document text independent of formatting. Source whitespace is removed before escapes and interpolation, so explicit character data remains intact. Exact nonblank prefixes avoid dependence on an editor tab width.
Tagged templates
링크TemplateLiteral = TemplateTag StringLiteral ;TemplateTag = "r" | "sh" | "sql" ;
String is defined above. Every tag uses its complete escape grammar, including the same delimiter and interpolation-brace escapes.
Tag-specific processing and operations on the resulting template value belong to their library entries.
Registered template tags
The template tags are r, sh, sql. Write the tag immediately before a single-line or triple-quoted string. A different immediately attached identifier produces TPZ2002 during parsing.
이유
The registry keeps template consumers explicit and catches misspelled tags. Paths use the ordinary Path.from call, which accepts both literal and computed strings and returns the same validated Path type. The former p tag produced a template with slash-only display conversion, so it is removed rather than retain a second path-looking spelling with different validation. This follows the Path.from-only owner decision and the one-way-to-say-it criterion. Joining path parts safely is expressed by Path.join. Reading text as a path is expressed by Path.from. A path template tag adds no distinct intent to either operation.
Template value types
A registered tagged template is checked as a template value.
이유
A distinct template type preserves the boundary between structured text and an ordinary string. Consumers can inspect the tag and literal parts before interpreting them.
Each registered tag uses the string escape grammar above. Construction, accessors, and display are defined below. Construct a path with Path.from applied to an ordinary string; p is not a registered template tag.
Tagged-template construction and display
Registered tags construct template values from cooked text parts and expressions evaluated once in source order. There is one more text part than interpolation values. tag returns the tag as a string. parts returns an array value of the literal text segments under value semantics. Interpolated values remain separate and have no public accessor.
| Tag | Construction and string-interpolation display |
|---|---|
r | Keeps the pattern structure without compiling or validating a regular expression. Display reports the tag and counts of parts and values. |
sh | Keeps text and values separate without executing a command. Display reports the tag and counts. |
sql | Keeps query text and values separate without executing a query or inserting values into query text. Display reports the tag and counts. |
A template value cannot be passed where string is required. Use ordinary string interpolation to obtain its display. All tags use the shared string escape grammar. For example, r"\\d" preserves a regex backslash, and \{ and \} preserve literal braces.
이유
Keeping inserted values separate from text lets a consumer interpret their roles without reconstructing them from a string. Construction does not execute the embedded command or query. Joining path parts safely is expressed by Path.join. Reading text as a path is expressed by Path.from. A path template tag adds no distinct intent to either operation.
Constructing paths
링크Construct a normalized Path with Path.from
Path. follows the Path construction contract. That rule defines normalization, input failures and removed construction members.
이유
Path. gives literal, interpolated and computed text one conversion to a relative path. Its construction contract owns normalization and input failures. The old cwd and project factories performed the same pure normalization. Their different error prefixes did not express a distinct operation. The old normalize member returned its receiver. Path. safely combines path parts, while Path. reads text as a path. The removed p tag added no distinct intent to either operation.
Examples and counterexamples
링크Integer bases and decimal floats
링크let decimal: int = 1_000let hexadecimal: int = 0xca_felet binary: int = 0b1010_0101let fraction: float = 1_234.5_6let minimum: int = -9223372036854775808let maximum: int = 9223372036854775807let value: int = 1_0
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Repeated digit separator
링크let value = 1__0
표준 출력 없음.error[TPZ2001]: malformed numeric literal
--> example.tpz:1:13
|
1 | let value = 1__0
| ^^^^
example.tpz: 1 diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ2001]: malformed numeric literal--> example.tpz:1:13|1 | let value = 1__0| ^^^^example.tpz: 1 diagnostic
- 통과 · checking TPZ2001; cause malformed-numeric-literal; primary location asserted; additional diagnostics allow
- 통과 · expected nonzero; observed 1
The intended cause is the repeated underscore inside the numeric token. Replace it with one underscore or remove it.
Exponent spelling
링크let value = 1e3
표준 출력 없음.error[TPZ2001]: malformed numeric literal
--> example.tpz:1:13
|
1 | let value = 1e3
| ^^^
example.tpz: 1 diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ2001]: malformed numeric literal--> example.tpz:1:13|1 | let value = 1e3| ^^^example.tpz: 1 diagnostic
- 통과 · checking TPZ2001; cause malformed-numeric-literal; primary location asserted; additional diagnostics allow
- 통과 · expected nonzero; observed 1
Use 1000. when the intended value is one thousand as a float.
Integer magnitude above the signed range
링크let value = 9223372036854775808
표준 출력 없음.error[TPZ5001]: integer literal `9223372036854775808` is out of range
--> example.tpz:1:13
|
1 | let value = 9223372036854775808
| ^^^^^^^^^^^^^^^^^^^
example.tpz: 1 type diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ5001]: integer literal `9223372036854775808` is out of range--> example.tpz:1:13|1 | let value = 9223372036854775808| ^^^^^^^^^^^^^^^^^^^example.tpz: 1 type diagnostic
- 통과 · checking TPZ5001; cause integer-literal-out-of-range; primary location asserted; additional diagnostics allow
- 통과 · expected nonzero; observed 1
Boolean, null, and unit values
링크let enabled: bool = truelet disabled: bool = falselet absent = nulllet completed: () = ()
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
Duration in its timeout context
링크let result = concurrent(timeout: 1_500ms) {value: 1} else {{ value: 0 }}
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
A Duration value outside a timeout
링크let delay = 3slet saved: Duration = (delay)
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
The stable example identity formerly tested the SELF-only context restriction. Its old fixture, assertion plan and receipt remain historical evidence. The current version expects an ordinary Duration binding to succeed; the original receipt is not evidence of this revised contract.
Length suffixes and types
링크let points: Length<Pt> = 12ptlet millimeters: Length<Mm> = 2.5mmlet centimeters: Length<Cm> = 1cmlet inches: Length<In> = 0.5inlet relative: Length<Em> = 1.25em
example.tpz: types-ok (1 module)
example.tpz: resolve-ok (1 module)
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
example.tpz: types-ok (1 module)example.tpz: resolve-ok (1 module)
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
Escapes and an interpolated value
링크import std.iolet count = 3io.writeLine("Topaz {count}: \"\{ok\}\"\\")io.writeLine("first\nsecond\tend")
Topaz 3: "{ok}"\
first
second end
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
Topaz 3: "{ok}"\firstsecond end
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
Topaz 3: "{ok}"\firstsecond end
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
Unknown escape
링크let text = "bad\q"
표준 출력 없음.error[TPZ0004]: invalid escape `\q` in a string literal
--> example.tpz:1:16
|
1 | let text = "bad\q"
| ^^
example.tpz: 1 diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ0004]: invalid escape `\q` in a string literal--> example.tpz:1:16|1 | let text = "bad\q"| ^^example.tpz: 1 diagnostic
- 통과 · checking TPZ0004; cause invalid-string-escape; primary location asserted; additional diagnostics allow
- 통과 · expected nonzero; observed 1
Replace the unknown escape with a supported escape or write an escaped backslash when a literal backslash is intended.
Multiline indentation and final newline
링크import std.ioio.writeLine("""firstsecond""")
first
second
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
firstsecond
관측한 단언 · 통과 · 5.21.3
종료 코드 0.
firstsecond
표준 오류 출력 없음.
- 통과 · expected 0; observed 0
- 통과 · stdout matches the authored expectation
- 통과 · stdout matches the authored expectation
- 통과 · stdout matches the authored expectation
- 통과 · stderr matches the authored expectation
The four registered template tags
링크let regexTemplate = r"a+"let shellTemplate = sh"echo hello"let sqlTemplate = sql"select {1}"
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Tag outside the registry
링크let value = html"hello"
표준 출력 없음.error[TPZ2002]: unknown template tag `html`; the registry is `p`, `r`, `sh`, `sql`
--> example.tpz:1:13
|
1 | let value = html"hello"
| ^^^^
example.tpz: 1 diagnostic
기대 결과
관측한 단언 · 통과 · 5.21.3
종료 코드 1.
표준 출력 없음.
error[TPZ2002]: unknown template tag `html`; the registry is `p`, `r`, `sh`, `sql`--> example.tpz:1:13|1 | let value = html"hello"| ^^^^example.tpz: 1 diagnostic
- 통과 · checking TPZ2002; cause unknown-template-tag; primary location asserted; additional diagnostics allow
- 통과 · expected nonzero; observed 1
The counterexample uses the tag html. The program does not invoke an HTML operation.
Blank source lines stay empty while CRLF and CR become LF
링크import std.iolet part = "x"let value = """A{part}B C"""io.writeLine(value.encodeUtf8().toHex())
41780a0a420a430a
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
41780a0a420a430a
A tab prefix is not two spaces
링크let value = """first"""
기대 결과
Interpolation cannot supply source indentation
링크let padding = " "let value = """{padding}body"""
기대 결과
Observe ties-to-even through equality and unit conversion
링크import std.iolet half = 0.00000762939453125ptlet oneAndHalf = 0.00002288818359375ptlet two = 0.000030517578125ptio.writeLine("{half == 0pt}|{oneAndHalf == two}|{-half == 0pt}")io.writeLine("{(25.4mm).toPt() == 72pt}|{(2.54cm).toPt() == 72pt}|{(1in).toPt() == 72pt}")io.writeLine("{0.00000762939453125em == 0em}|{0.00002288818359375em == 0.000030517578125em}")
true|true|true
true|true|true
true|true
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
true|true|truetrue|true|truetrue|true
Decimal values inside both limits for every unit
링크let good0 = -140737488355328.000007629394531250000000000000ptlet good1 = 140737488355327.999992370605468749999999999999ptlet good2 = -49649058392018.488891580369737413194444444444mmlet good3 = 49649058392018.488886197408040364583333333333mmlet good4 = -4964905839201.848889158036973741319444444444cmlet good5 = 4964905839201.848888619740804036458333333333cmlet good6 = -1954687338268.444444550408257378472222222222inlet good7 = 1954687338268.444444338480631510416666666666inlet good8 = -140737488355328.000007629394531250000000000000emlet good9 = 140737488355327.999992370605468749999999999999em
기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Observe rounding, infinity, subnormals, and signed zero
링크import std.iolet tieEven = 1.00000000000000011102230246251565404236316680908203125let tieNext = 1.00000000000000033306690738754696212708950042724609375let overflow = 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0let tiny = 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001let subnormal = 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005let twiceSubnormal = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001io.writeLine("{tieEven == 1.0}|{tieNext == 1.0000000000000004}")io.writeLine("{overflow}|{-overflow}")io.writeLine("{tiny}|{-tiny}|{1.0 / tiny}|{1.0 / -tiny}")io.writeLine("{subnormal > 0.0}|{subnormal < twiceSubnormal}|{subnormal + subnormal == twiceSubnormal}")
true|true
inf|-inf
0.0|-0.0|inf|-inf
true|true|true
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
true|trueinf|-inf0.0|-0.0|inf|-inftrue|true|true
Exponent spelling is not a decimal float literal
링크let value = 1.0e3
기대 결과
Nested interpolations evaluate each occurrence once
링크import std.iofunction mark(n: int) -> int { io.writeLine("mark {n}")n }let value = "outer {mark(1)}|{"inner {mark(2)}"}|{mark(3)}"io.writeLine(value)
mark 1
mark 2
mark 3
outer 1|inner 2|3
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
mark 1mark 2mark 3outer 1|inner 2|3
Display scalars and nested values with the standard renderer
링크import std.iolet row = { count: 3 }let selected: Option<int> = Some(3)let missing: Option<int> = None()let ok: Result<int, string> = Ok(4)let err: Result<int, string> = Err("no")io.writeLine("{7}|{2.5}|{true}|{()}|{null}")io.writeLine("{[1, 2]}|{row}|{selected}|{missing}|{ok}|{err}")
7|2.5|true|()|null
[1, 2]|{ count: 3 }|Some(3)|None|Ok(4)|Err(no)
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
7|2.5|true|()|null[1, 2]|{ count: 3 }|Some(3)|None|Ok(4)|Err(no)
An aggregate containing ByteBuffer cannot be interpolated
링크let buffer = ByteBuffer.allocate(1)let nested = [buffer]let value = "{nested}"
기대 결과
Inspect templates without executing or validating their contents
링크import std.ioimport std.path { Path }function mark(n: int) -> int { io.writeLine("mark {n}")n }let segment = "a\\b"let path = match (Path.from("dir\\{segment}/{mark(1)}")) {case Ok(value) => value.toString()case Err(error) => error}let pattern = r"[{mark(2)}"let command = sh"echo {mark(3)}"let query = sql"SELECT {mark(4)}"io.writeLine("{path}")io.writeLine("{pattern}|{command}|{query}")io.writeLine("{query.tag}|{query.parts.length}|{query.parts[0]}|{query.parts[1]}")let mut parts = query.partsparts[0] = "changed"io.writeLine("{query.parts[0]}")
mark 1
mark 2
mark 3
mark 4
dir/a/b/1
<r template, 2 part(s), 1 interpolation(s)>|<sh template, 2 part(s), 1 interpolation(s)>|<sql template, 2 part(s), 1 interpolation(s)>
sql|2|SELECT |
SELECT
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
mark 1mark 2mark 3mark 4dir/a/b/1<r template, 2 part(s), 1 interpolation(s)>|<sh template, 2 part(s), 1 interpolation(s)>|<sql template, 2 part(s), 1 interpolation(s)>sql|2|SELECT |SELECT
The parts accessor returns an array value under value semantics. Changing parts leaves query. unchanged.
A template value cannot initialize string
링크let value: string = sql"SELECT 1"
기대 결과
Tagged interpolation rejects ByteBuffer too
링크let buffer = ByteBuffer.allocate(1)let value = sql"SELECT {buffer}"
기대 결과
Reject a value past the negative pt limit
링크let bad0 = -140737488355328.000007629394531250000000000001pt
기대 결과
Reject a value past the positive pt limit
링크let bad1 = 140737488355327.999992370605468750000000000000pt
기대 결과
Reject a value past the negative mm limit
링크let bad2 = -49649058392018.488891580369737413194444444445mm
기대 결과
Reject a value past the positive mm limit
링크let bad3 = 49649058392018.488886197408040364583333333334mm
기대 결과
Reject a value past the negative cm limit
링크let bad4 = -4964905839201.848889158036973741319444444445cm
기대 결과
Reject a value past the positive cm limit
링크let bad5 = 4964905839201.848888619740804036458333333334cm
기대 결과
Reject a value past the negative in limit
링크let bad6 = -1954687338268.444444550408257378472222222223in
기대 결과
Reject a value past the positive in limit
링크let bad7 = 1954687338268.444444338480631510416666666667in
기대 결과
Reject a value past the negative em limit
링크let bad8 = -140737488355328.000007629394531250000000000001em
기대 결과
Reject a value past the positive em limit
링크let bad9 = 140737488355327.999992370605468750000000000000em
기대 결과
Every tag cooks the same single-line escapes
링크import std.iolet pattern = r"\n\r\t\\\"\{\}"io.writeLine(pattern.parts[0])let command = sh"\n\r\t\\\"\{\}"io.writeLine(command.parts[0])let query = sql"\n\r\t\\\"\{\}"io.writeLine(query.parts[0])
\"{}
\"{}
\"{}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
\"{}\"{}\"{}
The standard-output expectation checks the actual LF, CR, tab, backslash, quotation-mark, and brace characters in each cooked text part.
Every tag cooks the same multiline escapes
링크import std.iolet pattern = r"""\n\r\t\\\"\{\}"""io.writeLine(pattern.parts[0])let command = sh"""\n\r\t\\\"\{\}"""io.writeLine(command.parts[0])let query = sql"""\n\r\t\\\"\{\}"""io.writeLine(query.parts[0])
\"{}
\"{}
\"{}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
\"{}\"{}\"{}
The standard-output expectation checks the actual LF, CR, tab, backslash, quotation-mark, and brace characters in each cooked text part.
Unknown escape in a r template
링크let value = r"\d"
기대 결과
Use a supported escape or double the backslash to keep it as literal text.
Unknown escape in a sh template
링크let value = sh"\q"
기대 결과
Use a supported escape or double the backslash to keep it as literal text.
Unknown escape in a sql template
링크let value = sql"\q"
기대 결과
Use a supported escape or double the backslash to keep it as literal text.
Preserve a regex backslash and literal braces
링크import std.iolet pattern = r"\\d+\{n\}"io.writeLine(pattern.parts[0])
\d+{n}
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
\d+{n}
Unknown escape in a multiline r template
링크let pattern = r"""\d"""
기대 결과
Reject uppercase hex prefix
링크let value = 0Xff
기대 결과
Reject uppercase binary prefix
링크let value = 0B1010
기대 결과
Reject uppercase hex digit
링크let value = 0xA
기대 결과
Reject mixed case hex digit
링크let value = 0xaF
기대 결과
Read lowercase radix literals
링크import std.io { writeLine }writeLine("{0xff}")writeLine("{0b1010}")writeLine("{0xabcdef}")
255
10
11259375
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
2551011259375
Reject physical LF in single-line text
링크let value = "leftright"
기대 결과
Reject physical LF in single-line interpolation
링크let value = "{1+ 2}"
기대 결과
Reject physical CRLF in single-line text
링크let value = "leftright"
기대 결과
Reject physical CRLF in single-line interpolation
링크let value = "{1+ 2}"
기대 결과
Reject physical CR in single-line text
링크let value = "left right"
기대 결과
Reject physical CR in single-line interpolation
링크let value = "{1 + 2}"
기대 결과
Reject physical CR in a string nested inside single-line interpolation
링크let value = "{""" inner"""}"
기대 결과
Physical CRLF uses the same multiline text and indentation
링크import std.iolet value = """firstsecond"""io.writeLine(value.encodeUtf8().toHex())
66697273740a7365636f6e640a
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
66697273740a7365636f6e640a
Physical CR uses the same multiline text and indentation
링크import std.iolet value = """ first second """io.writeLine(value.encodeUtf8().toHex())
66697273740a7365636f6e640a
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
66697273740a7365636f6e640a
Reject missing indentation after a physical CR
링크let value = """first second"""
기대 결과
Escaped carriage returns remain character data
링크import std.iolet opening = """\rhead"""let single = "S\rE"let multi = """M\rN"""io.writeLine(opening.encodeUtf8().toHex())io.writeLine(single.encodeUtf8().toHex())io.writeLine(multi.encodeUtf8().toHex())
0d68656164
530d45
4d0d4e0a
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
0d68656164530d454d0d4e0a
An inserted carriage return decoded from bytes remains character data
링크import std.iolet data = match (Bytes.fromHex("0d")) {case Ok(bytes) => match (bytes.decodeUtf8()) {case Ok(value) => valuecase Err(_) => ""}case Err(_) => ""}let opening = """{data}head"""let single = "L{data}R"let multi = """L{data}R"""io.writeLine(opening.encodeUtf8().toHex())io.writeLine(single.encodeUtf8().toHex())io.writeLine(multi.encodeUtf8().toHex())
0d68656164
4c0d52
4c0d520a
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
0d686561644c0d524c0d520a
Blank source lines ignore indentation
링크import std.iolet indented = """AB"""let unindented = """AB"""let tagged = r"""AB"""io.writeLine(indented.encodeUtf8().toHex())io.writeLine(unindented.encodeUtf8().toHex())io.writeLine(tagged.parts[0].encodeUtf8().toHex())
410a0a0a420a
410a0a42
410a0a420a
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
410a0a0a420a410a0a42410a0a420a
Escaped and inserted whitespace remains data
링크import std.iolet inserted = " \t"let value = """A\t{inserted}B"""io.writeLine(value.encodeUtf8().toHex())
410a090a20090a420a
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
410a090a20090a420a
Path construction uses Path.from instead of the p tag
링크let value = p"notes"
기대 결과
Path construction uses Path.from instead of the p tag
링크let value = p"""notes"""
기대 결과
Path.from normalizes literal and interpolated text
링크import std.ioimport std.path { Path }function normalized(text: string) -> string {match (Path.from(text)) {case Ok(value) => value.toString()case Err(error) => error}}let directory = "notes"io.writeLine(normalized("./{directory}//draft/../chapter.tpz"))io.writeLine(normalized("notes\\draft\\..\\chapter.tpz"))io.writeLine(normalized("notes/.."))io.writeLine(normalized("Notes/가.TPZ"))
notes/chapter.tpz
notes/chapter.tpz
.
Notes/가.TPZ
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
notes/chapter.tpznotes/chapter.tpz.Notes/가.TPZ
Invalid path text is an Err result
링크import std.ioimport std.path { Path }function outcome(text: string) -> string {match (Path.from(text)) {case Ok(_) => "Ok"case Err(_) => "Err"}}io.writeLine("empty: {outcome("")}")io.writeLine("absolute: {outcome("/notes")}")io.writeLine("drive: {outcome("C:notes")}")io.writeLine("escape: {outcome("../notes")}")
empty: Err
absolute: Err
drive: Err
escape: Err
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
empty: Errabsolute: Errdrive: Errescape: Err
Use Path.from instead of Path.cwdRelative
링크import std.path { Path }let value = Path.cwdRelative("notes")
기대 결과
Use Path.from instead of Path.project
링크import std.path { Path }let value = Path.project("notes")
기대 결과
A Path is already normalized
링크import std.path { Path }function keep(value: Path) -> Path { value.normalize() }
기대 결과
Use an existing Path directly
링크import std.path { Path }function keep(value: Path) -> Path { value }
표준 출력 없음.기대 결과
기대 결과
검사가 프로그램을 받아들입니다. 종료 코드 0.
Preserve composed, decomposed, and invisible string data
링크import std.iolet composed = "é"let decomposed = "é"let hangul = "가"let invisible = "a͏️"let inserted = "{decomposed}"io.writeLine(composed.encodeUtf8().toHex())io.writeLine(decomposed.encodeUtf8().toHex())io.writeLine(hangul.encodeUtf8().toHex())io.writeLine(invisible.encodeUtf8().toHex())io.writeLine(inserted.encodeUtf8().toHex())
c3a9
65cc81
e18480e185a1
61cd8fe2808defb88f
65cc81
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
c3a965cc81e18480e185a161cd8fe2808defb88f65cc81
Add and subtract Duration values
링크import std.io { writeLine }let sum = 1s + 500mslet difference = 2s - 500mswriteLine("{sum}")writeLine("{difference}")
1500ms
1500ms
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
1500ms1500ms
Multiply a Duration by an int in either order
링크import std.io { writeLine }let count = 3let left = 500ms * countlet right = count * 500mslet constructed = 1ms * countwriteLine("{left}")writeLine("{right}")writeLine("{constructed}")
1500ms
1500ms
3ms
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
1500ms1500ms3ms
Compare Duration values by milliseconds
링크import std.io { writeLine }let first = 1slet same = 1000mslet later = 2swriteLine("{Eq.equals(first, same)}")writeLine("{Order.compare(first, later) < 0}")writeLine("{first == same}")writeLine("{first != later}")writeLine("{first < later}")writeLine("{first <= same}")writeLine("{later > first}")writeLine("{same >= first}")
true
true
true
true
true
true
true
true
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
truetruetruetruetruetruetruetrue
Display millisecond literals and extract int milliseconds
링크import std.io { writeLine }let delay = 1500mslet minute = 1mlet second = 1slet zero = 0mslet endpoint = 18446744073709551615mslet intEndpoint = 9223372036854775807mswriteLine(Show.show(delay))writeLine("{delay.toMillis()}")writeLine("{minute.toMillis()}")writeLine("{second.toMillis()}")writeLine("{zero}")writeLine("{endpoint}")writeLine("{intEndpoint.toMillis()}")
1500ms
1500
60000
1000
0ms
18446744073709551615ms
9223372036854775807
기대 결과
기대 결과
실행을 마칩니다. 종료 코드 0.
1500ms15006000010000ms18446744073709551615ms9223372036854775807
Reject a Duration subtraction below zero
링크let earlier = 1mslet later = 2mslet difference = earlier - later
표준 출력 없음.기대 결과
Reject a Duration sum outside its millisecond range
링크let largest = 18446744073709551615mslet result = largest + 1ms
표준 출력 없음.기대 결과
Reject a Duration product outside its millisecond range
링크let large = 9223372036854775807mslet result = large * 3
표준 출력 없음.기대 결과
Reject multiplication by a negative int
링크let delay = 1mslet count = -1let result = delay * count
표준 출력 없음.기대 결과
Reject a millisecond count outside int
링크let delay = 9223372036854775808mslet count = delay.toMillis()
표준 출력 없음.기대 결과
Pending contracts
링크Related reference
링크Lexical structure owns token boundaries and reserved spellings. General type compatibility belongs to Types; arithmetic and grouping belong to Expressions and operators. The enclosing timeout form belongs to Concurrency. Diagnostic entries own complete causes and remedies for each qualified diagnostic.