feat(stdlib): namespaced standard library (issue #2)
Implement the bulk of the namespaced-stdlib proposal (workshopsoft/ludic#2): 156 namespace methods across Math, Text, List, Ease, Collide, World, Net, Sys, Save, Mem, extended Screen, Color functions, extended Random, and Time. All deterministic fixed-point; self-hosting (C-free bootstrap fixpoint holds). Compiler (selfhost/): - Math.*: sqrt/sin/cos/tan/atan2/asin/acos (fixed-point runtime prelude — bit-by-bit isqrt, 256-entry interpolated sine table, Ross atan2), plus hypot/dist/dist2/deg_to_rad/rad_to_deg/posmod/wrap/ping_pong/snapped/ move_toward/smoothstep/lerp/remap/sign/floor/ceil/round. - Text.* (complete): upper/lower/trim/repeat/pad, split/join/replace, and the libc-backed queries. - List.* (complete): insert/remove_at/remove/sort plus the earlier ops. - Ease.* (in/out/in_out/back/bounce) and Collide.* (rects/point_rect/ circles/rect_circle). - Phase 3: World/Net/Sys/Save namespaced over the bare builtins (byte- identical IR) and Mem.* (bytes/words/copy/fill/peek/poke). - Screen.* extended (line/circle/fill_circle/triangle/fill_triangle via new runtime primitives; sprite/sprite_scaled aliases), Color.* functions, Random.* (value/int/sign), Time.* (frame/delta/elapsed/now — new game-loop frame counter). - Fix a lexer bug: fixed-point literals with >4 fractional digits overflowed. Docs & tooling: - 129 new per-symbol doc pages; gen.py made data-driven (namespaces discovered from the docs, no hardcoded list); new check-impl.py enforces that every implemented namespace method / keyword / type / phase has a doc page, wired into `x test-tools`. Document the previously-undocumented keywords (break/continue/where/entry/new/public + and/or/not tokens). - LSP: namespaced signature help (ns_method_sig) covering every namespace. Tests: 12 new self-host/regression tests + a golden render for the drawing primitives. All suites green (selfhost 21, regression 45, tools 29). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
ff15c4e01d
commit
a38195128f
235 changed files with 24676 additions and 7762 deletions
7
docs/language/text/_section.md
Normal file
7
docs/language/text/_section.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
id: text
|
||||
title: Text
|
||||
order: 6
|
||||
---
|
||||
|
||||
String queries and building over <code>str</code> values — length, character access, substrings, search, prefix/suffix tests, and int conversion. Arguments are positional. Strings are byte sequences, so indices and lengths count bytes.
|
||||
29
docs/language/text/text-char_at.md
Normal file
29
docs/language/text/text-char_at.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
id: text-char_at
|
||||
name: Text.char_at
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.char_at
|
||||
sig: Text.char_at(s, i) -> int
|
||||
tip: The byte value at an index, 0..255.
|
||||
order: 1
|
||||
ns: Text
|
||||
member: char_at
|
||||
---
|
||||
|
||||
Returns the byte at position <code>i</code> in <code>s</code> as an <code>int</code> in the range <code>0</code>..<code>255</code> — for example <code>Text.char_at("hello", 0)</code> is <code>104</code>, the code for <code>h</code>. Indices are zero-based and count bytes. Use it to inspect or classify individual characters, such as testing whether a key of input is a digit.
|
||||
|
||||
Parameters:
|
||||
- `s` — the string to read from
|
||||
- `i` — the zero-based byte index
|
||||
|
||||
```ludic
|
||||
program FirstIsDigit {
|
||||
var entry: str = "7up"
|
||||
|
||||
handler Check phase Update {
|
||||
let c = Text.char_at(entry, 0)
|
||||
let is_digit = c >= 48 and c <= 57 # true: '7'
|
||||
}
|
||||
}
|
||||
```
|
||||
28
docs/language/text/text-concat.md
Normal file
28
docs/language/text/text-concat.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
id: text-concat
|
||||
name: Text.concat
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.concat
|
||||
sig: Text.concat(a, b) -> str
|
||||
tip: Join two strings into a new one.
|
||||
order: 8
|
||||
ns: Text
|
||||
member: concat
|
||||
---
|
||||
|
||||
Returns a fresh string that is <code>a</code> followed by <code>b</code>. It is the call form of the <code>a + b</code> string operator and allocates a new string, leaving the inputs untouched. For building a line from several pieces, backtick interpolation such as <code>`score: {n}`</code> is usually clearer; reach for <code>Text.concat</code> when joining two values you already hold.
|
||||
|
||||
Parameters:
|
||||
- `a` — the left string
|
||||
- `b` — the right string
|
||||
|
||||
```ludic
|
||||
program Greeting {
|
||||
var name: str = "world"
|
||||
|
||||
handler Build phase Update {
|
||||
let line = Text.concat("hello ", name) # "hello world"
|
||||
}
|
||||
}
|
||||
```
|
||||
30
docs/language/text/text-contains.md
Normal file
30
docs/language/text/text-contains.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
id: text-contains
|
||||
name: Text.contains
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.contains
|
||||
sig: Text.contains(s, sub) -> bool
|
||||
tip: Whether a substring appears anywhere in a string.
|
||||
order: 5
|
||||
ns: Text
|
||||
member: contains
|
||||
---
|
||||
|
||||
Returns <code>true</code> when <code>sub</code> occurs anywhere inside <code>s</code>. An empty substring is always considered present. Use it for a quick membership test — filtering a log line, checking for a forbidden word, or seeing whether a path includes a folder — when you do not need the position. Reach for <code>Text.index_of</code> when you also want where it matched.
|
||||
|
||||
Parameters:
|
||||
- `s` — the string to search
|
||||
- `sub` — the substring to look for
|
||||
|
||||
```ludic
|
||||
program Filter {
|
||||
var line: str = "error: disk full"
|
||||
|
||||
handler Scan phase Update {
|
||||
if Text.contains(line, "error") {
|
||||
# flag it
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
28
docs/language/text/text-ends_with.md
Normal file
28
docs/language/text/text-ends_with.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
id: text-ends_with
|
||||
name: Text.ends_with
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.ends_with
|
||||
sig: Text.ends_with(s, suffix) -> bool
|
||||
tip: Whether a string ends with a given suffix.
|
||||
order: 4
|
||||
ns: Text
|
||||
member: ends_with
|
||||
---
|
||||
|
||||
Returns <code>true</code> when <code>s</code> ends with <code>suffix</code>, comparing the tail of the string over the suffix's length. If the suffix is longer than the string it simply returns <code>false</code>. Use it to detect file types by extension, recognize a trailing marker, or validate that input closes as expected.
|
||||
|
||||
Parameters:
|
||||
- `s` — the string to test
|
||||
- `suffix` — the trailing substring to look for
|
||||
|
||||
```ludic
|
||||
program IsImage {
|
||||
var filename: str = "hero.png"
|
||||
|
||||
handler Classify phase Update {
|
||||
let png = Text.ends_with(filename, ".png") # true
|
||||
}
|
||||
}
|
||||
```
|
||||
31
docs/language/text/text-equals.md
Normal file
31
docs/language/text/text-equals.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
id: text-equals
|
||||
name: Text.equals
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.equals
|
||||
sig: Text.equals(a, b) -> bool
|
||||
tip: Whether two strings have identical bytes.
|
||||
order: 7
|
||||
ns: Text
|
||||
member: equals
|
||||
---
|
||||
|
||||
Returns <code>true</code> when <code>a</code> and <code>b</code> hold the same bytes in the same order. This is a value comparison, not a pointer check, and is exactly what the <code>==</code> operator does between two strings — <code>Text.equals</code> is the named form for readability. Use it to match input against a keyword or compare a slice with an expected token.
|
||||
|
||||
Parameters:
|
||||
- `a` — the first string
|
||||
- `b` — the second string
|
||||
|
||||
```ludic
|
||||
program Guess {
|
||||
var answer: str = "swordfish"
|
||||
var attempt: str = "swordfish"
|
||||
|
||||
handler Check phase Update {
|
||||
if Text.equals(attempt, answer) {
|
||||
# correct
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
27
docs/language/text/text-from_int.md
Normal file
27
docs/language/text/text-from_int.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
id: text-from_int
|
||||
name: Text.from_int
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.from_int
|
||||
sig: Text.from_int(n) -> str
|
||||
tip: Render an integer as a string.
|
||||
order: 10
|
||||
ns: Text
|
||||
member: from_int
|
||||
---
|
||||
|
||||
Returns the decimal text of the integer <code>n</code> — <code>Text.from_int(1234)</code> is <code>"1234"</code>, and negatives keep their sign. It is the same conversion as the bare <code>str(n)</code> and the inverse of <code>Text.to_int</code>. Use it when you need a number as characters — to measure its width, concatenate it, or store it — though drawing a number to the screen is better done with <code>Screen.draw_number</code>.
|
||||
|
||||
Parameters:
|
||||
- `n` — the integer to render
|
||||
|
||||
```ludic
|
||||
program ScoreLabel {
|
||||
var score: int = 1500
|
||||
|
||||
handler Build phase Update {
|
||||
let label = Text.concat("score: ", Text.from_int(score))
|
||||
}
|
||||
}
|
||||
```
|
||||
30
docs/language/text/text-index_of.md
Normal file
30
docs/language/text/text-index_of.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
id: text-index_of
|
||||
name: Text.index_of
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.index_of
|
||||
sig: Text.index_of(s, sub) -> int
|
||||
tip: The byte index of a substring, or -1 if absent.
|
||||
order: 6
|
||||
ns: Text
|
||||
member: index_of
|
||||
---
|
||||
|
||||
Returns the zero-based byte index where <code>sub</code> first appears in <code>s</code>, or <code>-1</code> if it never does — so <code>Text.index_of("hello world", "world")</code> is <code>6</code>. Use it to locate a separator before slicing, or as a present-and-where test in one call: guard with <code>if idx >= 0</code>. It reports the first match only.
|
||||
|
||||
Parameters:
|
||||
- `s` — the string to search
|
||||
- `sub` — the substring to locate
|
||||
|
||||
```ludic
|
||||
program KeyValue {
|
||||
var pair: str = "hp=42"
|
||||
|
||||
handler Parse phase Update {
|
||||
let eq = Text.index_of(pair, "=") # 2
|
||||
let key = Text.slice(pair, 0, eq) # "hp"
|
||||
let value = Text.to_int(Text.slice(pair, eq + 1, Text.length(pair)))
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/text/text-join.md
Normal file
22
docs/language/text/text-join.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: text-join
|
||||
name: Text.join
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.join
|
||||
sig: Text.join(parts, sep) -> str
|
||||
tip: Join a list of strings with a separator.
|
||||
order: 18
|
||||
ns: Text
|
||||
member: join
|
||||
---
|
||||
|
||||
Concatenates the strings in the slice <code>parts</code> into one string, placing <code>sep</code> between each — the inverse of <code>Text.split</code>. With an empty separator it simply concatenates. Use it to build a CSV row, a path, or a display list from pieces.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let line = Text.join(fields, ",")
|
||||
}
|
||||
}
|
||||
```
|
||||
27
docs/language/text/text-length.md
Normal file
27
docs/language/text/text-length.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
id: text-length
|
||||
name: Text.length
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.length
|
||||
sig: Text.length(s) -> int
|
||||
tip: The number of bytes in a string.
|
||||
order: 0
|
||||
ns: Text
|
||||
member: length
|
||||
---
|
||||
|
||||
Returns how many bytes are in <code>s</code>, not counting the terminating zero. It is the same count as the bare <code>len(s)</code>, exposed under the <code>Text</code> namespace for discoverability. Use it to size a HUD field, walk a string by index, or check for emptiness with <code>Text.length(s) == 0</code>.
|
||||
|
||||
Parameters:
|
||||
- `s` — the string to measure
|
||||
|
||||
```ludic
|
||||
program NameWidth {
|
||||
var label: str = "player one"
|
||||
|
||||
handler Draw phase Render {
|
||||
let width = Text.length(label) * 6 # 6 px per glyph
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/text/text-lower.md
Normal file
22
docs/language/text/text-lower.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: text-lower
|
||||
name: Text.lower
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.lower
|
||||
sig: Text.lower(s) -> str
|
||||
tip: A lowercased copy of a string.
|
||||
order: 12
|
||||
ns: Text
|
||||
member: lower
|
||||
---
|
||||
|
||||
Returns a fresh string with every ASCII letter <code>A</code>-<code>Z</code> turned to lowercase; other bytes pass through unchanged. Pair it with <code>Text.equals</code> for case-insensitive matching by lowercasing both sides. Only ASCII is transformed.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
if Text.equals(Text.lower(cmd), "quit") { stop() }
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/text/text-pad_left.md
Normal file
22
docs/language/text/text-pad_left.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: text-pad_left
|
||||
name: Text.pad_left
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.pad_left
|
||||
sig: Text.pad_left(s, width) -> str
|
||||
tip: Pad with spaces on the left to a width.
|
||||
order: 15
|
||||
ns: Text
|
||||
member: pad_left
|
||||
---
|
||||
|
||||
Returns <code>s</code> padded with leading spaces until it is at least <code>width</code> bytes long; a string already that long is returned unchanged (never truncated). Right-aligns numbers and labels in a fixed-width HUD column.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let cell = Text.pad_left(Text.from_int(score), 6)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/text/text-pad_right.md
Normal file
22
docs/language/text/text-pad_right.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: text-pad_right
|
||||
name: Text.pad_right
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.pad_right
|
||||
sig: Text.pad_right(s, width) -> str
|
||||
tip: Pad with spaces on the right to a width.
|
||||
order: 16
|
||||
ns: Text
|
||||
member: pad_right
|
||||
---
|
||||
|
||||
Returns <code>s</code> padded with trailing spaces until it is at least <code>width</code> bytes long; a string already that long is returned unchanged. Left-aligns text into fixed-width columns for tables and menus.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let cell = Text.pad_right(label, 12)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/text/text-repeat.md
Normal file
22
docs/language/text/text-repeat.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: text-repeat
|
||||
name: Text.repeat
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.repeat
|
||||
sig: Text.repeat(s, n) -> str
|
||||
tip: A string repeated n times.
|
||||
order: 14
|
||||
ns: Text
|
||||
member: repeat
|
||||
---
|
||||
|
||||
Returns <code>s</code> concatenated with itself <code>n</code> times; <code>n <= 0</code> yields the empty string. Handy for drawing a text bar, an indent, or a separator line without a loop.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let bar = Text.repeat("#", filled)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/text/text-replace.md
Normal file
22
docs/language/text/text-replace.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: text-replace
|
||||
name: Text.replace
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.replace
|
||||
sig: Text.replace(s, from, to) -> str
|
||||
tip: Replace every occurrence of a substring.
|
||||
order: 19
|
||||
ns: Text
|
||||
member: replace
|
||||
---
|
||||
|
||||
Returns a fresh string with every occurrence of <code>from</code> in <code>s</code> replaced by <code>to</code>; if <code>from</code> never appears the string is returned unchanged. Use it to substitute tokens in a template, swap a delimiter, or sanitize input.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let path = Text.replace(name, " ", "_")
|
||||
}
|
||||
}
|
||||
```
|
||||
30
docs/language/text/text-slice.md
Normal file
30
docs/language/text/text-slice.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
id: text-slice
|
||||
name: Text.slice
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.slice
|
||||
sig: Text.slice(s, a, b) -> str
|
||||
tip: A substring covering bytes [a, b).
|
||||
order: 2
|
||||
ns: Text
|
||||
member: slice
|
||||
---
|
||||
|
||||
Returns a fresh string of the bytes from index <code>a</code> up to but not including <code>b</code> — the half-open range <code>[a, b)</code>, so <code>Text.slice("hello world", 0, 5)</code> is <code>"hello"</code>. It is the call form of the <code>s[a..b]</code> slice syntax and allocates a new string. Use it to cut a fixed-width field, drop a prefix, or take the first few characters of a name.
|
||||
|
||||
Parameters:
|
||||
- `s` — the source string
|
||||
- `a` — the start byte index (inclusive)
|
||||
- `b` — the end byte index (exclusive)
|
||||
|
||||
```ludic
|
||||
program FirstWord {
|
||||
var line: str = "hello world"
|
||||
|
||||
handler Split phase Update {
|
||||
let space = Text.index_of(line, " ") # 5
|
||||
let word = Text.slice(line, 0, space) # "hello"
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/text/text-split.md
Normal file
22
docs/language/text/text-split.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: text-split
|
||||
name: Text.split
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.split
|
||||
sig: Text.split(s, sep) -> []str
|
||||
tip: Split a string on a separator into a list.
|
||||
order: 17
|
||||
ns: Text
|
||||
member: split
|
||||
---
|
||||
|
||||
Splits <code>s</code> at every occurrence of the non-empty separator <code>sep</code> and returns the pieces as a <code>[]str</code> — the inverse of <code>Text.join</code>. Adjacent separators yield empty pieces, and a string with no separator returns a one-element list holding the whole string. Use it to parse CSV rows, command arguments, or delimited save data.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let fields = Text.split(line, ",")
|
||||
}
|
||||
}
|
||||
```
|
||||
30
docs/language/text/text-starts_with.md
Normal file
30
docs/language/text/text-starts_with.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
id: text-starts_with
|
||||
name: Text.starts_with
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.starts_with
|
||||
sig: Text.starts_with(s, prefix) -> bool
|
||||
tip: Whether a string begins with a given prefix.
|
||||
order: 3
|
||||
ns: Text
|
||||
member: starts_with
|
||||
---
|
||||
|
||||
Returns <code>true</code> when <code>s</code> begins with <code>prefix</code>, comparing byte for byte over the length of the prefix. An empty prefix always matches. Use it to route commands (<code>"/help ..."</code>), recognize a tag, or branch on a filename extension without slicing first.
|
||||
|
||||
Parameters:
|
||||
- `s` — the string to test
|
||||
- `prefix` — the leading substring to look for
|
||||
|
||||
```ludic
|
||||
program Command {
|
||||
var input: str = "/say hello"
|
||||
|
||||
handler Parse phase Update {
|
||||
if Text.starts_with(input, "/say ") {
|
||||
let msg = Text.slice(input, 5, Text.length(input))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
27
docs/language/text/text-to_int.md
Normal file
27
docs/language/text/text-to_int.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
id: text-to_int
|
||||
name: Text.to_int
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.to_int
|
||||
sig: Text.to_int(s) -> int
|
||||
tip: Parse a leading integer from a string.
|
||||
order: 9
|
||||
ns: Text
|
||||
member: to_int
|
||||
---
|
||||
|
||||
Reads an optional sign and the leading decimal digits of <code>s</code> and returns them as an <code>int</code>, stopping at the first non-digit — so <code>Text.to_int("42abc")</code> is <code>42</code>. A string with no leading number yields <code>0</code>. Use it to turn typed input, a config value, or a parsed field into a number. It is the inverse of <code>Text.from_int</code>.
|
||||
|
||||
Parameters:
|
||||
- `s` — the string to parse
|
||||
|
||||
```ludic
|
||||
program ParseAmount {
|
||||
var typed: str = "250"
|
||||
|
||||
handler Apply phase Update {
|
||||
let gold = Text.to_int(typed) # 250
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/text/text-trim.md
Normal file
22
docs/language/text/text-trim.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: text-trim
|
||||
name: Text.trim
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.trim
|
||||
sig: Text.trim(s) -> str
|
||||
tip: A copy with surrounding whitespace removed.
|
||||
order: 13
|
||||
ns: Text
|
||||
member: trim
|
||||
---
|
||||
|
||||
Returns a fresh string with leading and trailing whitespace (spaces, tabs, newlines, carriage returns) removed; inner spacing is kept. Use it to clean up typed input or a parsed field before comparing or storing it.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let name = Text.trim(raw_input)
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/text/text-upper.md
Normal file
22
docs/language/text/text-upper.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: text-upper
|
||||
name: Text.upper
|
||||
category: text
|
||||
kind: namespace-method
|
||||
tokens: Text.upper
|
||||
sig: Text.upper(s) -> str
|
||||
tip: An uppercased copy of a string.
|
||||
order: 11
|
||||
ns: Text
|
||||
member: upper
|
||||
---
|
||||
|
||||
Returns a fresh string with every ASCII letter <code>a</code>-<code>z</code> turned to uppercase; other bytes pass through unchanged. The input is left untouched. Use it to normalize input before comparing, or to shout a label. Only ASCII is transformed.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
handler Step phase Update {
|
||||
let shout = Text.upper("ready") # "READY"
|
||||
}
|
||||
}
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue