diff --git a/docs/language/builtins/fn-arg.md b/docs/language/builtins/fn-arg.md
index 62a973a2..641ad56e 100644
--- a/docs/language/builtins/fn-arg.md
+++ b/docs/language/builtins/fn-arg.md
@@ -4,7 +4,7 @@ name: arg
category: builtins
kind: builtin
tokens: arg
-sig: arg(i) -> str
+sig: arg(i) -> string
tip: The i-th command-line argument as a string.
order: 50
---
diff --git a/docs/language/builtins/fn-getenv.md b/docs/language/builtins/fn-getenv.md
index 66df9f70..8b2ede1d 100644
--- a/docs/language/builtins/fn-getenv.md
+++ b/docs/language/builtins/fn-getenv.md
@@ -4,7 +4,7 @@ name: getenv
category: builtins
kind: builtin
tokens: getenv
-sig: getenv(name) -> str
+sig: getenv(name) -> string
tip: Read an environment variable, returning empty when it is unset.
order: 23
---
diff --git a/docs/language/builtins/fn-str.md b/docs/language/builtins/fn-string.md
similarity index 66%
rename from docs/language/builtins/fn-str.md
rename to docs/language/builtins/fn-string.md
index 9009e706..274c9298 100644
--- a/docs/language/builtins/fn-str.md
+++ b/docs/language/builtins/fn-string.md
@@ -1,15 +1,15 @@
---
-id: fn-str
-name: str
+id: fn-string
+name: string
category: builtins
kind: builtin
-tokens: str
-sig: str(x) -> str
+tokens: string
+sig: string(x) -> string
tip: Convert an int, bool, or fixed value to text; a string passes through unchanged.
order: 1
---
-Converts a value to its textual form: an int, bool, or fixed becomes a string, and a value that is already a string is returned unchanged. This is what backtick `{…}` interpolation calls under the hood, so most of the time you can interpolate directly instead of calling str yourself. Reach for the explicit form when you need to store or pass around the text, or build a string in pieces. The result can be printed, drawn with Screen.draw_text, or concatenated.
+Converts a value to its textual form: an int, bool, or fixed becomes a string, and a value that is already a string is returned unchanged. This is what backtick `{…}` interpolation calls under the hood, so most of the time you can interpolate directly instead of calling string yourself. Reach for the explicit form when you need to store or pass around the text, or build a string in pieces. The result can be printed, drawn with Screen.draw_text, or concatenated.
Parameters:
- `x` — the value to convert to text
@@ -19,7 +19,7 @@ program LabelValue {
var score: int = 250
handler ReportScore phase Start {
- let label = str(score)
+ let label = string(score)
print(label)
}
}
diff --git a/docs/language/ecs/fn-world_field_id.md b/docs/language/ecs/fn-world_field_id.md
index 4a68d37b..30efc056 100644
--- a/docs/language/ecs/fn-world_field_id.md
+++ b/docs/language/ecs/fn-world_field_id.md
@@ -27,7 +27,7 @@ program ResolveField {
handler Inspect phase Update {
let position_property = world_prop_id("Position")
let column_field = world_field_id(position_property, "column")
- Screen.status(str(column_field))
+ Screen.status(string(column_field))
}
}
```
diff --git a/docs/language/ecs/fn-world_get.md b/docs/language/ecs/fn-world_get.md
index 2f52381e..c19a52b7 100644
--- a/docs/language/ecs/fn-world_get.md
+++ b/docs/language/ecs/fn-world_get.md
@@ -30,7 +30,7 @@ program ReadField {
let column_field = world_field_id(position_property, "column")
for (position) in query [Position, {Player}] {
let value = world_get(self(), position_property, column_field)
- Screen.status(str(value))
+ Screen.status(string(value))
}
}
}
diff --git a/docs/language/ecs/fn-world_model_id.md b/docs/language/ecs/fn-world_model_id.md
index c3fc3175..267ded8b 100644
--- a/docs/language/ecs/fn-world_model_id.md
+++ b/docs/language/ecs/fn-world_model_id.md
@@ -25,7 +25,7 @@ program ResolveModel {
handler Inspect phase Update {
let player_model = world_model_id("Player")
- Screen.status(str(player_model))
+ Screen.status(string(player_model))
}
}
```
diff --git a/docs/language/ecs/fn-world_prop_id.md b/docs/language/ecs/fn-world_prop_id.md
index 5b1b8afa..2634b422 100644
--- a/docs/language/ecs/fn-world_prop_id.md
+++ b/docs/language/ecs/fn-world_prop_id.md
@@ -25,7 +25,7 @@ program ResolveProperty {
handler Inspect phase Update {
let position_property = world_prop_id("Position")
- Screen.status(str(position_property))
+ Screen.status(string(position_property))
}
}
```
diff --git a/docs/language/ecs/fn-world_register_prop.md b/docs/language/ecs/fn-world_register_prop.md
index a51fb2b6..0d2c0ce1 100644
--- a/docs/language/ecs/fn-world_register_prop.md
+++ b/docs/language/ecs/fn-world_register_prop.md
@@ -23,7 +23,7 @@ program ModComponent {
handler Boot phase Start {
spawn Hero { Position { column: 4, row: 4 } }
let stamina_property = world_register_prop("Stamina", 1)
- Screen.status(str(stamina_property))
+ Screen.status(string(stamina_property))
}
}
```
diff --git a/docs/language/ecs/fn-world_save.md b/docs/language/ecs/fn-world_save.md
index 5421e5f6..2e9d4399 100644
--- a/docs/language/ecs/fn-world_save.md
+++ b/docs/language/ecs/fn-world_save.md
@@ -27,7 +27,7 @@ program SnapshotOut {
if Input.key() == 's' {
let buffer = bytes(4096)
let written = world_save(buffer)
- Screen.status(str(written))
+ Screen.status(string(written))
}
}
}
diff --git a/docs/language/ecs/fn-world_spawn.md b/docs/language/ecs/fn-world_spawn.md
index 9520bc40..f43bc931 100644
--- a/docs/language/ecs/fn-world_spawn.md
+++ b/docs/language/ecs/fn-world_spawn.md
@@ -23,7 +23,7 @@ program Reinforcements {
if Input.key() == ' ' {
let enemy_model = world_model_id("Enemy")
let new_enemy = world_spawn(enemy_model)
- Screen.status(str(new_enemy))
+ Screen.status(string(new_enemy))
}
}
}
diff --git a/docs/language/operators/op-access.md b/docs/language/operators/op-access.md
index 20a86621..a51af01e 100644
--- a/docs/language/operators/op-access.md
+++ b/docs/language/operators/op-access.md
@@ -13,5 +13,5 @@ The access operators reach into a compound value. `value.field` reads or writes
```ludic
let head_column: int = segments[0].column
segments[0].column = head_column + 1
-let extension: str = file_name[len(file_name) - 4 .. len(file_name)]
+let extension: string = file_name[len(file_name) - 4 .. len(file_name)]
```
diff --git a/docs/language/operators/op-compare.md b/docs/language/operators/op-compare.md
index f780ec00..c979fc4c 100644
--- a/docs/language/operators/op-compare.md
+++ b/docs/language/operators/op-compare.md
@@ -8,7 +8,7 @@ tip: Compare two values and yield a bool; on strings == compares contents.
order: 1
---
-The comparison operators — `==` (equal), `!=` (not equal), `<`, `<=`, `>`, `>=` — take two values and yield a `bool`, the kind of test an `if` or `where` clause wants. On `str` values `==` and `!=` compare by content, so `direction == "left"` checks the characters, not the pointer (a comparison against `null` stays a pointer test). Comparison binds looser than arithmetic and looser than the bitwise operators, so `flags & MASK == 0` reads as `(flags & MASK) == 0` with no parentheses needed. Chain several conditions together with `and` / `or`.
+The comparison operators — `==` (equal), `!=` (not equal), `<`, `<=`, `>`, `>=` — take two values and yield a `bool`, the kind of test an `if` or `where` clause wants. On `string` values `==` and `!=` compare by content, so `direction == "left"` checks the characters, not the pointer (a comparison against `null` stays a pointer test). Comparison binds looser than arithmetic and looser than the bitwise operators, so `flags & MASK == 0` reads as `(flags & MASK) == 0` with no parentheses needed. Chain several conditions together with `and` / `or`.
```ludic
if current_health <= 0 { become GameOver }
diff --git a/docs/language/operators/op-interp.md b/docs/language/operators/op-interp.md
index 17210529..df904934 100644
--- a/docs/language/operators/op-interp.md
+++ b/docs/language/operators/op-interp.md
@@ -8,10 +8,10 @@ tip: A backtick string with {expr} holes, each stringified and concatenated.
order: 7
---
-A backtick string `` `…` `` is an interpolated string: any `{expr}` hole inside it is evaluated, converted to text, and concatenated with the surrounding literal parts. Numbers, `bool`s, and `fixed` values are stringified automatically and `str` values pass through, so `` `score: {score}` `` desugars to `"score: " + str(score)`. It is the readable way to build a message from mixed pieces without hand-writing a `+` chain. Write a literal brace with `{{` or `}}`.
+A backtick string `` `…` `` is an interpolated string: any `{expr}` hole inside it is evaluated, converted to text, and concatenated with the surrounding literal parts. Numbers, `bool`s, and `fixed` values are stringified automatically and `string` values pass through, so `` `score: {score}` `` desugars to `"score: " + string(score)`. It is the readable way to build a message from mixed pieces without hand-writing a `+` chain. Write a literal brace with `{{` or `}}`.
```ludic
-let status_line: str = `score {score} — health {current_health}/{maximum_health}`
+let status_line: string = `score {score} — health {current_health}/{maximum_health}`
Screen.status(status_line)
print(`wave {wave_number} incoming`)
```
diff --git a/docs/language/operators/op-literals.md b/docs/language/operators/op-literals.md
index fe5e7297..988377ce 100644
--- a/docs/language/operators/op-literals.md
+++ b/docs/language/operators/op-literals.md
@@ -8,11 +8,11 @@ tip: Integer, hex, character, string, boolean, and null-pointer literals.
order: 8
---
-Literals are the fixed values you write directly in source. `42` is a decimal `int` and `0x1E90FF` is a hex `int` — hex is how colors are written, so a raw color is just an integer. A number with a decimal point (`1.5`) is a `fixed`. `'w'` is a character literal, an `int` code point handy for comparing against `Input.key()`. `"text"` is a `str`, `true` / `false` are `bool`s, and `null` is the null-pointer literal used to test an unset record, slice, or `ptr` field.
+Literals are the fixed values you write directly in source. `42` is a decimal `int` and `0x1E90FF` is a hex `int` — hex is how colors are written, so a raw color is just an integer. A number with a decimal point (`1.5`) is a `fixed`. `'w'` is a character literal, an `int` code point handy for comparing against `Input.key()`. `"text"` is a `string`, `true` / `false` are `bool`s, and `null` is the null-pointer literal used to test an unset record, slice, or `ptr` field.
```ludic
let sky_color: int = 0x1E90FF
-let banner: str = "GAME OVER"
+let banner: string = "GAME OVER"
if Input.key() == 'w' { row = row - 1 }
if next_segment == null { is_tail = true }
```
diff --git a/docs/language/structure/kw-extern.md b/docs/language/structure/kw-extern.md
index 8f939494..b397c60e 100644
--- a/docs/language/structure/kw-extern.md
+++ b/docs/language/structure/kw-extern.md
@@ -24,7 +24,7 @@ program Physics {
handler MeasureSpeed phase Update {
for (velocity) in query [Velocity, {Projectile}] {
let speed = c_hypot(a: fx(velocity.delta_x), b: fx(velocity.delta_y))
- Screen.status(str(flr(speed)))
+ Screen.status(string(flr(speed)))
}
}
}
diff --git a/docs/language/system/system-arg.md b/docs/language/system/system-arg.md
index 62f84b1c..8a42c59e 100644
--- a/docs/language/system/system-arg.md
+++ b/docs/language/system/system-arg.md
@@ -4,7 +4,7 @@ name: System.arg
category: system
kind: namespace-method
tokens: System.arg
-sig: System.arg(i) -> str
+sig: System.arg(i) -> string
tip: A command-line argument by index.
order: 0
ns: System
diff --git a/docs/language/system/system-env.md b/docs/language/system/system-env.md
index 8af87a19..a4bcdbe7 100644
--- a/docs/language/system/system-env.md
+++ b/docs/language/system/system-env.md
@@ -4,7 +4,7 @@ name: System.env
category: system
kind: namespace-method
tokens: System.env
-sig: System.env(name) -> str
+sig: System.env(name) -> string
tip: Read an environment variable.
order: 4
ns: System
diff --git a/docs/language/text/_section.md b/docs/language/text/_section.md
index 70bd8bf6..5cbb9f7f 100644
--- a/docs/language/text/_section.md
+++ b/docs/language/text/_section.md
@@ -4,4 +4,4 @@ title: Text
order: 6
---
-String queries and building over str 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.
+String queries and building over string 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.
diff --git a/docs/language/text/text-char_at.md b/docs/language/text/text-char_at.md
index 73796a0b..c5bfe53b 100644
--- a/docs/language/text/text-char_at.md
+++ b/docs/language/text/text-char_at.md
@@ -19,7 +19,7 @@ Parameters:
```ludic
program FirstIsDigit {
- var entry: str = "7up"
+ var entry: string = "7up"
handler Check phase Update {
let c = Text.char_at(entry, 0)
diff --git a/docs/language/text/text-concat.md b/docs/language/text/text-concat.md
index ceecedcf..92be1bde 100644
--- a/docs/language/text/text-concat.md
+++ b/docs/language/text/text-concat.md
@@ -4,7 +4,7 @@ name: Text.concat
category: text
kind: namespace-method
tokens: Text.concat
-sig: Text.concat(a, b) -> str
+sig: Text.concat(a, b) -> string
tip: Join two strings into a new one.
order: 8
ns: Text
@@ -19,7 +19,7 @@ Parameters:
```ludic
program Greeting {
- var name: str = "world"
+ var name: string = "world"
handler Build phase Update {
let line = Text.concat("hello ", name) # "hello world"
diff --git a/docs/language/text/text-contains.md b/docs/language/text/text-contains.md
index ea272d28..b71732ff 100644
--- a/docs/language/text/text-contains.md
+++ b/docs/language/text/text-contains.md
@@ -19,7 +19,7 @@ Parameters:
```ludic
program Filter {
- var line: str = "error: disk full"
+ var line: string = "error: disk full"
handler Scan phase Update {
if Text.contains(line, "error") {
diff --git a/docs/language/text/text-ends_with.md b/docs/language/text/text-ends_with.md
index de29002d..b1c4ed90 100644
--- a/docs/language/text/text-ends_with.md
+++ b/docs/language/text/text-ends_with.md
@@ -19,7 +19,7 @@ Parameters:
```ludic
program IsImage {
- var filename: str = "hero.png"
+ var filename: string = "hero.png"
handler Classify phase Update {
let png = Text.ends_with(filename, ".png") # true
diff --git a/docs/language/text/text-equals.md b/docs/language/text/text-equals.md
index 5ac25126..1acdb6e4 100644
--- a/docs/language/text/text-equals.md
+++ b/docs/language/text/text-equals.md
@@ -19,8 +19,8 @@ Parameters:
```ludic
program Guess {
- var answer: str = "swordfish"
- var attempt: str = "swordfish"
+ var answer: string = "swordfish"
+ var attempt: string = "swordfish"
handler Check phase Update {
if Text.equals(attempt, answer) {
diff --git a/docs/language/text/text-from_int.md b/docs/language/text/text-from_int.md
index cdde41ba..8aaa12eb 100644
--- a/docs/language/text/text-from_int.md
+++ b/docs/language/text/text-from_int.md
@@ -4,14 +4,14 @@ name: Text.from_int
category: text
kind: namespace-method
tokens: Text.from_int
-sig: Text.from_int(n) -> str
+sig: Text.from_int(n) -> string
tip: Render an integer as a string.
order: 10
ns: Text
member: from_int
---
-Returns the decimal text of the integer n — Text.from_int(1234) is "1234", and negatives keep their sign. It is the same conversion as the bare str(n) and the inverse of Text.to_int. 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 Screen.draw_number.
+Returns the decimal text of the integer n — Text.from_int(1234) is "1234", and negatives keep their sign. It is the same conversion as the bare string(n) and the inverse of Text.to_int. 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 Screen.draw_number.
Parameters:
- `n` — the integer to render
diff --git a/docs/language/text/text-index_of.md b/docs/language/text/text-index_of.md
index 9c1e6bb7..9eb5d5c4 100644
--- a/docs/language/text/text-index_of.md
+++ b/docs/language/text/text-index_of.md
@@ -19,7 +19,7 @@ Parameters:
```ludic
program KeyValue {
- var pair: str = "hp=42"
+ var pair: string = "hp=42"
handler Parse phase Update {
let eq = Text.index_of(pair, "=") # 2
diff --git a/docs/language/text/text-join.md b/docs/language/text/text-join.md
index 7c9e88a0..3c44610a 100644
--- a/docs/language/text/text-join.md
+++ b/docs/language/text/text-join.md
@@ -4,7 +4,7 @@ name: Text.join
category: text
kind: namespace-method
tokens: Text.join
-sig: Text.join(parts, sep) -> str
+sig: Text.join(parts, sep) -> string
tip: Join a list of strings with a separator.
order: 18
ns: Text
diff --git a/docs/language/text/text-length.md b/docs/language/text/text-length.md
index 07e8653c..ec8ebb55 100644
--- a/docs/language/text/text-length.md
+++ b/docs/language/text/text-length.md
@@ -18,7 +18,7 @@ Parameters:
```ludic
program NameWidth {
- var label: str = "player one"
+ var label: string = "player one"
handler Draw phase Render {
let width = Text.length(label) * 6 # 6 px per glyph
diff --git a/docs/language/text/text-lower.md b/docs/language/text/text-lower.md
index faff1e4c..eceaf897 100644
--- a/docs/language/text/text-lower.md
+++ b/docs/language/text/text-lower.md
@@ -4,7 +4,7 @@ name: Text.lower
category: text
kind: namespace-method
tokens: Text.lower
-sig: Text.lower(s) -> str
+sig: Text.lower(s) -> string
tip: A lowercased copy of a string.
order: 12
ns: Text
diff --git a/docs/language/text/text-pad_left.md b/docs/language/text/text-pad_left.md
index 8e6dbb31..f2f595b6 100644
--- a/docs/language/text/text-pad_left.md
+++ b/docs/language/text/text-pad_left.md
@@ -4,7 +4,7 @@ name: Text.pad_left
category: text
kind: namespace-method
tokens: Text.pad_left
-sig: Text.pad_left(s, width) -> str
+sig: Text.pad_left(s, width) -> string
tip: Pad with spaces on the left to a width.
order: 15
ns: Text
diff --git a/docs/language/text/text-pad_right.md b/docs/language/text/text-pad_right.md
index 38ed6b51..60e7482e 100644
--- a/docs/language/text/text-pad_right.md
+++ b/docs/language/text/text-pad_right.md
@@ -4,7 +4,7 @@ name: Text.pad_right
category: text
kind: namespace-method
tokens: Text.pad_right
-sig: Text.pad_right(s, width) -> str
+sig: Text.pad_right(s, width) -> string
tip: Pad with spaces on the right to a width.
order: 16
ns: Text
diff --git a/docs/language/text/text-repeat.md b/docs/language/text/text-repeat.md
index 6909b0f6..32cedb1b 100644
--- a/docs/language/text/text-repeat.md
+++ b/docs/language/text/text-repeat.md
@@ -4,7 +4,7 @@ name: Text.repeat
category: text
kind: namespace-method
tokens: Text.repeat
-sig: Text.repeat(s, n) -> str
+sig: Text.repeat(s, n) -> string
tip: A string repeated n times.
order: 14
ns: Text
diff --git a/docs/language/text/text-replace.md b/docs/language/text/text-replace.md
index c454d67c..63bdcb6a 100644
--- a/docs/language/text/text-replace.md
+++ b/docs/language/text/text-replace.md
@@ -4,7 +4,7 @@ name: Text.replace
category: text
kind: namespace-method
tokens: Text.replace
-sig: Text.replace(s, from, to) -> str
+sig: Text.replace(s, from, to) -> string
tip: Replace every occurrence of a substring.
order: 19
ns: Text
diff --git a/docs/language/text/text-slice.md b/docs/language/text/text-slice.md
index d8f3b182..1f4529ef 100644
--- a/docs/language/text/text-slice.md
+++ b/docs/language/text/text-slice.md
@@ -4,7 +4,7 @@ name: Text.slice
category: text
kind: namespace-method
tokens: Text.slice
-sig: Text.slice(s, a, b) -> str
+sig: Text.slice(s, a, b) -> string
tip: A substring covering bytes [a, b).
order: 2
ns: Text
@@ -20,7 +20,7 @@ Parameters:
```ludic
program FirstWord {
- var line: str = "hello world"
+ var line: string = "hello world"
handler Split phase Update {
let space = Text.index_of(line, " ") # 5
diff --git a/docs/language/text/text-split.md b/docs/language/text/text-split.md
index 4b7893df..54685ff2 100644
--- a/docs/language/text/text-split.md
+++ b/docs/language/text/text-split.md
@@ -4,14 +4,14 @@ name: Text.split
category: text
kind: namespace-method
tokens: Text.split
-sig: Text.split(s, sep) -> []str
+sig: Text.split(s, sep) -> []string
tip: Split a string on a separator into a list.
order: 17
ns: Text
member: split
---
-Splits s at every occurrence of the non-empty separator sep and returns the pieces as a []str — the inverse of Text.join. 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.
+Splits s at every occurrence of the non-empty separator sep and returns the pieces as a []string — the inverse of Text.join. 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 {
diff --git a/docs/language/text/text-starts_with.md b/docs/language/text/text-starts_with.md
index d371e12f..e9aa0a05 100644
--- a/docs/language/text/text-starts_with.md
+++ b/docs/language/text/text-starts_with.md
@@ -19,7 +19,7 @@ Parameters:
```ludic
program Command {
- var input: str = "/say hello"
+ var input: string = "/say hello"
handler Parse phase Update {
if Text.starts_with(input, "/say ") {
diff --git a/docs/language/text/text-to_int.md b/docs/language/text/text-to_int.md
index 1d300c93..fc52b6c1 100644
--- a/docs/language/text/text-to_int.md
+++ b/docs/language/text/text-to_int.md
@@ -18,7 +18,7 @@ Parameters:
```ludic
program ParseAmount {
- var typed: str = "250"
+ var typed: string = "250"
handler Apply phase Update {
let gold = Text.to_int(typed) # 250
diff --git a/docs/language/text/text-trim.md b/docs/language/text/text-trim.md
index fe5edb7d..057f42bb 100644
--- a/docs/language/text/text-trim.md
+++ b/docs/language/text/text-trim.md
@@ -4,7 +4,7 @@ name: Text.trim
category: text
kind: namespace-method
tokens: Text.trim
-sig: Text.trim(s) -> str
+sig: Text.trim(s) -> string
tip: A copy with surrounding whitespace removed.
order: 13
ns: Text
diff --git a/docs/language/text/text-upper.md b/docs/language/text/text-upper.md
index ccf0a911..d2277ef7 100644
--- a/docs/language/text/text-upper.md
+++ b/docs/language/text/text-upper.md
@@ -4,7 +4,7 @@ name: Text.upper
category: text
kind: namespace-method
tokens: Text.upper
-sig: Text.upper(s) -> str
+sig: Text.upper(s) -> string
tip: An uppercased copy of a string.
order: 11
ns: Text
diff --git a/docs/language/types/type-long.md b/docs/language/types/type-long.md
index 35ba3a8b..e7dbdb58 100644
--- a/docs/language/types/type-long.md
+++ b/docs/language/types/type-long.md
@@ -9,7 +9,7 @@ tip: A 64-bit signed integer for values that overflow a 32-bit int.
order: 1
---
-`long` is a 64-bit signed integer — reach for it when a value would overflow the 32-bit `int`: a 64-bit hash or content id, an accumulated playtime in milliseconds, a large score or currency total, packed bit flags. Arithmetic (`+ - * / %`), comparison, and the bitwise operators all work on it, and mixing an `int` with a `long` promotes the `int` to 64 bits automatically — so `big * count` where `big` is a `long` computes in 64 bits and does not overflow. `print` and `str` render all its digits.
+`long` is a 64-bit signed integer — reach for it when a value would overflow the 32-bit `int`: a 64-bit hash or content id, an accumulated playtime in milliseconds, a large score or currency total, packed bit flags. Arithmetic (`+ - * / %`), comparison, and the bitwise operators all work on it, and mixing an `int` with a `long` promotes the `int` to 64 bits automatically — so `big * count` where `big` is a `long` computes in 64 bits and does not overflow. `print` and `string` render all its digits.
One limit to know: a numeric *literal* is still parsed as a 32-bit `int`, so build large values by widening — assign a smaller literal into a `long` and compute from there (`let m: long = 1000000` then `m * m`) rather than writing a 10-digit literal directly.
diff --git a/docs/language/types/type-str.md b/docs/language/types/type-str.md
deleted file mode 100644
index fe950cd8..00000000
--- a/docs/language/types/type-str.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-id: type-str
-name: str
-category: types
-kind: type
-tokens: str
-sig: str
-tip: An immutable string — compared by content, sliceable, and interpolatable.
-order: 3
----
-
-`str` is an immutable string of bytes. Strings are true values: `+` concatenates two of them and `==` / `!=` compare them by content, not by pointer, so `"go" + direction == "goleft"` behaves as written. Index a single byte with `text[index]` (an `int` code point), take a fresh substring with `text[start..end]`, and measure the byte length with `len(text)`. The readable way to build one is backtick interpolation — `` `score: {score}` `` — which stringifies each `{…}` hole and concatenates.
-
-```ludic
-let player_name: str = "Ada"
-let greeting: str = `hello {player_name}, score {score}`
-if player_name == "Ada" { Screen.status(greeting) }
-```
diff --git a/docs/language/types/type-string.md b/docs/language/types/type-string.md
new file mode 100644
index 00000000..a580861b
--- /dev/null
+++ b/docs/language/types/type-string.md
@@ -0,0 +1,18 @@
+---
+id: type-string
+name: string
+category: types
+kind: type
+tokens: string
+sig: string
+tip: An immutable string — compared by content, sliceable, and interpolatable.
+order: 3
+---
+
+`string` is an immutable string of bytes. Strings are true values: `+` concatenates two of them and `==` / `!=` compare them by content, not by pointer, so `"go" + direction == "goleft"` behaves as written. Index a single byte with `text[index]` (an `int` code point), take a fresh substring with `text[start..end]`, and measure the byte length with `len(text)`. The readable way to build one is backtick interpolation — `` `score: {score}` `` — which stringifies each `{…}` hole and concatenates.
+
+```ludic
+let player_name: string = "Ada"
+let greeting: string = `hello {player_name}, score {score}`
+if player_name == "Ada" { Screen.status(greeting) }
+```
diff --git a/examples/chronorift/rules.ludic b/examples/chronorift/rules.ludic
index 96d242de..685409b8 100644
--- a/examples/chronorift/rules.ludic
+++ b/examples/chronorift/rules.ludic
@@ -16,7 +16,7 @@ function walkable(x: int, y: int) -> bool {
return c == '.' or c == 'D' or c == 'r' or c == ',' or c == 'S' or c == 'B' or c == 'h'
}
function is_confirm(k: int) -> bool { return k == 32 or k == 10 or k == 13 }
-function enemy_name(et: int) -> str {
+function enemy_name(et: int) -> string {
if et == 0 { return "SLIME" }
if et == 1 { return "SKELETON" }
return "RIFT WARDEN"
diff --git a/runtime/native/core.ludic b/runtime/native/core.ludic
index a5a48e77..fa458800 100644
--- a/runtime/native/core.ludic
+++ b/runtime/native/core.ludic
@@ -29,7 +29,7 @@ var rt_alive: int = 1 # platform still running?
# 5x7 glyphs for ASCII 32..90, 7 rows per glyph, each row a 5-bit mask stored
# biased by '0' so the whole font is one printable string literal.
-function rt_font() -> str {
+function rt_font() -> string {
return "00000004444404000000000000000000000IJ4:FC000000000000000000000000000000E>O>E0044O4400000448000O000000004012448@@>ACEIA>4<4444>>A168@ON11>11N26:BO22O@N11A>>@@NAA>O124888>AA>AA>>AA?11>04004000000000024842000O0O000842480>A164040000000>AAOAAANAANAAN>A@@@A>LBAAABLO@@L@@OO@@L@@@>A@GAA>AAAOAAA>44444>7222BBAAAAA>NAAN@@@>AAAEB=NAANDBA>A@>1A>O444444AAAAAA>AAAAA:4AAAEEKAAA:4:AAAA:4444O1248@O"
}
@@ -203,7 +203,7 @@ function rt_glyph(x: int, y: int, ch: int, colour: int, sc: int) -> void {
}
}
-function rt_text(x: int, y: int, s: str, colour: int, sc: int) -> void {
+function rt_text(x: int, y: int, s: string, colour: int, sc: int) -> void {
var i = 0
var cx = x
var ch = s[0]
@@ -329,7 +329,7 @@ function rt_running() -> bool {
}
# ---- writing the frame out ------------------------------------------------
-function rt_put_str(buf: ptr, at: int, s: str) -> int {
+function rt_put_str(buf: ptr, at: int, s: string) -> int {
var i = 0
var n = at
var ch = s[0]
@@ -367,7 +367,7 @@ function rt_put_int(buf: ptr, at: int, v: int) -> int {
return n
}
-function rt_dump_ppm(path: str) -> void {
+function rt_dump_ppm(path: string) -> void {
let f = file_open(path, "wb")
if (f == null) { return }
@@ -412,7 +412,7 @@ function rt_map_size(w: int, h: int) -> void {
fill(rt_map, 32, 96 * 64)
}
-function rt_map_row(y: int, s: str) -> void {
+function rt_map_row(y: int, s: string) -> void {
if y < 0 { return }
if y >= 64 { return }
var x = 0
@@ -438,7 +438,7 @@ function rt_tile(x: int, y: int) -> int {
# so it survives whatever the caller does with the original.
var rt_statusbuf: ptr = null
-function rt_status(s: str) -> void {
+function rt_status(s: string) -> void {
var i = 0
var ch = s[0]
while ch != 0 {
diff --git a/runtime/native/image.ludic b/runtime/native/image.ludic
index 5d8a1ecf..16360f28 100644
--- a/runtime/native/image.ludic
+++ b/runtime/native/image.ludic
@@ -42,7 +42,7 @@ function png_tag(b: ptr, at: int, a: int, c: int, d: int, e: int) -> bool {
return true
}
-function rt_read_file(path: str) -> ptr {
+function rt_read_file(path: string) -> ptr {
let f = file_open(path, "rb")
if (f == null) { return null }
file_seek(f, 0, 2)
@@ -62,7 +62,7 @@ var png_w: int = 0
var png_h: int = 0
var png_px: words = null
-function rt_decode_png(path: str) -> bool {
+function rt_decode_png(path: string) -> bool {
png_w = 0
png_h = 0
png_px = null
@@ -227,7 +227,7 @@ function rt_decode_png(path: str) -> bool {
}
# ---- images ---------------------------------------------------------------
-function rt_image_load(path: str) -> int {
+function rt_image_load(path: string) -> int {
if img_n >= IMG_MAX { return 0 - 1 }
if rt_decode_png(path) == false { return 0 - 1 }
let id = img_n
@@ -315,7 +315,7 @@ function rt_draw_9slice(id: int, dx: int, dy: int, dw: int, dh: int, inset: int)
}
# ---- sprites (16x16 art) --------------------------------------------------
-function rt_png_load(path: str) -> int {
+function rt_png_load(path: string) -> int {
if spr_n >= SPR_MAX { return 0 - 1 }
if rt_decode_png(path) == false { return 0 - 1 }
let id = spr_n
@@ -375,7 +375,7 @@ function rt_hexval(c: int) -> int {
return 0 - 1
}
-function rt_sprites_load(path: str) -> void {
+function rt_sprites_load(path: string) -> void {
let d = rt_read_file(path)
if (d == null) { spr_n = 0; return }
let size = rt_file_len
diff --git a/runtime/native/truetype.ludic b/runtime/native/truetype.ludic
index bbacc74f..2655d053 100644
--- a/runtime/native/truetype.ludic
+++ b/runtime/native/truetype.ludic
@@ -166,7 +166,7 @@ function tt_pick_cmap(id: int, d: ptr, co: int) -> void {
tt_cfmt[id] = tt_u16(d, best)
}
-function rt_font_load(path: str) -> int {
+function rt_font_load(path: string) -> int {
if tt_n >= TT_MAX { return 0 - 1 }
let d = rt_read_file(path)
if (d == null) { return 0 - 1 }
diff --git a/runtime/native/truetype_raster.ludic b/runtime/native/truetype_raster.ludic
index d85b053b..74237ea6 100644
--- a/runtime/native/truetype_raster.ludic
+++ b/runtime/native/truetype_raster.ludic
@@ -269,7 +269,7 @@ function tt_glyph_get(font: int, cp: int, px: int) -> int {
# ---- UTF-8 ----------------------------------------------------------------
var u8_next: int = 0 # byte index just past the codepoint last decoded
-function tt_utf8(s: str, at: int) -> int {
+function tt_utf8(s: string, at: int) -> int {
let c = s[at]
var extra = 0 - 1
if c < 128 { extra = 0 }
@@ -327,7 +327,7 @@ function tt_blit(bmp: ptr, w: int, h: int, dx: int, dy: int, colour: int) -> voi
}
}
-function rt_text_ttf(font: int, x: int, y: int, s: str, colour: int, px: int) -> void {
+function rt_text_ttf(font: int, x: int, y: int, s: string, colour: int, px: int) -> void {
if font < 0 { return }
if font >= tt_n { return }
if px <= 0 { return }
@@ -351,7 +351,7 @@ function rt_text_ttf(font: int, x: int, y: int, s: str, colour: int, px: int) ->
}
}
-function rt_text_w(font: int, s: str, px: int) -> int {
+function rt_text_w(font: int, s: string, px: int) -> int {
if font < 0 { return 0 }
if font >= tt_n { return 0 }
if px <= 0 { return 0 }
diff --git a/runtime/native/ui.ludic b/runtime/native/ui.ludic
index 7e26a09b..27bbc18f 100644
--- a/runtime/native/ui.ludic
+++ b/runtime/native/ui.ludic
@@ -168,7 +168,7 @@ function rt_ui_set(i: int, k: int, v: int) -> void {
if k == K_SKIN { ui_skin[i] = v }
}
-function rt_ui_static_text(i: int, s: str) -> void {
+function rt_ui_static_text(i: int, s: string) -> void {
if i < 0 { return }
if i >= UI_MAX { return }
ui_text[i] = s
diff --git a/runtime/native/ui_draw.ludic b/runtime/native/ui_draw.ludic
index 0ab6f837..1c3be23d 100644
--- a/runtime/native/ui_draw.ludic
+++ b/runtime/native/ui_draw.ludic
@@ -214,7 +214,7 @@ function rt_ui_clicked(id: int) -> bool {
return ui_fired[id] == 1
}
-function rt_ui_set_text(id: int, s: str) -> void {
+function rt_ui_set_text(id: int, s: string) -> void {
if id < 0 { return }
if id >= ui_n { return }
let base = id * 96
diff --git a/selfhost/emit_core.ludic b/selfhost/emit_core.ludic
index 6972db43..bf1ae345 100644
--- a/selfhost/emit_core.ludic
+++ b/selfhost/emit_core.ludic
@@ -19,13 +19,13 @@ var loc_ty: []ptr
var loc_mut: []int # 1 = mutable (var / param / loop-var), 0 = immutable (let)
var nloc: int = 0
var g_uses_str: bool = false # a `str + str` / `str == str` was emitted -> emit the prelude
-var g_uses_intstr: bool = false # `str(int)` was emitted -> emit the int->string prelude
+var g_uses_intstr: bool = false # `string(int)` was emitted -> emit the int->string prelude
var g_uses_strslice: bool = false # `s[a..b]` was emitted -> emit the substring prelude
var g_uses_mathrt: bool = false # Math.sqrt/sin/cos/tan was emitted -> emit the math runtime prelude
var g_uses_textrt: bool = false # Text.upper/lower/trim/repeat/pad was emitted -> emit the text builders
var g_uses_textrt2: bool = false # Text.split/join/replace was emitted -> emit the string/slice builders
var g_uses_hashrt: bool = false # Hash.of/fnv1a/crc32 was emitted -> emit the byte-stream hashers
-var g_uses_longstr: bool = false # str(long) / interpolating a long was emitted -> emit fn_long_str
+var g_uses_longstr: bool = false # string(long) / interpolating a long was emitted -> emit fn_long_str
# loop targets for break/continue (innermost last)
var brk_lbl: []ptr
diff --git a/selfhost/emit_decl.ludic b/selfhost/emit_decl.ludic
index f07d9be6..3d4263e1 100644
--- a/selfhost/emit_decl.ludic
+++ b/selfhost/emit_decl.ludic
@@ -97,8 +97,8 @@ function emit_program() -> void {
} }
if g_uses_loopback { emit_loopback() } # built-in transport, after all net_send/net_poll uses are seen
if g_uses_str { emit_str_prelude() } # @fn_str_eq / @fn_str_concat, after all uses are seen
- if g_uses_intstr { emit_int_str() } # @fn_int_str, for str(int) in interpolation
- if g_uses_longstr { emit_long_str() } # @fn_long_str, for str(long) / long interpolation
+ if g_uses_intstr { emit_int_str() } # @fn_int_str, for string(int) in interpolation
+ if g_uses_longstr { emit_long_str() } # @fn_long_str, for string(long) / long interpolation
if g_uses_strslice { emit_str_slice() } # @fn_str_slice, for s[a..b]
if g_uses_mathrt { emit_math_prelude() } # @fn_fx_sqrt / @fn_fx_sin + the sine table
if g_uses_textrt { emit_text_prelude() } # @fn_str_upper/lower/trim/repeat/pad builders
diff --git a/selfhost/emit_expr.ludic b/selfhost/emit_expr.ludic
index b3a29156..e17815ed 100644
--- a/selfhost/emit_expr.ludic
+++ b/selfhost/emit_expr.ludic
@@ -79,7 +79,7 @@ function to_long(v: Val) -> ptr {
function emit_str_op(op: ptr, a: Val, b: Val) -> Val {
g_uses_str = true
if (op == ("+")) {
- return val(emit_bind(`call ptr @fn_str_concat(ptr {a.code}, ptr {b.code})`), "str")
+ return val(emit_bind(`call ptr @fn_str_concat(ptr {a.code}, ptr {b.code})`), "string")
}
let r = emit_bind(`call i32 @fn_str_eq(ptr {a.code}, ptr {b.code})`)
if (op == ("!=")) {
@@ -411,12 +411,12 @@ function emit_call(e: Node) -> Val {
}
if (name == "len") { return emit_len(e) }
if (name == "push") { return emit_push(e) }
- if (name == "str") { # str(x): int/bool/fixed/long -> text, a string passes through
+ if (name == "string") { # string(x): int/bool/fixed/long -> text, a string passes through
let a = emit_expr(e.kids[0])
if (llty(a.ty) == "ptr") { return a }
- if (llty(a.ty) == "i64") { g_uses_longstr = true; return val(emit_bind(`call ptr @fn_long_str(i64 {a.code})`), "str") }
+ if (llty(a.ty) == "i64") { g_uses_longstr = true; return val(emit_bind(`call ptr @fn_long_str(i64 {a.code})`), "string") }
g_uses_intstr = true
- return val(emit_bind(`call ptr @fn_int_str(i32 {a.code})`), "str")
+ return val(emit_bind(`call ptr @fn_int_str(i32 {a.code})`), "string")
}
if (name == "print") { # print(x): a value + newline (string, long, or int)
let a = emit_expr(e.kids[0])
@@ -536,9 +536,9 @@ function emit_expr(e: Node) -> Val {
let lo = emit_expr(e.b)
let hi = emit_expr(e.c)
g_uses_strslice = true
- return val(emit_bind(`call ptr @fn_str_slice(ptr {base.code}, i32 {lo.code}, i32 {hi.code})`), "str")
+ return val(emit_bind(`call ptr @fn_str_slice(ptr {base.code}, i32 {lo.code}, i32 {hi.code})`), "string")
}
- if e.kind == E_STR { return val(emit_str_const(e.s), "str") }
+ if e.kind == E_STR { return val(emit_str_const(e.s), "string") }
if e.kind == E_NEW {
if is_slice_ty(e.s) { return emit_new_slice(e.s) }
return emit_new_struct(e.s)
diff --git a/selfhost/emit_head.ludic b/selfhost/emit_head.ludic
index 94c6c8d6..fdc9d787 100644
--- a/selfhost/emit_head.ludic
+++ b/selfhost/emit_head.ludic
@@ -170,7 +170,7 @@ function emit_str_prelude() -> void {
emith("fin:\n %pe = getelementptr inbounds i8, ptr %out, i32 %sum\n store i8 0, ptr %pe\n ret ptr %out\n}\n")
}
-# int -> decimal string, emitted (once) into any program that uses str(int)
+# int -> decimal string, emitted (once) into any program that uses string(int)
# (string interpolation of a number). Writes digits from the end of a 24-byte
# buffer, prepends '-' for negatives, and returns a pointer into the buffer.
function emit_int_str() -> void {
diff --git a/selfhost/emit_intrin.ludic b/selfhost/emit_intrin.ludic
index dc7695ef..d50d845e 100644
--- a/selfhost/emit_intrin.ludic
+++ b/selfhost/emit_intrin.ludic
@@ -62,7 +62,7 @@ function emit_intrinsic(name: ptr, e: Node) -> Val {
let i = arg_code(e, 0)
let v = emit_bind("load ptr, ptr @L_argv")
let q = emit_bind(`getelementptr ptr, ptr {v}, i32 {i}`)
- return val(emit_bind(`load ptr, ptr {q}`), "str")
+ return val(emit_bind(`load ptr, ptr {q}`), "string")
}
if (name == "exit") {
let n = arg_code(e, 0)
@@ -79,7 +79,7 @@ function emit_intrinsic(name: ptr, e: Node) -> Val {
}
if (name == "getenv") {
let n = arg_code(e, 0)
- return val(emit_bind(`call ptr @getenv(ptr {n})`), "str")
+ return val(emit_bind(`call ptr @getenv(ptr {n})`), "string")
}
# bitwise ops are the operators & | ^ << >> ~ now (see emit_bin / p_mul).
# peek32 / poke32 are `words` indexing now: w[i] and w[i] = v (see emit_index_addr).
diff --git a/selfhost/emit_intrin2.ludic b/selfhost/emit_intrin2.ludic
index 900866c2..1151f6d6 100644
--- a/selfhost/emit_intrin2.ludic
+++ b/selfhost/emit_intrin2.ludic
@@ -34,7 +34,7 @@ function emit_intrinsic2(name: ptr, e: Node) -> Val {
if (name == "as_fixed") { let a = emit_expr(e.kids[0]); return val(a.code, "fixed") }
if (name == "as_int") { let a = emit_expr(e.kids[0]); return val(a.code, "int") }
if (name == "is_windowed") { if g_windowed { return val("1", "bool") }; return val("0", "bool") }
- if (name == "game_title") { return val("@.gametitle", "str") }
+ if (name == "game_title") { return val("@.gametitle", "string") }
# windowing hooks — declared external; only reached on the is_windowed() branch
if (name == "win_poll") { return val(emit_bind("call i32 @win_poll()"), "int") }
if (name == "win_running") { return val(emit_bind("call i32 @win_running()"), "bool") }
diff --git a/selfhost/emit_text.ludic b/selfhost/emit_text.ludic
index e43129c4..0bf8f707 100644
--- a/selfhost/emit_text.ludic
+++ b/selfhost/emit_text.ludic
@@ -1,7 +1,7 @@
# emit_text.ludic — the Text.* namespace over `str` (null-terminated byte
# strings). The libc-backed queries (length/char_at/starts_with/ends_with/
# contains/index_of/to_int) allocate nothing; slice/from_int/equals/concat reuse
-# the string preludes that the `+`, `s[a..b]` and str(int) operators emit.
+# the string preludes that the `+`, `s[a..b]` and string(int) operators emit.
function is_text_ns(meth: ptr) -> bool {
if (meth == "length") or (meth == "char_at") or (meth == "slice") { return true }
@@ -15,15 +15,15 @@ function is_text_ns(meth: ptr) -> bool {
}
function emit_text_ns(meth: ptr, e: Node) -> Val {
- if (meth == "from_int") { # int -> str, same as str(n)
+ if (meth == "from_int") { # int -> string, same as string(n)
let n = emit_expr(e.kids[0])
g_uses_intstr = true
- return val(emit_bind(`call ptr @fn_int_str(i32 {n.code})`), "str")
+ return val(emit_bind(`call ptr @fn_int_str(i32 {n.code})`), "string")
}
if (meth == "slice") { # s[a..b], same substring helper
let s0 = emit_expr(e.kids[0]); let a = emit_expr(e.kids[1]); let b = emit_expr(e.kids[2])
g_uses_strslice = true
- return val(emit_bind(`call ptr @fn_str_slice(ptr {s0.code}, i32 {a.code}, i32 {b.code})`), "str")
+ return val(emit_bind(`call ptr @fn_str_slice(ptr {s0.code}, i32 {a.code}, i32 {b.code})`), "string")
}
if (meth == "equals") { # byte-wise equality, same as ==
let a = emit_expr(e.kids[0]); let b = emit_expr(e.kids[1])
@@ -33,7 +33,7 @@ function emit_text_ns(meth: ptr, e: Node) -> Val {
if (meth == "concat") { # a + b, same as the + operator
let a = emit_expr(e.kids[0]); let b = emit_expr(e.kids[1])
g_uses_str = true
- return val(emit_bind(`call ptr @fn_str_concat(ptr {a.code}, ptr {b.code})`), "str")
+ return val(emit_bind(`call ptr @fn_str_concat(ptr {a.code}, ptr {b.code})`), "string")
}
let s = emit_expr(e.kids[0])
@@ -52,45 +52,45 @@ function emit_text_ns(meth: ptr, e: Node) -> Val {
}
if (meth == "upper") { # ASCII a-z -> A-Z, fresh string
g_uses_textrt = true
- return val(emit_bind(`call ptr @fn_str_upper(ptr {s.code})`), "str")
+ return val(emit_bind(`call ptr @fn_str_upper(ptr {s.code})`), "string")
}
if (meth == "lower") { # ASCII A-Z -> a-z, fresh string
g_uses_textrt = true
- return val(emit_bind(`call ptr @fn_str_lower(ptr {s.code})`), "str")
+ return val(emit_bind(`call ptr @fn_str_lower(ptr {s.code})`), "string")
}
if (meth == "trim") { # drop leading/trailing whitespace
g_uses_textrt = true
- return val(emit_bind(`call ptr @fn_str_trim(ptr {s.code})`), "str")
+ return val(emit_bind(`call ptr @fn_str_trim(ptr {s.code})`), "string")
}
if (meth == "repeat") { # s repeated n times
g_uses_textrt = true
let n = emit_expr(e.kids[1])
- return val(emit_bind(`call ptr @fn_str_repeat(ptr {s.code}, i32 {n.code})`), "str")
+ return val(emit_bind(`call ptr @fn_str_repeat(ptr {s.code}, i32 {n.code})`), "string")
}
if (meth == "pad_left") { # pad with spaces to width, on the left
g_uses_textrt = true
let w = emit_expr(e.kids[1])
- return val(emit_bind(`call ptr @fn_str_pad(ptr {s.code}, i32 {w.code}, i1 1)`), "str")
+ return val(emit_bind(`call ptr @fn_str_pad(ptr {s.code}, i32 {w.code}, i1 1)`), "string")
}
if (meth == "pad_right") { # pad with spaces to width, on the right
g_uses_textrt = true
let w = emit_expr(e.kids[1])
- return val(emit_bind(`call ptr @fn_str_pad(ptr {s.code}, i32 {w.code}, i1 0)`), "str")
+ return val(emit_bind(`call ptr @fn_str_pad(ptr {s.code}, i32 {w.code}, i1 0)`), "string")
}
if (meth == "replace") { # replace every `from` with `to`
g_uses_textrt2 = true
let from = emit_expr(e.kids[1]); let to = emit_expr(e.kids[2])
- return val(emit_bind(`call ptr @fn_str_replace(ptr {s.code}, ptr {from.code}, ptr {to.code})`), "str")
+ return val(emit_bind(`call ptr @fn_str_replace(ptr {s.code}, ptr {from.code}, ptr {to.code})`), "string")
}
- if (meth == "split") { # split on a separator -> []str
+ if (meth == "split") { # split on a separator -> []string
g_uses_textrt2 = true
let sep = emit_expr(e.kids[1])
- return val(emit_bind(`call ptr @fn_str_split(ptr {s.code}, ptr {sep.code})`), "[]str")
+ return val(emit_bind(`call ptr @fn_str_split(ptr {s.code}, ptr {sep.code})`), "[]string")
}
- if (meth == "join") { # join a []str with a separator (s is the slice)
+ if (meth == "join") { # join a []string with a separator (s is the slice)
g_uses_textrt2 = true
let sep = emit_expr(e.kids[1])
- return val(emit_bind(`call ptr @fn_str_join(ptr {s.code}, ptr {sep.code})`), "str")
+ return val(emit_bind(`call ptr @fn_str_join(ptr {s.code}, ptr {sep.code})`), "string")
}
if (meth == "contains") or (meth == "index_of") { # substring search
let sub = emit_expr(e.kids[1])
@@ -340,7 +340,7 @@ function emit_text_prelude() -> void {
}
# emit_text2_prelude — the allocating Text ops that build strings/slices:
-# replace, join (over a []str), split (returns a []str). Emitted once per
+# replace, join (over a []string), split (returns a []string). Emitted once per
# program that uses them (g_uses_textrt2). Slices are the {data,len,cap}
# %LSlice with str (ptr) elements.
function emit_text2_prelude() -> void {
diff --git a/selfhost/io.ludic b/selfhost/io.ludic
index 33097b79..129756f3 100644
--- a/selfhost/io.ludic
+++ b/selfhost/io.ludic
@@ -1,7 +1,7 @@
# io.ludic — reading the input file and writing the output, plus tiny stdio.
# The compiler reads one .ludic file whole and emits LLVM IR text to stdout.
-function read_file(path: str) -> ptr {
+function read_file(path: string) -> ptr {
let f = file_open(path, "rb")
if (f == null) { return null }
file_seek(f, 0, 2)
diff --git a/selfhost/ludicc.seed.ll b/selfhost/ludicc.seed.ll
index 12266175..6eecf9b0 100644
--- a/selfhost/ludicc.seed.ll
+++ b/selfhost/ludicc.seed.ll
@@ -111,7 +111,7 @@ declare void @win_close()
@.str10 = private unnamed_addr constant [2 x i8] c",\00"
@.str11 = private unnamed_addr constant [2 x i8] c")\00"
@.str12 = private unnamed_addr constant [2 x i8] c"+\00"
-@.str13 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str13 = private unnamed_addr constant [7 x i8] c"string\00"
@.str14 = private unnamed_addr constant [2 x i8] c"(\00"
@.str15 = private unnamed_addr constant [2 x i8] c")\00"
@.str16 = private unnamed_addr constant [2 x i8] c":\00"
@@ -700,7 +700,7 @@ declare void @win_close()
@.str599 = private unnamed_addr constant [24 x i8] c"getelementptr ptr, ptr \00"
@.str600 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str601 = private unnamed_addr constant [15 x i8] c"load ptr, ptr \00"
-@.str602 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str602 = private unnamed_addr constant [7 x i8] c"string\00"
@.str603 = private unnamed_addr constant [5 x i8] c"exit\00"
@.str604 = private unnamed_addr constant [23 x i8] c" call void @exit(i32 \00"
@.str605 = private unnamed_addr constant [3 x i8] c")\0A\00"
@@ -720,7 +720,7 @@ declare void @win_close()
@.str619 = private unnamed_addr constant [7 x i8] c"getenv\00"
@.str620 = private unnamed_addr constant [22 x i8] c"call ptr @getenv(ptr \00"
@.str621 = private unnamed_addr constant [2 x i8] c")\00"
-@.str622 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str622 = private unnamed_addr constant [7 x i8] c"string\00"
@.str623 = private unnamed_addr constant [2 x i8] c"0\00"
@.str624 = private unnamed_addr constant [5 x i8] c"void\00"
@.str625 = private unnamed_addr constant [5 x i8] c"free\00"
@@ -770,7 +770,7 @@ declare void @win_close()
@.str669 = private unnamed_addr constant [5 x i8] c"bool\00"
@.str670 = private unnamed_addr constant [11 x i8] c"game_title\00"
@.str671 = private unnamed_addr constant [12 x i8] c"@.gametitle\00"
-@.str672 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str672 = private unnamed_addr constant [7 x i8] c"string\00"
@.str673 = private unnamed_addr constant [9 x i8] c"win_poll\00"
@.str674 = private unnamed_addr constant [21 x i8] c"call i32 @win_poll()\00"
@.str675 = private unnamed_addr constant [4 x i8] c"int\00"
@@ -1236,13 +1236,13 @@ declare void @win_close()
@.str1135 = private unnamed_addr constant [9 x i8] c"from_int\00"
@.str1136 = private unnamed_addr constant [26 x i8] c"call ptr @fn_int_str(i32 \00"
@.str1137 = private unnamed_addr constant [2 x i8] c")\00"
-@.str1138 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1138 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1139 = private unnamed_addr constant [6 x i8] c"slice\00"
@.str1140 = private unnamed_addr constant [28 x i8] c"call ptr @fn_str_slice(ptr \00"
@.str1141 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str1142 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str1143 = private unnamed_addr constant [2 x i8] c")\00"
-@.str1144 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1144 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1145 = private unnamed_addr constant [7 x i8] c"equals\00"
@.str1146 = private unnamed_addr constant [25 x i8] c"call i32 @fn_str_eq(ptr \00"
@.str1147 = private unnamed_addr constant [7 x i8] c", ptr \00"
@@ -1252,7 +1252,7 @@ declare void @win_close()
@.str1151 = private unnamed_addr constant [29 x i8] c"call ptr @fn_str_concat(ptr \00"
@.str1152 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str1153 = private unnamed_addr constant [2 x i8] c")\00"
-@.str1154 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1154 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1155 = private unnamed_addr constant [7 x i8] c"length\00"
@.str1156 = private unnamed_addr constant [22 x i8] c"call i64 @strlen(ptr \00"
@.str1157 = private unnamed_addr constant [2 x i8] c")\00"
@@ -1273,46 +1273,46 @@ declare void @win_close()
@.str1172 = private unnamed_addr constant [6 x i8] c"upper\00"
@.str1173 = private unnamed_addr constant [28 x i8] c"call ptr @fn_str_upper(ptr \00"
@.str1174 = private unnamed_addr constant [2 x i8] c")\00"
-@.str1175 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1175 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1176 = private unnamed_addr constant [6 x i8] c"lower\00"
@.str1177 = private unnamed_addr constant [28 x i8] c"call ptr @fn_str_lower(ptr \00"
@.str1178 = private unnamed_addr constant [2 x i8] c")\00"
-@.str1179 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1179 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1180 = private unnamed_addr constant [5 x i8] c"trim\00"
@.str1181 = private unnamed_addr constant [27 x i8] c"call ptr @fn_str_trim(ptr \00"
@.str1182 = private unnamed_addr constant [2 x i8] c")\00"
-@.str1183 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1183 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1184 = private unnamed_addr constant [7 x i8] c"repeat\00"
@.str1185 = private unnamed_addr constant [29 x i8] c"call ptr @fn_str_repeat(ptr \00"
@.str1186 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str1187 = private unnamed_addr constant [2 x i8] c")\00"
-@.str1188 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1188 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1189 = private unnamed_addr constant [9 x i8] c"pad_left\00"
@.str1190 = private unnamed_addr constant [26 x i8] c"call ptr @fn_str_pad(ptr \00"
@.str1191 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str1192 = private unnamed_addr constant [8 x i8] c", i1 1)\00"
-@.str1193 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1193 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1194 = private unnamed_addr constant [10 x i8] c"pad_right\00"
@.str1195 = private unnamed_addr constant [26 x i8] c"call ptr @fn_str_pad(ptr \00"
@.str1196 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str1197 = private unnamed_addr constant [8 x i8] c", i1 0)\00"
-@.str1198 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1198 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1199 = private unnamed_addr constant [8 x i8] c"replace\00"
@.str1200 = private unnamed_addr constant [30 x i8] c"call ptr @fn_str_replace(ptr \00"
@.str1201 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str1202 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str1203 = private unnamed_addr constant [2 x i8] c")\00"
-@.str1204 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1204 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1205 = private unnamed_addr constant [6 x i8] c"split\00"
@.str1206 = private unnamed_addr constant [28 x i8] c"call ptr @fn_str_split(ptr \00"
@.str1207 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str1208 = private unnamed_addr constant [2 x i8] c")\00"
-@.str1209 = private unnamed_addr constant [6 x i8] c"[]str\00"
+@.str1209 = private unnamed_addr constant [9 x i8] c"[]string\00"
@.str1210 = private unnamed_addr constant [5 x i8] c"join\00"
@.str1211 = private unnamed_addr constant [27 x i8] c"call ptr @fn_str_join(ptr \00"
@.str1212 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str1213 = private unnamed_addr constant [2 x i8] c")\00"
-@.str1214 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str1214 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1215 = private unnamed_addr constant [9 x i8] c"contains\00"
@.str1216 = private unnamed_addr constant [9 x i8] c"index_of\00"
@.str1217 = private unnamed_addr constant [22 x i8] c"call ptr @strstr(ptr \00"
@@ -3148,7 +3148,7 @@ declare void @win_close()
@.str3047 = private unnamed_addr constant [29 x i8] c"call ptr @fn_str_concat(ptr \00"
@.str3048 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str3049 = private unnamed_addr constant [2 x i8] c")\00"
-@.str3050 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str3050 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3051 = private unnamed_addr constant [25 x i8] c"call i32 @fn_str_eq(ptr \00"
@.str3052 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str3053 = private unnamed_addr constant [2 x i8] c")\00"
@@ -3568,15 +3568,15 @@ declare void @win_close()
@.str3467 = private unnamed_addr constant [4 x i8] c"int\00"
@.str3468 = private unnamed_addr constant [4 x i8] c"len\00"
@.str3469 = private unnamed_addr constant [5 x i8] c"push\00"
-@.str3470 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str3470 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3471 = private unnamed_addr constant [4 x i8] c"ptr\00"
@.str3472 = private unnamed_addr constant [4 x i8] c"i64\00"
@.str3473 = private unnamed_addr constant [27 x i8] c"call ptr @fn_long_str(i64 \00"
@.str3474 = private unnamed_addr constant [2 x i8] c")\00"
-@.str3475 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str3475 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3476 = private unnamed_addr constant [26 x i8] c"call ptr @fn_int_str(i32 \00"
@.str3477 = private unnamed_addr constant [2 x i8] c")\00"
-@.str3478 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str3478 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3479 = private unnamed_addr constant [6 x i8] c"print\00"
@.str3480 = private unnamed_addr constant [4 x i8] c"ptr\00"
@.str3481 = private unnamed_addr constant [51 x i8] c" call i32 (ptr, ...) @printf(ptr @.fmt_line, ptr \00"
@@ -3712,8 +3712,8 @@ declare void @win_close()
@.str3611 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str3612 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str3613 = private unnamed_addr constant [2 x i8] c")\00"
-@.str3614 = private unnamed_addr constant [4 x i8] c"str\00"
-@.str3615 = private unnamed_addr constant [4 x i8] c"str\00"
+@.str3614 = private unnamed_addr constant [7 x i8] c"string\00"
+@.str3615 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3616 = private unnamed_addr constant [4 x i8] c"int\00"
@.str3617 = private unnamed_addr constant [6 x i8] c"load \00"
@.str3618 = private unnamed_addr constant [10 x i8] c", ptr @g_\00"
diff --git a/selfhost/parse.ludic b/selfhost/parse.ludic
index 34d62317..34ff3ac2 100644
--- a/selfhost/parse.ludic
+++ b/selfhost/parse.ludic
@@ -68,15 +68,15 @@ function args_call(call: Node) -> void {
}
# ---- string interpolation --------------------------------------------------
-# `text {expr} text` desugars to a `+` chain of string literals and `str(expr)`
+# `text {expr} text` desugars to a `+` chain of string literals and `string(expr)`
# holes, so it reuses the string-concat operator and needs no new runtime.
function interp_lit(buf: ptr, len: int) -> Node { let n = node(E_STR); n.s = buf[0..0 + len]; return n }
function interp_add(acc: Node, part: Node) -> Node {
if acc == null { return part }
return mkbin("+", acc, part)
}
-function interp_str(e: Node) -> Node { # wrap a hole in str(...)
- let c = node(E_CALL); let id = node(E_ID); id.s = "str"; c.a = id; push(c.kids, e); return c
+function interp_str(e: Node) -> Node { # wrap a hole in string(...)
+ let c = node(E_CALL); let id = node(E_ID); id.s = "string"; c.a = id; push(c.kids, e); return c
}
function parse_hole(inner: ptr) -> Node { # re-lex+parse an embedded expression
let saved_toks = toks; let saved_pi = pi
diff --git a/selfhost/tests/long.ludic b/selfhost/tests/long.ludic
index e528c7c2..04f6ae4c 100644
--- a/selfhost/tests/long.ludic
+++ b/selfhost/tests/long.ludic
@@ -18,6 +18,6 @@ program T {
print(x == x) # 1
print(0 - sq) # -1000000000000 (unary negate stays 64-bit)
print(big) # 1000000
- print(Text.length(str(sq))) # 13 — str(long) renders all 13 digits
+ print(Text.length(string(sq))) # 13 — string(long) renders all 13 digits
}
}
diff --git a/tools/atlas.ludic b/tools/atlas.ludic
index 5965ed92..c2ef93ec 100644
--- a/tools/atlas.ludic
+++ b/tools/atlas.ludic
@@ -34,7 +34,7 @@ game Atlas {
# build "/tile_%04d.png" without a formatter: the runtime's string
# helpers write into a scratch buffer we own
- function tile_path(i: int) -> str {
+ function tile_path(i: int) -> string {
let buf = atlas_buf()
let n = rt_put_str(buf, 0, DIR)
n = rt_put_str(buf, n, "/tile_")
diff --git a/tools/docgen/inventory.json b/tools/docgen/inventory.json
index 3fe7c0a4..db92f160 100644
--- a/tools/docgen/inventory.json
+++ b/tools/docgen/inventory.json
@@ -25,7 +25,7 @@
],
"builtins": [
"fn-print",
- "fn-str",
+ "fn-string",
"fn-quit",
"fn-save",
"fn-load",
@@ -327,7 +327,7 @@
"type-ptr",
"type-ptrs",
"type-slices",
- "type-str",
+ "type-string",
"type-void",
"type-words"
],
diff --git a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt
index 9d9dd775..3d2aa523 100644
--- a/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt
+++ b/tools/editors/jetbrains/src/main/kotlin/io/ludic/ide/LudicTokens.kt
@@ -22,7 +22,7 @@ object LudicTokens {
val KEYWORD = LudicTokenType("KEYWORD")
val DECL_KEYWORD = LudicTokenType("DECL_KEYWORD") // game, component, system, function, ...
val CLAUSE = LudicTokenType("CLAUSE") // phase, query, reads, writes, ...
- val PRIMITIVE = LudicTokenType("PRIMITIVE") // int, fixed, bool, entity, str, ptr, void
+ val PRIMITIVE = LudicTokenType("PRIMITIVE") // int, fixed, bool, entity, string, pointer, void
val PHASE = LudicTokenType("PHASE") // Start, Update, Render, ...
val BOOLEAN = LudicTokenType("BOOLEAN")
val BUILTIN = LudicTokenType("BUILTIN") // runtime surface + compiler intrinsics
@@ -52,7 +52,7 @@ object LudicVocabulary {
"enable", "disable", "match", "machine", "state", "become", "where",
"and", "or", "not", "break", "continue", "new", "emit", "cancel"
)
- val PRIMITIVES = setOf("int", "long", "fixed", "bool", "entity", "str", "ptr", "byte", "words", "fixeds", "ptrs", "void")
+ val PRIMITIVES = setOf("int", "long", "fixed", "bool", "entity", "string", "ptr", "byte", "words", "fixeds", "ptrs", "void")
val PHASES = setOf("Start", "Input", "FixedUpdate", "Update", "LateUpdate", "Render")
val WIDGETS = setOf("panel", "col", "row", "label", "button", "image", "spacer")
@@ -64,7 +64,7 @@ object LudicVocabulary {
"sprites_load", "draw_sprite", "draw_sprite_scaled", "ui_build", "ui_open",
"ui_tick", "ui_render", "ui_clicked", "ui_set_text", "ui_set_int", "ui_focus",
"ui_focused", "ui_visible", "key", "reg", "set_reg", "self", "save", "load",
- "status", "print", "str", "quit",
+ "status", "print", "string", "quit",
// compiler intrinsics: the floor the Ludic-written runtime stands on
"bytes", "words", "resize", "free", "fill", "arg_count", "arg", "file_stderr", "file_stdout",
"offset",
diff --git a/tools/editors/shared/ludic.tmLanguage.json b/tools/editors/shared/ludic.tmLanguage.json
index 563c08f6..7ec5a746 100644
--- a/tools/editors/shared/ludic.tmLanguage.json
+++ b/tools/editors/shared/ludic.tmLanguage.json
@@ -177,7 +177,7 @@
{ "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|on)\\b" },
{ "name": "keyword.other.ludic", "match": "\\b(import|extern)\\b" },
{ "name": "storage.type.ludic", "match": "\\b(program|property|model|enum|ui|const|var|let|function|handler|entry|state)\\b" },
- { "name": "support.type.primitive.ludic", "match": "\\b(int|long|fixed|bool|entity|str|ptr|byte|words|fixeds|ptrs|void)\\b" },
+ { "name": "support.type.primitive.ludic", "match": "\\b(int|long|fixed|bool|entity|string|ptr|byte|words|fixeds|ptrs|void)\\b" },
{ "name": "constant.language.boolean.ludic", "match": "\\b(true|false|null)\\b" },
{ "name": "constant.language.phase.ludic", "match": "\\b(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\b" }
]
@@ -204,7 +204,7 @@
{
"comment": "the runtime surface — every name here resolves to rt_ in runtime/native",
"name": "support.function.builtin.ludic",
- "match": "\\b(min|max|abs|clamp|seed|rng_range|rng_chance|fx|flr|map_size|map_row|tile|clear|present|fill_rect|frame_rect|put_px|text|text_int|font_load|text_ttf|text_w|text_h|image_load|draw_image|draw_image_scaled|draw_9slice|png_load|sprites_load|draw_sprite|draw_sprite_scaled|ui_build|ui_open|ui_tick|ui_render|ui_clicked|ui_set_text|ui_set_int|ui_focus|ui_focused|ui_visible|key|reg|set_reg|self|save|load|status|print|str|quit)\\b(?=\\s*\\()"
+ "match": "\\b(min|max|abs|clamp|seed|rng_range|rng_chance|fx|flr|map_size|map_row|tile|clear|present|fill_rect|frame_rect|put_px|text|text_int|font_load|text_ttf|text_w|text_h|image_load|draw_image|draw_image_scaled|draw_9slice|png_load|sprites_load|draw_sprite|draw_sprite_scaled|ui_build|ui_open|ui_tick|ui_render|ui_clicked|ui_set_text|ui_set_int|ui_focus|ui_focused|ui_visible|key|reg|set_reg|self|save|load|status|print|string|quit)\\b(?=\\s*\\()"
},
{
"comment": "compiler intrinsics — these lower straight to libc or the OS",
diff --git a/tools/editors/vscode/syntaxes/ludic.tmLanguage.json b/tools/editors/vscode/syntaxes/ludic.tmLanguage.json
index 563c08f6..7ec5a746 100644
--- a/tools/editors/vscode/syntaxes/ludic.tmLanguage.json
+++ b/tools/editors/vscode/syntaxes/ludic.tmLanguage.json
@@ -177,7 +177,7 @@
{ "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|on)\\b" },
{ "name": "keyword.other.ludic", "match": "\\b(import|extern)\\b" },
{ "name": "storage.type.ludic", "match": "\\b(program|property|model|enum|ui|const|var|let|function|handler|entry|state)\\b" },
- { "name": "support.type.primitive.ludic", "match": "\\b(int|long|fixed|bool|entity|str|ptr|byte|words|fixeds|ptrs|void)\\b" },
+ { "name": "support.type.primitive.ludic", "match": "\\b(int|long|fixed|bool|entity|string|ptr|byte|words|fixeds|ptrs|void)\\b" },
{ "name": "constant.language.boolean.ludic", "match": "\\b(true|false|null)\\b" },
{ "name": "constant.language.phase.ludic", "match": "\\b(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\b" }
]
@@ -204,7 +204,7 @@
{
"comment": "the runtime surface — every name here resolves to rt_ in runtime/native",
"name": "support.function.builtin.ludic",
- "match": "\\b(min|max|abs|clamp|seed|rng_range|rng_chance|fx|flr|map_size|map_row|tile|clear|present|fill_rect|frame_rect|put_px|text|text_int|font_load|text_ttf|text_w|text_h|image_load|draw_image|draw_image_scaled|draw_9slice|png_load|sprites_load|draw_sprite|draw_sprite_scaled|ui_build|ui_open|ui_tick|ui_render|ui_clicked|ui_set_text|ui_set_int|ui_focus|ui_focused|ui_visible|key|reg|set_reg|self|save|load|status|print|str|quit)\\b(?=\\s*\\()"
+ "match": "\\b(min|max|abs|clamp|seed|rng_range|rng_chance|fx|flr|map_size|map_row|tile|clear|present|fill_rect|frame_rect|put_px|text|text_int|font_load|text_ttf|text_w|text_h|image_load|draw_image|draw_image_scaled|draw_9slice|png_load|sprites_load|draw_sprite|draw_sprite_scaled|ui_build|ui_open|ui_tick|ui_render|ui_clicked|ui_set_text|ui_set_int|ui_focus|ui_focused|ui_visible|key|reg|set_reg|self|save|load|status|print|string|quit)\\b(?=\\s*\\()"
},
{
"comment": "compiler intrinsics — these lower straight to libc or the OS",
diff --git a/tools/ludic-tools/fmt.ludic b/tools/ludic-tools/fmt.ludic
index 9b3ac0ad..02489075 100644
--- a/tools/ludic-tools/fmt.ludic
+++ b/tools/ludic-tools/fmt.ludic
@@ -28,7 +28,7 @@ program LudicFmt {
const LT_ERR: int = 14
# ---- tiny stdio + string helpers (self-contained) ----
- function read_file(path: str) -> ptr {
+ function read_file(path: string) -> ptr {
let f = file_open(path, "rb")
if (f == null) { return null }
file_seek(f, 0, 2)
diff --git a/tools/ludic-tools/lsp.ludic b/tools/ludic-tools/lsp.ludic
index 3d783637..e431d6e6 100644
--- a/tools/ludic-tools/lsp.ludic
+++ b/tools/ludic-tools/lsp.ludic
@@ -204,7 +204,7 @@ program LudicLsp {
return c == 43 or c == 45 or c == 42 or c == 47 or c == 37 or c == 60 or c == 62 or c == 61 or c == 40 or c == 41 or c == 123 or c == 125 or c == 91 or c == 93 or c == 44 or c == 58 or c == 46 or c == 33 or c == 64 or c == 59
}
function is_type_word(w: ptr) -> bool {
- return (w == "int") or (w == "long") or (w == "fixed") or (w == "bool") or (w == "entity") or (w == "str") or (w == "ptr") or (w == "byte") or (w == "words") or (w == "fixeds") or (w == "ptrs") or (w == "void")
+ return (w == "int") or (w == "long") or (w == "fixed") or (w == "bool") or (w == "entity") or (w == "string") or (w == "ptr") or (w == "byte") or (w == "words") or (w == "fixeds") or (w == "ptrs") or (w == "void")
}
function is_phase_word(w: ptr) -> bool {
return (w == "Start") or (w == "Input") or (w == "FixedUpdate") or (w == "Update") or (w == "LateUpdate") or (w == "Render")
@@ -1272,24 +1272,24 @@ program LudicLsp {
if (ns == "Text") {
if (meth == "length") { return "Text.length(s) -> int" }
if (meth == "char_at") { return "Text.char_at(s, i) -> int" }
- if (meth == "slice") { return "Text.slice(s, a, b) -> str" }
+ if (meth == "slice") { return "Text.slice(s, a, b) -> string" }
if (meth == "starts_with") { return "Text.starts_with(s, prefix) -> bool" }
if (meth == "ends_with") { return "Text.ends_with(s, suffix) -> bool" }
if (meth == "contains") { return "Text.contains(s, sub) -> bool" }
if (meth == "index_of") { return "Text.index_of(s, sub) -> int" }
if (meth == "equals") { return "Text.equals(a, b) -> bool" }
- if (meth == "concat") { return "Text.concat(a, b) -> str" }
+ if (meth == "concat") { return "Text.concat(a, b) -> string" }
if (meth == "to_int") { return "Text.to_int(s) -> int" }
- if (meth == "from_int") { return "Text.from_int(n) -> str" }
- if (meth == "upper") { return "Text.upper(s) -> str" }
- if (meth == "lower") { return "Text.lower(s) -> str" }
- if (meth == "trim") { return "Text.trim(s) -> str" }
- if (meth == "repeat") { return "Text.repeat(s, n) -> str" }
- if (meth == "pad_left") { return "Text.pad_left(s, width) -> str" }
- if (meth == "pad_right") { return "Text.pad_right(s, width) -> str" }
- if (meth == "split") { return "Text.split(s, sep) -> []str" }
- if (meth == "join") { return "Text.join(parts, sep) -> str" }
- if (meth == "replace") { return "Text.replace(s, from, to) -> str" }
+ if (meth == "from_int") { return "Text.from_int(n) -> string" }
+ if (meth == "upper") { return "Text.upper(s) -> string" }
+ if (meth == "lower") { return "Text.lower(s) -> string" }
+ if (meth == "trim") { return "Text.trim(s) -> string" }
+ if (meth == "repeat") { return "Text.repeat(s, n) -> string" }
+ if (meth == "pad_left") { return "Text.pad_left(s, width) -> string" }
+ if (meth == "pad_right") { return "Text.pad_right(s, width) -> string" }
+ if (meth == "split") { return "Text.split(s, sep) -> []string" }
+ if (meth == "join") { return "Text.join(parts, sep) -> string" }
+ if (meth == "replace") { return "Text.replace(s, from, to) -> string" }
}
if (ns == "Hash") {
if (meth == "of") { return "Hash.of(s) -> int" }
@@ -1360,11 +1360,11 @@ program LudicLsp {
if (meth == "local_id") { return "Network.local_id() -> int" }
}
if (ns == "System") {
- if (meth == "arg") { return "System.arg(i) -> str" }
+ if (meth == "arg") { return "System.arg(i) -> string" }
if (meth == "arg_count") { return "System.arg_count() -> int" }
if (meth == "exit") { return "System.exit(code)" }
if (meth == "run") { return "System.run(command) -> int" }
- if (meth == "env") { return "System.env(name) -> str" }
+ if (meth == "env") { return "System.env(name) -> string" }
if (meth == "read_char") { return "System.read_char() -> int" }
if (meth == "file_open") { return "System.file_open(path, mode) -> ptr" }
if (meth == "file_read") { return "System.file_read(file, buf, n) -> int" }
@@ -1407,25 +1407,25 @@ program LudicLsp {
badd("fx", "fx(i: int) -> fixed")
badd("flr", "flr(f: fixed) -> int")
badd("map_size", "map_size(w: int, h: int)")
- badd("map_row", "map_row(y: int, row: str)")
+ badd("map_row", "map_row(y: int, row: string)")
badd("tile", "tile(x: int, y: int) -> int")
badd("clear", "clear(color: int)")
badd("present", "present()")
badd("fill_rect", "fill_rect(x: int, y: int, w: int, h: int, color: int)")
badd("frame_rect", "frame_rect(x: int, y: int, w: int, h: int, color: int)")
badd("put_px", "put_px(x: int, y: int, color: int)")
- badd("text", "text(x: int, y: int, s: str, color: int, scale: int)")
+ badd("text", "text(x: int, y: int, s: string, color: int, scale: int)")
badd("text_int", "text_int(x: int, y: int, n: int, color: int, scale: int)")
- badd("font_load", "font_load(path: str) -> int")
- badd("text_ttf", "text_ttf(font: int, x: int, y: int, utf8: str, color: int, px: int)")
- badd("text_w", "text_w(font: int, utf8: str, px: int) -> int")
+ badd("font_load", "font_load(path: string) -> int")
+ badd("text_ttf", "text_ttf(font: int, x: int, y: int, utf8: string, color: int, px: int)")
+ badd("text_w", "text_w(font: int, utf8: string, px: int) -> int")
badd("text_h", "text_h(font: int, px: int) -> int")
- badd("image_load", "image_load(path: str) -> int")
+ badd("image_load", "image_load(path: string) -> int")
badd("draw_image", "draw_image(id: int, x: int, y: int)")
badd("draw_image_scaled", "draw_image_scaled(id: int, x: int, y: int, w: int, h: int)")
badd("draw_9slice", "draw_9slice(id: int, x: int, y: int, w: int, h: int, inset: int)")
- badd("png_load", "png_load(path: str) -> int")
- badd("sprites_load", "sprites_load(path: str)")
+ badd("png_load", "png_load(path: string) -> int")
+ badd("sprites_load", "sprites_load(path: string)")
badd("draw_sprite", "draw_sprite(id: int, x: int, y: int)")
badd("draw_sprite_scaled", "draw_sprite_scaled(id: int, x: int, y: int, scale: int)")
badd("ui_build", "ui_build()")
@@ -1433,7 +1433,7 @@ program LudicLsp {
badd("ui_tick", "ui_tick(key: int)")
badd("ui_render", "ui_render()")
badd("ui_clicked", "ui_clicked(id: int) -> bool")
- badd("ui_set_text", "ui_set_text(id: int, s: str)")
+ badd("ui_set_text", "ui_set_text(id: int, s: string)")
badd("ui_set_int", "ui_set_int(id: int, n: int)")
badd("ui_focus", "ui_focus(id: int)")
badd("ui_focused", "ui_focused() -> int")
@@ -1444,15 +1444,15 @@ program LudicLsp {
badd("self", "self() -> entity")
badd("save", "save()")
badd("load", "load() -> bool")
- badd("status", "status(s: str)")
+ badd("status", "status(s: string)")
badd("print", "print(x)")
- badd("str", "str(x) -> str")
+ badd("string", "string(x) -> string")
badd("quit", "quit()")
badd("bytes", "bytes(n: int) -> ptr")
badd("words", "words(n: int) -> words")
badd("resize", "resize(p: ptr, n: int) -> ptr")
badd("arg_count", "arg_count() -> int")
- badd("arg", "arg(i: int) -> str")
+ badd("arg", "arg(i: int) -> string")
badd("file_stderr", "file_stderr() -> ptr")
badd("file_stdout", "file_stdout() -> ptr")
badd("free", "free(p: ptr)")
@@ -1460,7 +1460,7 @@ program LudicLsp {
badd("offset", "offset(p: ptr, off: int) -> ptr")
badd("as_fixed", "as_fixed(i: int) -> fixed")
badd("as_int", "as_int(f: fixed) -> int")
- badd("file_open", "file_open(path: str, mode: str) -> ptr")
+ badd("file_open", "file_open(path: string, mode: string) -> ptr")
badd("file_read", "file_read(f: ptr, buf: ptr, n: int) -> int")
badd("file_write", "file_write(f: ptr, buf: ptr, n: int) -> int")
badd("file_seek", "file_seek(f: ptr, off: int, whence: int) -> int")
@@ -1469,8 +1469,8 @@ program LudicLsp {
badd("read_char", "read_char() -> int")
badd("exit", "exit(code: int)")
badd("is_windowed", "is_windowed() -> bool")
- badd("game_title", "game_title() -> str")
- badd("win_open", "win_open(title: str, w: int, h: int, scale: int)")
+ badd("game_title", "game_title() -> string")
+ badd("win_open", "win_open(title: string, w: int, h: int, scale: int)")
badd("win_poll", "win_poll() -> int")
badd("win_present", "win_present(px: ptr, w: int, h: int)")
badd("win_running", "win_running() -> bool")
@@ -2287,7 +2287,7 @@ program LudicLsp {
}
function comp_types(o: Buf) -> void {
comp_item(o, "int", 14, "built-in type"); comp_item(o, "long", 14, "built-in type"); comp_item(o, "fixed", 14, "built-in type"); comp_item(o, "bool", 14, "built-in type")
- comp_item(o, "entity", 14, "built-in type"); comp_item(o, "str", 14, "built-in type"); comp_item(o, "ptr", 14, "built-in type"); comp_item(o, "void", 14, "built-in type")
+ comp_item(o, "entity", 14, "built-in type"); comp_item(o, "string", 14, "built-in type"); comp_item(o, "ptr", 14, "built-in type"); comp_item(o, "void", 14, "built-in type")
}
function comp_builtins(o: Buf) -> void { var i = 0; while i < len(g_builtins) { comp_item(o, g_builtins[i], 3, g_bsigs[i]); i = i + 1 } }
function on_completion(msg: JVal, id: JVal) -> void {
diff --git a/tools/ludic-tools/ludic_syntax.h b/tools/ludic-tools/ludic_syntax.h
index f2463b56..1334e047 100644
--- a/tools/ludic-tools/ludic_syntax.h
+++ b/tools/ludic-tools/ludic_syntax.h
@@ -25,7 +25,7 @@ enum {
LT_EOF, LT_NL, LT_COMMENT,
LT_ID, /* a plain identifier */
LT_KW, /* a reserved word (see KEYWORDS) */
- LT_TYPE, /* a built-in type name: int fixed bool entity str ptr void */
+ LT_TYPE, /* a built-in type name: int fixed bool entity string pointer void */
LT_PHASE, /* Start Input FixedUpdate Update LateUpdate Render */
LT_BOOL, /* true false */
LT_INT, LT_FLOAT, LT_STR, LT_CHAR,
@@ -71,7 +71,7 @@ static const char* LUDIC_KW_STMT[] = {
"and","or","not","break","continue","new","emit","cancel", 0
};
static const char* LUDIC_TYPES[] = {
- "int","long","fixed","bool","entity","str","ptr","byte","words","fixeds","ptrs","void", 0
+ "int","long","fixed","bool","entity","string","ptr","byte","words","fixeds","ptrs","void", 0
};
static const char* LUDIC_PHASES[] = {
"Start","Input","FixedUpdate","Update","LateUpdate","Render", 0
@@ -100,25 +100,25 @@ static const LBuiltin LUDIC_BUILTINS[] = {
{"fx","fx(i: int) -> fixed","Widen an int to Q16.16 fixed-point."},
{"flr","flr(f: fixed) -> int","Truncate a fixed-point value toward zero."},
{"map_size","map_size(w: int, h: int)","Set the tilemap dimensions."},
- {"map_row","map_row(y: int, row: str)","Fill one tilemap row from a string."},
+ {"map_row","map_row(y: int, row: string)","Fill one tilemap row from a string."},
{"tile","tile(x: int, y: int) -> int","Tile code at a map cell."},
{"clear","clear(color: int)","Clear the framebuffer to a 0xRRGGBB colour."},
{"present","present()","Push the framebuffer to the window (or out.ppm when headless)."},
{"fill_rect","fill_rect(x: int, y: int, w: int, h: int, color: int)","Filled rectangle."},
{"frame_rect","frame_rect(x: int, y: int, w: int, h: int, color: int)","One-pixel rectangle outline."},
{"put_px","put_px(x: int, y: int, color: int)","Write a single pixel."},
- {"text","text(x: int, y: int, s: str, color: int, scale: int)","Draw text with the built-in 5x7 bitmap font."},
+ {"text","text(x: int, y: int, s: string, color: int, scale: int)","Draw text with the built-in 5x7 bitmap font."},
{"text_int","text_int(x: int, y: int, n: int, color: int, scale: int)","Draw an integer with the 5x7 bitmap font."},
- {"font_load","font_load(path: str) -> int","Load a TrueType .ttf/.ttc; returns a font id."},
- {"text_ttf","text_ttf(font: int, x: int, y: int, utf8: str, color: int, px: int)","Draw UTF-8 text with a TrueType font."},
- {"text_w","text_w(font: int, utf8: str, px: int) -> int","Advance width of the string, in pixels."},
+ {"font_load","font_load(path: string) -> int","Load a TrueType .ttf/.ttc; returns a font id."},
+ {"text_ttf","text_ttf(font: int, x: int, y: int, utf8: string, color: int, px: int)","Draw UTF-8 text with a TrueType font."},
+ {"text_w","text_w(font: int, utf8: string, px: int) -> int","Advance width of the string, in pixels."},
{"text_h","text_h(font: int, px: int) -> int","Line height of the font, in pixels."},
- {"image_load","image_load(path: str) -> int","Decode a PNG into an image id."},
+ {"image_load","image_load(path: string) -> int","Decode a PNG into an image id."},
{"draw_image","draw_image(id: int, x: int, y: int)","Blit an image at its natural size."},
{"draw_image_scaled","draw_image_scaled(id: int, x: int, y: int, w: int, h: int)","Blit an image stretched to w x h."},
{"draw_9slice","draw_9slice(id: int, x: int, y: int, w: int, h: int, inset: int)","Nine-slice an image across a w x h box."},
- {"png_load","png_load(path: str) -> int","Decode a PNG as a 16x16 sprite sheet; returns the first sprite id."},
- {"sprites_load","sprites_load(path: str)","Load the sprite sheet used by draw_sprite."},
+ {"png_load","png_load(path: string) -> int","Decode a PNG as a 16x16 sprite sheet; returns the first sprite id."},
+ {"sprites_load","sprites_load(path: string)","Load the sprite sheet used by draw_sprite."},
{"draw_sprite","draw_sprite(id: int, x: int, y: int)","Blit a sprite."},
{"draw_sprite_scaled","draw_sprite_scaled(id: int, x: int, y: int, scale: int)","Blit a sprite at an integer scale."},
{"ui_build","ui_build()","Construct every declared `ui` tree (loads skins and images)."},
@@ -126,7 +126,7 @@ static const LBuiltin LUDIC_BUILTINS[] = {
{"ui_tick","ui_tick(key: int)","Feed a key to the UI: w/s move focus, space/enter activate."},
{"ui_render","ui_render()","Lay out and draw the active ui tree."},
{"ui_clicked","ui_clicked(id: int) -> bool","True on the frame a widget was activated."},
- {"ui_set_text","ui_set_text(id: int, s: str)","Replace a widget's text."},
+ {"ui_set_text","ui_set_text(id: int, s: string)","Replace a widget's text."},
{"ui_set_int","ui_set_int(id: int, n: int)","Replace a widget's text with a number."},
{"ui_focus","ui_focus(id: int)","Move keyboard focus to a widget."},
{"ui_focused","ui_focused() -> int","Id of the focused widget."},
@@ -137,9 +137,9 @@ static const LBuiltin LUDIC_BUILTINS[] = {
{"self","self() -> entity","The entity of the innermost query loop."},
{"save","save()","Write a binary snapshot of the whole ECS world."},
{"load","load() -> bool","Restore the snapshot; false if there is none."},
- {"status","status(s: str)","Set the one-line status message."},
+ {"status","status(s: string)","Set the one-line status message."},
{"print","print(x)","Print a value (int or string) and a newline to stdout."},
- {"str","str(x) -> str","Convert an int/bool/fixed to text (a string passes through)."},
+ {"string","string(x) -> string","Convert an int/bool/fixed to text (a string passes through)."},
{"quit","quit()","Stop the frame loop and exit."},
{0,0,0}
};
@@ -157,7 +157,7 @@ static const LBuiltin LUDIC_INTRINSICS[] = {
{"offset","offset(p: ptr, off: int) -> ptr","Offset a pointer by bytes."},
{"as_fixed","as_fixed(i: int) -> fixed","Reinterpret an int as fixed (no conversion)."},
{"as_int","as_int(f: fixed) -> int","Reinterpret a fixed as int (no conversion)."},
- {"file_open","file_open(path: str, mode: str) -> ptr","fopen."},
+ {"file_open","file_open(path: string, mode: string) -> ptr","fopen."},
{"file_read","file_read(f: ptr, buf: ptr, n: int) -> int","fread."},
{"file_write","file_write(f: ptr, buf: ptr, n: int) -> int","fwrite."},
{"file_seek","file_seek(f: ptr, off: int, whence: int) -> int","fseek."},
@@ -167,7 +167,7 @@ static const LBuiltin LUDIC_INTRINSICS[] = {
{"exit","exit(code: int)","Terminate the process."},
{"is_windowed","is_windowed() -> bool","True when the build has a window."},
{"game_title","game_title() -> str","The name from the `game` declaration."},
- {"win_open","win_open(title: str, w: int, h: int, scale: int)","Open the platform window."},
+ {"win_open","win_open(title: string, w: int, h: int, scale: int)","Open the platform window."},
{"win_poll","win_poll() -> int","Pump the event queue; returns a key code."},
{"win_present","win_present(px: ptr, w: int, h: int)","Blit a framebuffer to the window."},
{"win_running","win_running() -> bool","False once the window has been closed."},
diff --git a/tools/x/prelude.ludic b/tools/x/prelude.ludic
index 34e3b0e6..002932f3 100644
--- a/tools/x/prelude.ludic
+++ b/tools/x/prelude.ludic
@@ -113,7 +113,7 @@ function check(label: ptr, got: ptr, want: ptr) -> void {
# print the "== N passed, M failed ==" footer and return the process exit code
function report() -> int {
print("")
- print(`== {str(PASS)} passed, {str(FAIL)} failed ==`)
+ print(`== {string(PASS)} passed, {string(FAIL)} failed ==`)
if (FAIL == 0) { return 0 }
return 1
}
diff --git a/tools/x/test.ludic b/tools/x/test.ludic
index 4bb713f9..2c52c2d7 100644
--- a/tools/x/test.ludic
+++ b/tools/x/test.ludic
@@ -137,7 +137,7 @@ function cmd_test() -> int {
write_file("/tmp/x_cli_exit.ludic", "entry { exit(42) }\n")
let rc = sh("LUDIC_HOME=. bin/ludic /tmp/x_cli_exit.ludic > /tmp/x_cli.out 2>&1")
if (rc == 42) { ok("ludic app.ludic -> compiles, runs, forwards exit code") }
- else { bad2("ludic run: expected exit 42", `got {str(rc)}`) }
+ else { bad2("ludic run: expected exit 42", `got {string(rc)}`) }
return report()
}
diff --git a/tools/x/tools.ludic b/tools/x/tools.ludic
index 6211eb28..9e23218e 100644
--- a/tools/x/tools.ludic
+++ b/tools/x/tools.ludic
@@ -81,7 +81,7 @@ function cmd_test_tools() -> int {
} else { bad("formatter altered non-whitespace bytes") }
# --- multi-byte characters must survive intact -----------------------------
- write_file("/tmp/x_utf8.ludic", "program E {\n # … ellipsis in a comment\n const S: str = \"café → naïve\"\n}\n")
+ write_file("/tmp/x_utf8.ludic", "program E {\n # … ellipsis in a comment\n const S: string = \"café → naïve\"\n}\n")
if shq(`{fmt} /tmp/x_utf8.ludic > /tmp/x_utf8.out 2>/dev/null; cmp -s /tmp/x_utf8.ludic /tmp/x_utf8.out`) {
ok("UTF-8 preserved byte for byte")
} else { bad("UTF-8 mangled") }
@@ -111,10 +111,10 @@ function cmd_test_tools() -> int {
# --- --check exit status, for CI and pre-commit hooks ----------------------
let chk1 = sh(`{fmt} --check -q /tmp/x_m.ludic`)
- check("--check exits 1 on unformatted input", str(chk1), "1")
+ check("--check exits 1 on unformatted input", string(chk1), "1")
run(`{fmt} -w /tmp/x_m.ludic`)
let chk2 = sh(`{fmt} --check -q /tmp/x_m.ludic`)
- check("--check exits 0 after -w", str(chk2), "0")
+ check("--check exits 0 after -w", string(chk2), "0")
# --- markdown: fences formatted, prose untouched ---------------------------
write_file("/tmp/x_d.md", "# T\n\nprose with spaces\n\n```ludic\nprogram D{property P{x:int=0}}\n```\n\n```python\nz = 1\n```\n")