refactor(lang): rename the str type (and stringify builtin) to string
Expand the abbreviated string type and its conversion builtin to the full
word everywhere:
str -> string (the immutable-string type)
str(x) -> str -> string(x) -> string (the stringify builtin;
what `{…}` interpolation calls)
Types are recognized by identifier, and llty maps both spellings to LLVM
`ptr`, so this is an atomic source rewrite: type annotations, the Ludic
type tags, the builtin name/dispatch, and the interpolation desugar, plus
the grammars, LSP, docs (type-str -> type-string, fn-str -> fn-string), and
inventory. int/bool stay (universally accepted, like Math).
Reseeded; C-free fixpoint holds; all suites green (45/24/29); site + check.py OK.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
4c48077d68
commit
b7745a4600
70 changed files with 207 additions and 207 deletions
|
|
@ -4,7 +4,7 @@ name: arg
|
||||||
category: builtins
|
category: builtins
|
||||||
kind: builtin
|
kind: builtin
|
||||||
tokens: arg
|
tokens: arg
|
||||||
sig: arg(i) -> str
|
sig: arg(i) -> string
|
||||||
tip: The i-th command-line argument as a string.
|
tip: The i-th command-line argument as a string.
|
||||||
order: 50
|
order: 50
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: getenv
|
||||||
category: builtins
|
category: builtins
|
||||||
kind: builtin
|
kind: builtin
|
||||||
tokens: getenv
|
tokens: getenv
|
||||||
sig: getenv(name) -> str
|
sig: getenv(name) -> string
|
||||||
tip: Read an environment variable, returning empty when it is unset.
|
tip: Read an environment variable, returning empty when it is unset.
|
||||||
order: 23
|
order: 23
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
---
|
---
|
||||||
id: fn-str
|
id: fn-string
|
||||||
name: str
|
name: string
|
||||||
category: builtins
|
category: builtins
|
||||||
kind: builtin
|
kind: builtin
|
||||||
tokens: str
|
tokens: string
|
||||||
sig: str(x) -> str
|
sig: string(x) -> string
|
||||||
tip: Convert an int, bool, or fixed value to text; a string passes through unchanged.
|
tip: Convert an int, bool, or fixed value to text; a string passes through unchanged.
|
||||||
order: 1
|
order: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
Converts a value to its textual form: an <code>int</code>, <code>bool</code>, or <code>fixed</code> becomes a string, and a value that is already a string is returned unchanged. This is what backtick <code>`{…}`</code> interpolation calls under the hood, so most of the time you can interpolate directly instead of calling <code>str</code> 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 <code>Screen.draw_text</code>, or concatenated.
|
Converts a value to its textual form: an <code>int</code>, <code>bool</code>, or <code>fixed</code> becomes a string, and a value that is already a string is returned unchanged. This is what backtick <code>`{…}`</code> interpolation calls under the hood, so most of the time you can interpolate directly instead of calling <code>string</code> 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 <code>Screen.draw_text</code>, or concatenated.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- `x` — the value to convert to text
|
- `x` — the value to convert to text
|
||||||
|
|
@ -19,7 +19,7 @@ program LabelValue {
|
||||||
var score: int = 250
|
var score: int = 250
|
||||||
|
|
||||||
handler ReportScore phase Start {
|
handler ReportScore phase Start {
|
||||||
let label = str(score)
|
let label = string(score)
|
||||||
print(label)
|
print(label)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +27,7 @@ program ResolveField {
|
||||||
handler Inspect phase Update {
|
handler Inspect phase Update {
|
||||||
let position_property = world_prop_id("Position")
|
let position_property = world_prop_id("Position")
|
||||||
let column_field = world_field_id(position_property, "column")
|
let column_field = world_field_id(position_property, "column")
|
||||||
Screen.status(str(column_field))
|
Screen.status(string(column_field))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ program ReadField {
|
||||||
let column_field = world_field_id(position_property, "column")
|
let column_field = world_field_id(position_property, "column")
|
||||||
for (position) in query [Position, {Player}] {
|
for (position) in query [Position, {Player}] {
|
||||||
let value = world_get(self(), position_property, column_field)
|
let value = world_get(self(), position_property, column_field)
|
||||||
Screen.status(str(value))
|
Screen.status(string(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ program ResolveModel {
|
||||||
|
|
||||||
handler Inspect phase Update {
|
handler Inspect phase Update {
|
||||||
let player_model = world_model_id("Player")
|
let player_model = world_model_id("Player")
|
||||||
Screen.status(str(player_model))
|
Screen.status(string(player_model))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ program ResolveProperty {
|
||||||
|
|
||||||
handler Inspect phase Update {
|
handler Inspect phase Update {
|
||||||
let position_property = world_prop_id("Position")
|
let position_property = world_prop_id("Position")
|
||||||
Screen.status(str(position_property))
|
Screen.status(string(position_property))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ program ModComponent {
|
||||||
handler Boot phase Start {
|
handler Boot phase Start {
|
||||||
spawn Hero { Position { column: 4, row: 4 } }
|
spawn Hero { Position { column: 4, row: 4 } }
|
||||||
let stamina_property = world_register_prop("Stamina", 1)
|
let stamina_property = world_register_prop("Stamina", 1)
|
||||||
Screen.status(str(stamina_property))
|
Screen.status(string(stamina_property))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ program SnapshotOut {
|
||||||
if Input.key() == 's' {
|
if Input.key() == 's' {
|
||||||
let buffer = bytes(4096)
|
let buffer = bytes(4096)
|
||||||
let written = world_save(buffer)
|
let written = world_save(buffer)
|
||||||
Screen.status(str(written))
|
Screen.status(string(written))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ program Reinforcements {
|
||||||
if Input.key() == ' ' {
|
if Input.key() == ' ' {
|
||||||
let enemy_model = world_model_id("Enemy")
|
let enemy_model = world_model_id("Enemy")
|
||||||
let new_enemy = world_spawn(enemy_model)
|
let new_enemy = world_spawn(enemy_model)
|
||||||
Screen.status(str(new_enemy))
|
Screen.status(string(new_enemy))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,5 @@ The access operators reach into a compound value. `value.field` reads or writes
|
||||||
```ludic
|
```ludic
|
||||||
let head_column: int = segments[0].column
|
let head_column: int = segments[0].column
|
||||||
segments[0].column = head_column + 1
|
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)]
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ tip: Compare two values and yield a bool; on strings == compares contents.
|
||||||
order: 1
|
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 <b>by content</b>, 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 <b>by content</b>, 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
|
```ludic
|
||||||
if current_health <= 0 { become GameOver }
|
if current_health <= 0 { become GameOver }
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ tip: A backtick string with {expr} holes, each stringified and concatenated.
|
||||||
order: 7
|
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
|
```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)
|
Screen.status(status_line)
|
||||||
print(`wave {wave_number} incoming`)
|
print(`wave {wave_number} incoming`)
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ tip: Integer, hex, character, string, boolean, and null-pointer literals.
|
||||||
order: 8
|
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
|
```ludic
|
||||||
let sky_color: int = 0x1E90FF
|
let sky_color: int = 0x1E90FF
|
||||||
let banner: str = "GAME OVER"
|
let banner: string = "GAME OVER"
|
||||||
if Input.key() == 'w' { row = row - 1 }
|
if Input.key() == 'w' { row = row - 1 }
|
||||||
if next_segment == null { is_tail = true }
|
if next_segment == null { is_tail = true }
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ program Physics {
|
||||||
handler MeasureSpeed phase Update {
|
handler MeasureSpeed phase Update {
|
||||||
for (velocity) in query [Velocity, {Projectile}] {
|
for (velocity) in query [Velocity, {Projectile}] {
|
||||||
let speed = c_hypot(a: fx(velocity.delta_x), b: fx(velocity.delta_y))
|
let speed = c_hypot(a: fx(velocity.delta_x), b: fx(velocity.delta_y))
|
||||||
Screen.status(str(flr(speed)))
|
Screen.status(string(flr(speed)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: System.arg
|
||||||
category: system
|
category: system
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: System.arg
|
tokens: System.arg
|
||||||
sig: System.arg(i) -> str
|
sig: System.arg(i) -> string
|
||||||
tip: A command-line argument by index.
|
tip: A command-line argument by index.
|
||||||
order: 0
|
order: 0
|
||||||
ns: System
|
ns: System
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: System.env
|
||||||
category: system
|
category: system
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: System.env
|
tokens: System.env
|
||||||
sig: System.env(name) -> str
|
sig: System.env(name) -> string
|
||||||
tip: Read an environment variable.
|
tip: Read an environment variable.
|
||||||
order: 4
|
order: 4
|
||||||
ns: System
|
ns: System
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ title: Text
|
||||||
order: 6
|
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.
|
String queries and building over <code>string</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.
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ Parameters:
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program FirstIsDigit {
|
program FirstIsDigit {
|
||||||
var entry: str = "7up"
|
var entry: string = "7up"
|
||||||
|
|
||||||
handler Check phase Update {
|
handler Check phase Update {
|
||||||
let c = Text.char_at(entry, 0)
|
let c = Text.char_at(entry, 0)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: Text.concat
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.concat
|
tokens: Text.concat
|
||||||
sig: Text.concat(a, b) -> str
|
sig: Text.concat(a, b) -> string
|
||||||
tip: Join two strings into a new one.
|
tip: Join two strings into a new one.
|
||||||
order: 8
|
order: 8
|
||||||
ns: Text
|
ns: Text
|
||||||
|
|
@ -19,7 +19,7 @@ Parameters:
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program Greeting {
|
program Greeting {
|
||||||
var name: str = "world"
|
var name: string = "world"
|
||||||
|
|
||||||
handler Build phase Update {
|
handler Build phase Update {
|
||||||
let line = Text.concat("hello ", name) # "hello world"
|
let line = Text.concat("hello ", name) # "hello world"
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ Parameters:
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program Filter {
|
program Filter {
|
||||||
var line: str = "error: disk full"
|
var line: string = "error: disk full"
|
||||||
|
|
||||||
handler Scan phase Update {
|
handler Scan phase Update {
|
||||||
if Text.contains(line, "error") {
|
if Text.contains(line, "error") {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ Parameters:
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program IsImage {
|
program IsImage {
|
||||||
var filename: str = "hero.png"
|
var filename: string = "hero.png"
|
||||||
|
|
||||||
handler Classify phase Update {
|
handler Classify phase Update {
|
||||||
let png = Text.ends_with(filename, ".png") # true
|
let png = Text.ends_with(filename, ".png") # true
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ Parameters:
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program Guess {
|
program Guess {
|
||||||
var answer: str = "swordfish"
|
var answer: string = "swordfish"
|
||||||
var attempt: str = "swordfish"
|
var attempt: string = "swordfish"
|
||||||
|
|
||||||
handler Check phase Update {
|
handler Check phase Update {
|
||||||
if Text.equals(attempt, answer) {
|
if Text.equals(attempt, answer) {
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ name: Text.from_int
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.from_int
|
tokens: Text.from_int
|
||||||
sig: Text.from_int(n) -> str
|
sig: Text.from_int(n) -> string
|
||||||
tip: Render an integer as a string.
|
tip: Render an integer as a string.
|
||||||
order: 10
|
order: 10
|
||||||
ns: Text
|
ns: Text
|
||||||
member: from_int
|
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>.
|
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>string(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:
|
Parameters:
|
||||||
- `n` — the integer to render
|
- `n` — the integer to render
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ Parameters:
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program KeyValue {
|
program KeyValue {
|
||||||
var pair: str = "hp=42"
|
var pair: string = "hp=42"
|
||||||
|
|
||||||
handler Parse phase Update {
|
handler Parse phase Update {
|
||||||
let eq = Text.index_of(pair, "=") # 2
|
let eq = Text.index_of(pair, "=") # 2
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: Text.join
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.join
|
tokens: Text.join
|
||||||
sig: Text.join(parts, sep) -> str
|
sig: Text.join(parts, sep) -> string
|
||||||
tip: Join a list of strings with a separator.
|
tip: Join a list of strings with a separator.
|
||||||
order: 18
|
order: 18
|
||||||
ns: Text
|
ns: Text
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Parameters:
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program NameWidth {
|
program NameWidth {
|
||||||
var label: str = "player one"
|
var label: string = "player one"
|
||||||
|
|
||||||
handler Draw phase Render {
|
handler Draw phase Render {
|
||||||
let width = Text.length(label) * 6 # 6 px per glyph
|
let width = Text.length(label) * 6 # 6 px per glyph
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: Text.lower
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.lower
|
tokens: Text.lower
|
||||||
sig: Text.lower(s) -> str
|
sig: Text.lower(s) -> string
|
||||||
tip: A lowercased copy of a string.
|
tip: A lowercased copy of a string.
|
||||||
order: 12
|
order: 12
|
||||||
ns: Text
|
ns: Text
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: Text.pad_left
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.pad_left
|
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.
|
tip: Pad with spaces on the left to a width.
|
||||||
order: 15
|
order: 15
|
||||||
ns: Text
|
ns: Text
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: Text.pad_right
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.pad_right
|
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.
|
tip: Pad with spaces on the right to a width.
|
||||||
order: 16
|
order: 16
|
||||||
ns: Text
|
ns: Text
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: Text.repeat
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.repeat
|
tokens: Text.repeat
|
||||||
sig: Text.repeat(s, n) -> str
|
sig: Text.repeat(s, n) -> string
|
||||||
tip: A string repeated n times.
|
tip: A string repeated n times.
|
||||||
order: 14
|
order: 14
|
||||||
ns: Text
|
ns: Text
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: Text.replace
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.replace
|
tokens: Text.replace
|
||||||
sig: Text.replace(s, from, to) -> str
|
sig: Text.replace(s, from, to) -> string
|
||||||
tip: Replace every occurrence of a substring.
|
tip: Replace every occurrence of a substring.
|
||||||
order: 19
|
order: 19
|
||||||
ns: Text
|
ns: Text
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: Text.slice
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.slice
|
tokens: Text.slice
|
||||||
sig: Text.slice(s, a, b) -> str
|
sig: Text.slice(s, a, b) -> string
|
||||||
tip: A substring covering bytes [a, b).
|
tip: A substring covering bytes [a, b).
|
||||||
order: 2
|
order: 2
|
||||||
ns: Text
|
ns: Text
|
||||||
|
|
@ -20,7 +20,7 @@ Parameters:
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program FirstWord {
|
program FirstWord {
|
||||||
var line: str = "hello world"
|
var line: string = "hello world"
|
||||||
|
|
||||||
handler Split phase Update {
|
handler Split phase Update {
|
||||||
let space = Text.index_of(line, " ") # 5
|
let space = Text.index_of(line, " ") # 5
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,14 @@ name: Text.split
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.split
|
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.
|
tip: Split a string on a separator into a list.
|
||||||
order: 17
|
order: 17
|
||||||
ns: Text
|
ns: Text
|
||||||
member: split
|
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.
|
Splits <code>s</code> at every occurrence of the non-empty separator <code>sep</code> and returns the pieces as a <code>[]string</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
|
```ludic
|
||||||
program Demo {
|
program Demo {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ Parameters:
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program Command {
|
program Command {
|
||||||
var input: str = "/say hello"
|
var input: string = "/say hello"
|
||||||
|
|
||||||
handler Parse phase Update {
|
handler Parse phase Update {
|
||||||
if Text.starts_with(input, "/say ") {
|
if Text.starts_with(input, "/say ") {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Parameters:
|
||||||
|
|
||||||
```ludic
|
```ludic
|
||||||
program ParseAmount {
|
program ParseAmount {
|
||||||
var typed: str = "250"
|
var typed: string = "250"
|
||||||
|
|
||||||
handler Apply phase Update {
|
handler Apply phase Update {
|
||||||
let gold = Text.to_int(typed) # 250
|
let gold = Text.to_int(typed) # 250
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: Text.trim
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.trim
|
tokens: Text.trim
|
||||||
sig: Text.trim(s) -> str
|
sig: Text.trim(s) -> string
|
||||||
tip: A copy with surrounding whitespace removed.
|
tip: A copy with surrounding whitespace removed.
|
||||||
order: 13
|
order: 13
|
||||||
ns: Text
|
ns: Text
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ name: Text.upper
|
||||||
category: text
|
category: text
|
||||||
kind: namespace-method
|
kind: namespace-method
|
||||||
tokens: Text.upper
|
tokens: Text.upper
|
||||||
sig: Text.upper(s) -> str
|
sig: Text.upper(s) -> string
|
||||||
tip: An uppercased copy of a string.
|
tip: An uppercased copy of a string.
|
||||||
order: 11
|
order: 11
|
||||||
ns: Text
|
ns: Text
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ tip: A 64-bit signed integer for values that overflow a 32-bit int.
|
||||||
order: 1
|
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.
|
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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 <b>values</b>: `+` concatenates two of them and `==` / `!=` compare them <b>by content</b>, 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) }
|
|
||||||
```
|
|
||||||
18
docs/language/types/type-string.md
Normal file
18
docs/language/types/type-string.md
Normal file
|
|
@ -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 <b>values</b>: `+` concatenates two of them and `==` / `!=` compare them <b>by content</b>, 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) }
|
||||||
|
```
|
||||||
|
|
@ -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'
|
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 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 == 0 { return "SLIME" }
|
||||||
if et == 1 { return "SKELETON" }
|
if et == 1 { return "SKELETON" }
|
||||||
return "RIFT WARDEN"
|
return "RIFT WARDEN"
|
||||||
|
|
|
||||||
|
|
@ -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
|
# 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.
|
# 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>7222BB<ABDHDBA@@@@@@OAKEEAAAAIEECAA>AAAAA>NAAN@@@>AAAEB=NAANDBA>A@>1A>O444444AAAAAA>AAAAA:4AAAEEKAAA:4:AAAA:4444O1248@O"
|
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>7222BB<ABDHDBA@@@@@@OAKEEAAAAIEECAA>AAAAA>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 i = 0
|
||||||
var cx = x
|
var cx = x
|
||||||
var ch = s[0]
|
var ch = s[0]
|
||||||
|
|
@ -329,7 +329,7 @@ function rt_running() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---- writing the frame out ------------------------------------------------
|
# ---- 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 i = 0
|
||||||
var n = at
|
var n = at
|
||||||
var ch = s[0]
|
var ch = s[0]
|
||||||
|
|
@ -367,7 +367,7 @@ function rt_put_int(buf: ptr, at: int, v: int) -> int {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
function rt_dump_ppm(path: str) -> void {
|
function rt_dump_ppm(path: string) -> void {
|
||||||
let f = file_open(path, "wb")
|
let f = file_open(path, "wb")
|
||||||
if (f == null) { return }
|
if (f == null) { return }
|
||||||
|
|
||||||
|
|
@ -412,7 +412,7 @@ function rt_map_size(w: int, h: int) -> void {
|
||||||
fill(rt_map, 32, 96 * 64)
|
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 < 0 { return }
|
||||||
if y >= 64 { return }
|
if y >= 64 { return }
|
||||||
var x = 0
|
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.
|
# so it survives whatever the caller does with the original.
|
||||||
var rt_statusbuf: ptr = null
|
var rt_statusbuf: ptr = null
|
||||||
|
|
||||||
function rt_status(s: str) -> void {
|
function rt_status(s: string) -> void {
|
||||||
var i = 0
|
var i = 0
|
||||||
var ch = s[0]
|
var ch = s[0]
|
||||||
while ch != 0 {
|
while ch != 0 {
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ function png_tag(b: ptr, at: int, a: int, c: int, d: int, e: int) -> bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
function rt_read_file(path: str) -> ptr {
|
function rt_read_file(path: string) -> ptr {
|
||||||
let f = file_open(path, "rb")
|
let f = file_open(path, "rb")
|
||||||
if (f == null) { return null }
|
if (f == null) { return null }
|
||||||
file_seek(f, 0, 2)
|
file_seek(f, 0, 2)
|
||||||
|
|
@ -62,7 +62,7 @@ var png_w: int = 0
|
||||||
var png_h: int = 0
|
var png_h: int = 0
|
||||||
var png_px: words = null
|
var png_px: words = null
|
||||||
|
|
||||||
function rt_decode_png(path: str) -> bool {
|
function rt_decode_png(path: string) -> bool {
|
||||||
png_w = 0
|
png_w = 0
|
||||||
png_h = 0
|
png_h = 0
|
||||||
png_px = null
|
png_px = null
|
||||||
|
|
@ -227,7 +227,7 @@ function rt_decode_png(path: str) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---- images ---------------------------------------------------------------
|
# ---- images ---------------------------------------------------------------
|
||||||
function rt_image_load(path: str) -> int {
|
function rt_image_load(path: string) -> int {
|
||||||
if img_n >= IMG_MAX { return 0 - 1 }
|
if img_n >= IMG_MAX { return 0 - 1 }
|
||||||
if rt_decode_png(path) == false { return 0 - 1 }
|
if rt_decode_png(path) == false { return 0 - 1 }
|
||||||
let id = img_n
|
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) --------------------------------------------------
|
# ---- 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 spr_n >= SPR_MAX { return 0 - 1 }
|
||||||
if rt_decode_png(path) == false { return 0 - 1 }
|
if rt_decode_png(path) == false { return 0 - 1 }
|
||||||
let id = spr_n
|
let id = spr_n
|
||||||
|
|
@ -375,7 +375,7 @@ function rt_hexval(c: int) -> int {
|
||||||
return 0 - 1
|
return 0 - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function rt_sprites_load(path: str) -> void {
|
function rt_sprites_load(path: string) -> void {
|
||||||
let d = rt_read_file(path)
|
let d = rt_read_file(path)
|
||||||
if (d == null) { spr_n = 0; return }
|
if (d == null) { spr_n = 0; return }
|
||||||
let size = rt_file_len
|
let size = rt_file_len
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ function tt_pick_cmap(id: int, d: ptr, co: int) -> void {
|
||||||
tt_cfmt[id] = tt_u16(d, best)
|
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 }
|
if tt_n >= TT_MAX { return 0 - 1 }
|
||||||
let d = rt_read_file(path)
|
let d = rt_read_file(path)
|
||||||
if (d == null) { return 0 - 1 }
|
if (d == null) { return 0 - 1 }
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ function tt_glyph_get(font: int, cp: int, px: int) -> int {
|
||||||
# ---- UTF-8 ----------------------------------------------------------------
|
# ---- UTF-8 ----------------------------------------------------------------
|
||||||
var u8_next: int = 0 # byte index just past the codepoint last decoded
|
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]
|
let c = s[at]
|
||||||
var extra = 0 - 1
|
var extra = 0 - 1
|
||||||
if c < 128 { extra = 0 }
|
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 < 0 { return }
|
||||||
if font >= tt_n { return }
|
if font >= tt_n { return }
|
||||||
if px <= 0 { 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 < 0 { return 0 }
|
||||||
if font >= tt_n { return 0 }
|
if font >= tt_n { return 0 }
|
||||||
if px <= 0 { return 0 }
|
if px <= 0 { return 0 }
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ function rt_ui_set(i: int, k: int, v: int) -> void {
|
||||||
if k == K_SKIN { ui_skin[i] = v }
|
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 < 0 { return }
|
||||||
if i >= UI_MAX { return }
|
if i >= UI_MAX { return }
|
||||||
ui_text[i] = s
|
ui_text[i] = s
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ function rt_ui_clicked(id: int) -> bool {
|
||||||
return ui_fired[id] == 1
|
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 < 0 { return }
|
||||||
if id >= ui_n { return }
|
if id >= ui_n { return }
|
||||||
let base = id * 96
|
let base = id * 96
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,13 @@ var loc_ty: []ptr
|
||||||
var loc_mut: []int # 1 = mutable (var / param / loop-var), 0 = immutable (let)
|
var loc_mut: []int # 1 = mutable (var / param / loop-var), 0 = immutable (let)
|
||||||
var nloc: int = 0
|
var nloc: int = 0
|
||||||
var g_uses_str: bool = false # a `str + str` / `str == str` was emitted -> emit the prelude
|
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_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_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_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_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_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)
|
# loop targets for break/continue (innermost last)
|
||||||
var brk_lbl: []ptr
|
var brk_lbl: []ptr
|
||||||
|
|
|
||||||
|
|
@ -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_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_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_intstr { emit_int_str() } # @fn_int_str, for string(int) in interpolation
|
||||||
if g_uses_longstr { emit_long_str() } # @fn_long_str, for str(long) / long 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_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_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
|
if g_uses_textrt { emit_text_prelude() } # @fn_str_upper/lower/trim/repeat/pad builders
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ function to_long(v: Val) -> ptr {
|
||||||
function emit_str_op(op: ptr, a: Val, b: Val) -> Val {
|
function emit_str_op(op: ptr, a: Val, b: Val) -> Val {
|
||||||
g_uses_str = true
|
g_uses_str = true
|
||||||
if (op == ("+")) {
|
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})`)
|
let r = emit_bind(`call i32 @fn_str_eq(ptr {a.code}, ptr {b.code})`)
|
||||||
if (op == ("!=")) {
|
if (op == ("!=")) {
|
||||||
|
|
@ -411,12 +411,12 @@ function emit_call(e: Node) -> Val {
|
||||||
}
|
}
|
||||||
if (name == "len") { return emit_len(e) }
|
if (name == "len") { return emit_len(e) }
|
||||||
if (name == "push") { return emit_push(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])
|
let a = emit_expr(e.kids[0])
|
||||||
if (llty(a.ty) == "ptr") { return a }
|
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
|
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)
|
if (name == "print") { # print(x): a value + newline (string, long, or int)
|
||||||
let a = emit_expr(e.kids[0])
|
let a = emit_expr(e.kids[0])
|
||||||
|
|
@ -536,9 +536,9 @@ function emit_expr(e: Node) -> Val {
|
||||||
let lo = emit_expr(e.b)
|
let lo = emit_expr(e.b)
|
||||||
let hi = emit_expr(e.c)
|
let hi = emit_expr(e.c)
|
||||||
g_uses_strslice = true
|
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 e.kind == E_NEW {
|
||||||
if is_slice_ty(e.s) { return emit_new_slice(e.s) }
|
if is_slice_ty(e.s) { return emit_new_slice(e.s) }
|
||||||
return emit_new_struct(e.s)
|
return emit_new_struct(e.s)
|
||||||
|
|
|
||||||
|
|
@ -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")
|
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
|
# (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.
|
# buffer, prepends '-' for negatives, and returns a pointer into the buffer.
|
||||||
function emit_int_str() -> void {
|
function emit_int_str() -> void {
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ function emit_intrinsic(name: ptr, e: Node) -> Val {
|
||||||
let i = arg_code(e, 0)
|
let i = arg_code(e, 0)
|
||||||
let v = emit_bind("load ptr, ptr @L_argv")
|
let v = emit_bind("load ptr, ptr @L_argv")
|
||||||
let q = emit_bind(`getelementptr ptr, ptr {v}, i32 {i}`)
|
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") {
|
if (name == "exit") {
|
||||||
let n = arg_code(e, 0)
|
let n = arg_code(e, 0)
|
||||||
|
|
@ -79,7 +79,7 @@ function emit_intrinsic(name: ptr, e: Node) -> Val {
|
||||||
}
|
}
|
||||||
if (name == "getenv") {
|
if (name == "getenv") {
|
||||||
let n = arg_code(e, 0)
|
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).
|
# 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).
|
# peek32 / poke32 are `words` indexing now: w[i] and w[i] = v (see emit_index_addr).
|
||||||
|
|
|
||||||
|
|
@ -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_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 == "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 == "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
|
# 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_poll") { return val(emit_bind("call i32 @win_poll()"), "int") }
|
||||||
if (name == "win_running") { return val(emit_bind("call i32 @win_running()"), "bool") }
|
if (name == "win_running") { return val(emit_bind("call i32 @win_running()"), "bool") }
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# emit_text.ludic — the Text.* namespace over `str` (null-terminated byte
|
# emit_text.ludic — the Text.* namespace over `str` (null-terminated byte
|
||||||
# strings). The libc-backed queries (length/char_at/starts_with/ends_with/
|
# 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
|
# 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 {
|
function is_text_ns(meth: ptr) -> bool {
|
||||||
if (meth == "length") or (meth == "char_at") or (meth == "slice") { return true }
|
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 {
|
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])
|
let n = emit_expr(e.kids[0])
|
||||||
g_uses_intstr = true
|
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
|
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])
|
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
|
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 ==
|
if (meth == "equals") { # byte-wise equality, same as ==
|
||||||
let a = emit_expr(e.kids[0]); let b = emit_expr(e.kids[1])
|
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
|
if (meth == "concat") { # a + b, same as the + operator
|
||||||
let a = emit_expr(e.kids[0]); let b = emit_expr(e.kids[1])
|
let a = emit_expr(e.kids[0]); let b = emit_expr(e.kids[1])
|
||||||
g_uses_str = true
|
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])
|
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
|
if (meth == "upper") { # ASCII a-z -> A-Z, fresh string
|
||||||
g_uses_textrt = true
|
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
|
if (meth == "lower") { # ASCII A-Z -> a-z, fresh string
|
||||||
g_uses_textrt = true
|
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
|
if (meth == "trim") { # drop leading/trailing whitespace
|
||||||
g_uses_textrt = true
|
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
|
if (meth == "repeat") { # s repeated n times
|
||||||
g_uses_textrt = true
|
g_uses_textrt = true
|
||||||
let n = emit_expr(e.kids[1])
|
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
|
if (meth == "pad_left") { # pad with spaces to width, on the left
|
||||||
g_uses_textrt = true
|
g_uses_textrt = true
|
||||||
let w = emit_expr(e.kids[1])
|
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
|
if (meth == "pad_right") { # pad with spaces to width, on the right
|
||||||
g_uses_textrt = true
|
g_uses_textrt = true
|
||||||
let w = emit_expr(e.kids[1])
|
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`
|
if (meth == "replace") { # replace every `from` with `to`
|
||||||
g_uses_textrt2 = true
|
g_uses_textrt2 = true
|
||||||
let from = emit_expr(e.kids[1]); let to = emit_expr(e.kids[2])
|
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
|
g_uses_textrt2 = true
|
||||||
let sep = emit_expr(e.kids[1])
|
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
|
g_uses_textrt2 = true
|
||||||
let sep = emit_expr(e.kids[1])
|
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
|
if (meth == "contains") or (meth == "index_of") { # substring search
|
||||||
let sub = emit_expr(e.kids[1])
|
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:
|
# 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}
|
# program that uses them (g_uses_textrt2). Slices are the {data,len,cap}
|
||||||
# %LSlice with str (ptr) elements.
|
# %LSlice with str (ptr) elements.
|
||||||
function emit_text2_prelude() -> void {
|
function emit_text2_prelude() -> void {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# io.ludic — reading the input file and writing the output, plus tiny stdio.
|
# 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.
|
# 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")
|
let f = file_open(path, "rb")
|
||||||
if (f == null) { return null }
|
if (f == null) { return null }
|
||||||
file_seek(f, 0, 2)
|
file_seek(f, 0, 2)
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ declare void @win_close()
|
||||||
@.str10 = private unnamed_addr constant [2 x i8] c",\00"
|
@.str10 = private unnamed_addr constant [2 x i8] c",\00"
|
||||||
@.str11 = 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"
|
@.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"
|
@.str14 = private unnamed_addr constant [2 x i8] c"(\00"
|
||||||
@.str15 = 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"
|
@.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"
|
@.str599 = private unnamed_addr constant [24 x i8] c"getelementptr ptr, ptr \00"
|
||||||
@.str600 = private unnamed_addr constant [7 x i8] c", i32 \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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.str620 = private unnamed_addr constant [22 x i8] c"call ptr @getenv(ptr \00"
|
||||||
@.str621 = private unnamed_addr constant [2 x i8] c")\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"
|
@.str623 = private unnamed_addr constant [2 x i8] c"0\00"
|
||||||
@.str624 = private unnamed_addr constant [5 x i8] c"void\00"
|
@.str624 = private unnamed_addr constant [5 x i8] c"void\00"
|
||||||
@.str625 = private unnamed_addr constant [5 x i8] c"free\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"
|
@.str669 = private unnamed_addr constant [5 x i8] c"bool\00"
|
||||||
@.str670 = private unnamed_addr constant [11 x i8] c"game_title\00"
|
@.str670 = private unnamed_addr constant [11 x i8] c"game_title\00"
|
||||||
@.str671 = private unnamed_addr constant [12 x i8] c"@.gametitle\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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.str1141 = private unnamed_addr constant [7 x i8] c", i32 \00"
|
||||||
@.str1142 = 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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.str1152 = private unnamed_addr constant [7 x i8] c", ptr \00"
|
||||||
@.str1153 = private unnamed_addr constant [2 x i8] c")\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"
|
@.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"
|
@.str1156 = private unnamed_addr constant [22 x i8] c"call i64 @strlen(ptr \00"
|
||||||
@.str1157 = private unnamed_addr constant [2 x i8] c")\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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.str1186 = private unnamed_addr constant [7 x i8] c", i32 \00"
|
||||||
@.str1187 = private unnamed_addr constant [2 x i8] c")\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"
|
@.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"
|
@.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"
|
@.str1191 = private unnamed_addr constant [7 x i8] c", i32 \00"
|
||||||
@.str1192 = private unnamed_addr constant [8 x i8] c", i1 1)\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"
|
@.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"
|
@.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"
|
@.str1196 = private unnamed_addr constant [7 x i8] c", i32 \00"
|
||||||
@.str1197 = private unnamed_addr constant [8 x i8] c", i1 0)\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"
|
@.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"
|
@.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"
|
@.str1201 = private unnamed_addr constant [7 x i8] c", ptr \00"
|
||||||
@.str1202 = 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"
|
@.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"
|
@.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"
|
@.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"
|
@.str1207 = private unnamed_addr constant [7 x i8] c", ptr \00"
|
||||||
@.str1208 = private unnamed_addr constant [2 x i8] c")\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"
|
@.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"
|
@.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"
|
@.str1212 = private unnamed_addr constant [7 x i8] c", ptr \00"
|
||||||
@.str1213 = private unnamed_addr constant [2 x i8] c")\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"
|
@.str1215 = private unnamed_addr constant [9 x i8] c"contains\00"
|
||||||
@.str1216 = private unnamed_addr constant [9 x i8] c"index_of\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"
|
@.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"
|
@.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"
|
@.str3048 = private unnamed_addr constant [7 x i8] c", ptr \00"
|
||||||
@.str3049 = private unnamed_addr constant [2 x i8] c")\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"
|
@.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"
|
@.str3052 = private unnamed_addr constant [7 x i8] c", ptr \00"
|
||||||
@.str3053 = private unnamed_addr constant [2 x i8] c")\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"
|
@.str3467 = private unnamed_addr constant [4 x i8] c"int\00"
|
||||||
@.str3468 = private unnamed_addr constant [4 x i8] c"len\00"
|
@.str3468 = private unnamed_addr constant [4 x i8] c"len\00"
|
||||||
@.str3469 = private unnamed_addr constant [5 x i8] c"push\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"
|
@.str3471 = private unnamed_addr constant [4 x i8] c"ptr\00"
|
||||||
@.str3472 = private unnamed_addr constant [4 x i8] c"i64\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"
|
@.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"
|
@.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"
|
@.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"
|
@.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"
|
@.str3479 = private unnamed_addr constant [6 x i8] c"print\00"
|
||||||
@.str3480 = private unnamed_addr constant [4 x i8] c"ptr\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"
|
@.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"
|
@.str3611 = private unnamed_addr constant [7 x i8] c", i32 \00"
|
||||||
@.str3612 = 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"
|
@.str3613 = private unnamed_addr constant [2 x i8] c")\00"
|
||||||
@.str3614 = 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 [4 x i8] c"str\00"
|
@.str3615 = private unnamed_addr constant [7 x i8] c"string\00"
|
||||||
@.str3616 = private unnamed_addr constant [4 x i8] c"int\00"
|
@.str3616 = private unnamed_addr constant [4 x i8] c"int\00"
|
||||||
@.str3617 = private unnamed_addr constant [6 x i8] c"load \00"
|
@.str3617 = private unnamed_addr constant [6 x i8] c"load \00"
|
||||||
@.str3618 = private unnamed_addr constant [10 x i8] c", ptr @g_\00"
|
@.str3618 = private unnamed_addr constant [10 x i8] c", ptr @g_\00"
|
||||||
|
|
|
||||||
|
|
@ -68,15 +68,15 @@ function args_call(call: Node) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---- string interpolation --------------------------------------------------
|
# ---- 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.
|
# 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_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 {
|
function interp_add(acc: Node, part: Node) -> Node {
|
||||||
if acc == null { return part }
|
if acc == null { return part }
|
||||||
return mkbin("+", acc, part)
|
return mkbin("+", acc, part)
|
||||||
}
|
}
|
||||||
function interp_str(e: Node) -> Node { # wrap a hole in str(...)
|
function interp_str(e: Node) -> Node { # wrap a hole in string(...)
|
||||||
let c = node(E_CALL); let id = node(E_ID); id.s = "str"; c.a = id; push(c.kids, e); return c
|
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
|
function parse_hole(inner: ptr) -> Node { # re-lex+parse an embedded expression
|
||||||
let saved_toks = toks; let saved_pi = pi
|
let saved_toks = toks; let saved_pi = pi
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,6 @@ program T {
|
||||||
print(x == x) # 1
|
print(x == x) # 1
|
||||||
print(0 - sq) # -1000000000000 (unary negate stays 64-bit)
|
print(0 - sq) # -1000000000000 (unary negate stays 64-bit)
|
||||||
print(big) # 1000000
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ game Atlas {
|
||||||
|
|
||||||
# build "<DIR>/tile_%04d.png" without a formatter: the runtime's string
|
# build "<DIR>/tile_%04d.png" without a formatter: the runtime's string
|
||||||
# helpers write into a scratch buffer we own
|
# 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 buf = atlas_buf()
|
||||||
let n = rt_put_str(buf, 0, DIR)
|
let n = rt_put_str(buf, 0, DIR)
|
||||||
n = rt_put_str(buf, n, "/tile_")
|
n = rt_put_str(buf, n, "/tile_")
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
],
|
],
|
||||||
"builtins": [
|
"builtins": [
|
||||||
"fn-print",
|
"fn-print",
|
||||||
"fn-str",
|
"fn-string",
|
||||||
"fn-quit",
|
"fn-quit",
|
||||||
"fn-save",
|
"fn-save",
|
||||||
"fn-load",
|
"fn-load",
|
||||||
|
|
@ -327,7 +327,7 @@
|
||||||
"type-ptr",
|
"type-ptr",
|
||||||
"type-ptrs",
|
"type-ptrs",
|
||||||
"type-slices",
|
"type-slices",
|
||||||
"type-str",
|
"type-string",
|
||||||
"type-void",
|
"type-void",
|
||||||
"type-words"
|
"type-words"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ object LudicTokens {
|
||||||
val KEYWORD = LudicTokenType("KEYWORD")
|
val KEYWORD = LudicTokenType("KEYWORD")
|
||||||
val DECL_KEYWORD = LudicTokenType("DECL_KEYWORD") // game, component, system, function, ...
|
val DECL_KEYWORD = LudicTokenType("DECL_KEYWORD") // game, component, system, function, ...
|
||||||
val CLAUSE = LudicTokenType("CLAUSE") // phase, query, reads, writes, ...
|
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 PHASE = LudicTokenType("PHASE") // Start, Update, Render, ...
|
||||||
val BOOLEAN = LudicTokenType("BOOLEAN")
|
val BOOLEAN = LudicTokenType("BOOLEAN")
|
||||||
val BUILTIN = LudicTokenType("BUILTIN") // runtime surface + compiler intrinsics
|
val BUILTIN = LudicTokenType("BUILTIN") // runtime surface + compiler intrinsics
|
||||||
|
|
@ -52,7 +52,7 @@ object LudicVocabulary {
|
||||||
"enable", "disable", "match", "machine", "state", "become", "where",
|
"enable", "disable", "match", "machine", "state", "become", "where",
|
||||||
"and", "or", "not", "break", "continue", "new", "emit", "cancel"
|
"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 PHASES = setOf("Start", "Input", "FixedUpdate", "Update", "LateUpdate", "Render")
|
||||||
val WIDGETS = setOf("panel", "col", "row", "label", "button", "image", "spacer")
|
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",
|
"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_tick", "ui_render", "ui_clicked", "ui_set_text", "ui_set_int", "ui_focus",
|
||||||
"ui_focused", "ui_visible", "key", "reg", "set_reg", "self", "save", "load",
|
"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
|
// compiler intrinsics: the floor the Ludic-written runtime stands on
|
||||||
"bytes", "words", "resize", "free", "fill", "arg_count", "arg", "file_stderr", "file_stdout",
|
"bytes", "words", "resize", "free", "fill", "arg_count", "arg", "file_stderr", "file_stdout",
|
||||||
"offset",
|
"offset",
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@
|
||||||
{ "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|on)\\b" },
|
{ "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|on)\\b" },
|
||||||
{ "name": "keyword.other.ludic", "match": "\\b(import|extern)\\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": "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.boolean.ludic", "match": "\\b(true|false|null)\\b" },
|
||||||
{ "name": "constant.language.phase.ludic", "match": "\\b(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\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_<name> in runtime/native",
|
"comment": "the runtime surface — every name here resolves to rt_<name> in runtime/native",
|
||||||
"name": "support.function.builtin.ludic",
|
"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",
|
"comment": "compiler intrinsics — these lower straight to libc or the OS",
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@
|
||||||
{ "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|on)\\b" },
|
{ "name": "keyword.other.clause.ludic", "match": "\\b(phase|query|on)\\b" },
|
||||||
{ "name": "keyword.other.ludic", "match": "\\b(import|extern)\\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": "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.boolean.ludic", "match": "\\b(true|false|null)\\b" },
|
||||||
{ "name": "constant.language.phase.ludic", "match": "\\b(Start|Input|FixedUpdate|Update|LateUpdate|Render)\\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_<name> in runtime/native",
|
"comment": "the runtime surface — every name here resolves to rt_<name> in runtime/native",
|
||||||
"name": "support.function.builtin.ludic",
|
"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",
|
"comment": "compiler intrinsics — these lower straight to libc or the OS",
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ program LudicFmt {
|
||||||
const LT_ERR: int = 14
|
const LT_ERR: int = 14
|
||||||
|
|
||||||
# ---- tiny stdio + string helpers (self-contained) ----
|
# ---- tiny stdio + string helpers (self-contained) ----
|
||||||
function read_file(path: str) -> ptr {
|
function read_file(path: string) -> ptr {
|
||||||
let f = file_open(path, "rb")
|
let f = file_open(path, "rb")
|
||||||
if (f == null) { return null }
|
if (f == null) { return null }
|
||||||
file_seek(f, 0, 2)
|
file_seek(f, 0, 2)
|
||||||
|
|
|
||||||
|
|
@ -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
|
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 {
|
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 {
|
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")
|
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 (ns == "Text") {
|
||||||
if (meth == "length") { return "Text.length(s) -> int" }
|
if (meth == "length") { return "Text.length(s) -> int" }
|
||||||
if (meth == "char_at") { return "Text.char_at(s, i) -> 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 == "starts_with") { return "Text.starts_with(s, prefix) -> bool" }
|
||||||
if (meth == "ends_with") { return "Text.ends_with(s, suffix) -> bool" }
|
if (meth == "ends_with") { return "Text.ends_with(s, suffix) -> bool" }
|
||||||
if (meth == "contains") { return "Text.contains(s, sub) -> bool" }
|
if (meth == "contains") { return "Text.contains(s, sub) -> bool" }
|
||||||
if (meth == "index_of") { return "Text.index_of(s, sub) -> int" }
|
if (meth == "index_of") { return "Text.index_of(s, sub) -> int" }
|
||||||
if (meth == "equals") { return "Text.equals(a, b) -> bool" }
|
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 == "to_int") { return "Text.to_int(s) -> int" }
|
||||||
if (meth == "from_int") { return "Text.from_int(n) -> str" }
|
if (meth == "from_int") { return "Text.from_int(n) -> string" }
|
||||||
if (meth == "upper") { return "Text.upper(s) -> str" }
|
if (meth == "upper") { return "Text.upper(s) -> string" }
|
||||||
if (meth == "lower") { return "Text.lower(s) -> str" }
|
if (meth == "lower") { return "Text.lower(s) -> string" }
|
||||||
if (meth == "trim") { return "Text.trim(s) -> str" }
|
if (meth == "trim") { return "Text.trim(s) -> string" }
|
||||||
if (meth == "repeat") { return "Text.repeat(s, n) -> str" }
|
if (meth == "repeat") { return "Text.repeat(s, n) -> string" }
|
||||||
if (meth == "pad_left") { return "Text.pad_left(s, width) -> str" }
|
if (meth == "pad_left") { return "Text.pad_left(s, width) -> string" }
|
||||||
if (meth == "pad_right") { return "Text.pad_right(s, width) -> str" }
|
if (meth == "pad_right") { return "Text.pad_right(s, width) -> string" }
|
||||||
if (meth == "split") { return "Text.split(s, sep) -> []str" }
|
if (meth == "split") { return "Text.split(s, sep) -> []string" }
|
||||||
if (meth == "join") { return "Text.join(parts, sep) -> str" }
|
if (meth == "join") { return "Text.join(parts, sep) -> string" }
|
||||||
if (meth == "replace") { return "Text.replace(s, from, to) -> str" }
|
if (meth == "replace") { return "Text.replace(s, from, to) -> string" }
|
||||||
}
|
}
|
||||||
if (ns == "Hash") {
|
if (ns == "Hash") {
|
||||||
if (meth == "of") { return "Hash.of(s) -> int" }
|
if (meth == "of") { return "Hash.of(s) -> int" }
|
||||||
|
|
@ -1360,11 +1360,11 @@ program LudicLsp {
|
||||||
if (meth == "local_id") { return "Network.local_id() -> int" }
|
if (meth == "local_id") { return "Network.local_id() -> int" }
|
||||||
}
|
}
|
||||||
if (ns == "System") {
|
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 == "arg_count") { return "System.arg_count() -> int" }
|
||||||
if (meth == "exit") { return "System.exit(code)" }
|
if (meth == "exit") { return "System.exit(code)" }
|
||||||
if (meth == "run") { return "System.run(command) -> int" }
|
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 == "read_char") { return "System.read_char() -> int" }
|
||||||
if (meth == "file_open") { return "System.file_open(path, mode) -> ptr" }
|
if (meth == "file_open") { return "System.file_open(path, mode) -> ptr" }
|
||||||
if (meth == "file_read") { return "System.file_read(file, buf, n) -> int" }
|
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("fx", "fx(i: int) -> fixed")
|
||||||
badd("flr", "flr(f: fixed) -> int")
|
badd("flr", "flr(f: fixed) -> int")
|
||||||
badd("map_size", "map_size(w: int, h: 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("tile", "tile(x: int, y: int) -> int")
|
||||||
badd("clear", "clear(color: int)")
|
badd("clear", "clear(color: int)")
|
||||||
badd("present", "present()")
|
badd("present", "present()")
|
||||||
badd("fill_rect", "fill_rect(x: int, y: int, w: int, h: int, color: int)")
|
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("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("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("text_int", "text_int(x: int, y: int, n: int, color: int, scale: int)")
|
||||||
badd("font_load", "font_load(path: str) -> int")
|
badd("font_load", "font_load(path: string) -> int")
|
||||||
badd("text_ttf", "text_ttf(font: int, x: int, y: int, utf8: str, color: int, px: 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: str, px: int) -> int")
|
badd("text_w", "text_w(font: int, utf8: string, px: int) -> int")
|
||||||
badd("text_h", "text_h(font: int, 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", "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_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("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("png_load", "png_load(path: string) -> int")
|
||||||
badd("sprites_load", "sprites_load(path: str)")
|
badd("sprites_load", "sprites_load(path: string)")
|
||||||
badd("draw_sprite", "draw_sprite(id: int, x: int, y: int)")
|
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("draw_sprite_scaled", "draw_sprite_scaled(id: int, x: int, y: int, scale: int)")
|
||||||
badd("ui_build", "ui_build()")
|
badd("ui_build", "ui_build()")
|
||||||
|
|
@ -1433,7 +1433,7 @@ program LudicLsp {
|
||||||
badd("ui_tick", "ui_tick(key: int)")
|
badd("ui_tick", "ui_tick(key: int)")
|
||||||
badd("ui_render", "ui_render()")
|
badd("ui_render", "ui_render()")
|
||||||
badd("ui_clicked", "ui_clicked(id: int) -> bool")
|
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_set_int", "ui_set_int(id: int, n: int)")
|
||||||
badd("ui_focus", "ui_focus(id: int)")
|
badd("ui_focus", "ui_focus(id: int)")
|
||||||
badd("ui_focused", "ui_focused() -> int")
|
badd("ui_focused", "ui_focused() -> int")
|
||||||
|
|
@ -1444,15 +1444,15 @@ program LudicLsp {
|
||||||
badd("self", "self() -> entity")
|
badd("self", "self() -> entity")
|
||||||
badd("save", "save()")
|
badd("save", "save()")
|
||||||
badd("load", "load() -> bool")
|
badd("load", "load() -> bool")
|
||||||
badd("status", "status(s: str)")
|
badd("status", "status(s: string)")
|
||||||
badd("print", "print(x)")
|
badd("print", "print(x)")
|
||||||
badd("str", "str(x) -> str")
|
badd("string", "string(x) -> string")
|
||||||
badd("quit", "quit()")
|
badd("quit", "quit()")
|
||||||
badd("bytes", "bytes(n: int) -> ptr")
|
badd("bytes", "bytes(n: int) -> ptr")
|
||||||
badd("words", "words(n: int) -> words")
|
badd("words", "words(n: int) -> words")
|
||||||
badd("resize", "resize(p: ptr, n: int) -> ptr")
|
badd("resize", "resize(p: ptr, n: int) -> ptr")
|
||||||
badd("arg_count", "arg_count() -> int")
|
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_stderr", "file_stderr() -> ptr")
|
||||||
badd("file_stdout", "file_stdout() -> ptr")
|
badd("file_stdout", "file_stdout() -> ptr")
|
||||||
badd("free", "free(p: ptr)")
|
badd("free", "free(p: ptr)")
|
||||||
|
|
@ -1460,7 +1460,7 @@ program LudicLsp {
|
||||||
badd("offset", "offset(p: ptr, off: int) -> ptr")
|
badd("offset", "offset(p: ptr, off: int) -> ptr")
|
||||||
badd("as_fixed", "as_fixed(i: int) -> fixed")
|
badd("as_fixed", "as_fixed(i: int) -> fixed")
|
||||||
badd("as_int", "as_int(f: fixed) -> int")
|
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_read", "file_read(f: ptr, buf: ptr, n: int) -> int")
|
||||||
badd("file_write", "file_write(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")
|
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("read_char", "read_char() -> int")
|
||||||
badd("exit", "exit(code: int)")
|
badd("exit", "exit(code: int)")
|
||||||
badd("is_windowed", "is_windowed() -> bool")
|
badd("is_windowed", "is_windowed() -> bool")
|
||||||
badd("game_title", "game_title() -> str")
|
badd("game_title", "game_title() -> string")
|
||||||
badd("win_open", "win_open(title: str, w: int, h: int, scale: int)")
|
badd("win_open", "win_open(title: string, w: int, h: int, scale: int)")
|
||||||
badd("win_poll", "win_poll() -> int")
|
badd("win_poll", "win_poll() -> int")
|
||||||
badd("win_present", "win_present(px: ptr, w: int, h: int)")
|
badd("win_present", "win_present(px: ptr, w: int, h: int)")
|
||||||
badd("win_running", "win_running() -> bool")
|
badd("win_running", "win_running() -> bool")
|
||||||
|
|
@ -2287,7 +2287,7 @@ program LudicLsp {
|
||||||
}
|
}
|
||||||
function comp_types(o: Buf) -> void {
|
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, "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 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 {
|
function on_completion(msg: JVal, id: JVal) -> void {
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ enum {
|
||||||
LT_EOF, LT_NL, LT_COMMENT,
|
LT_EOF, LT_NL, LT_COMMENT,
|
||||||
LT_ID, /* a plain identifier */
|
LT_ID, /* a plain identifier */
|
||||||
LT_KW, /* a reserved word (see KEYWORDS) */
|
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_PHASE, /* Start Input FixedUpdate Update LateUpdate Render */
|
||||||
LT_BOOL, /* true false */
|
LT_BOOL, /* true false */
|
||||||
LT_INT, LT_FLOAT, LT_STR, LT_CHAR,
|
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
|
"and","or","not","break","continue","new","emit","cancel", 0
|
||||||
};
|
};
|
||||||
static const char* LUDIC_TYPES[] = {
|
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[] = {
|
static const char* LUDIC_PHASES[] = {
|
||||||
"Start","Input","FixedUpdate","Update","LateUpdate","Render", 0
|
"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."},
|
{"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."},
|
{"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_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."},
|
{"tile","tile(x: int, y: int) -> int","Tile code at a map cell."},
|
||||||
{"clear","clear(color: int)","Clear the framebuffer to a 0xRRGGBB colour."},
|
{"clear","clear(color: int)","Clear the framebuffer to a 0xRRGGBB colour."},
|
||||||
{"present","present()","Push the framebuffer to the window (or out.ppm when headless)."},
|
{"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."},
|
{"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."},
|
{"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."},
|
{"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."},
|
{"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."},
|
{"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: str, color: int, px: int)","Draw UTF-8 text with a TrueType font."},
|
{"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: str, px: int) -> int","Advance width of the string, in pixels."},
|
{"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."},
|
{"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","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_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."},
|
{"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."},
|
{"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: str)","Load the sprite sheet used by draw_sprite."},
|
{"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","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."},
|
{"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)."},
|
{"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_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_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_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_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_focus","ui_focus(id: int)","Move keyboard focus to a widget."},
|
||||||
{"ui_focused","ui_focused() -> int","Id of the focused 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."},
|
{"self","self() -> entity","The entity of the innermost query loop."},
|
||||||
{"save","save()","Write a binary snapshot of the whole ECS world."},
|
{"save","save()","Write a binary snapshot of the whole ECS world."},
|
||||||
{"load","load() -> bool","Restore the snapshot; false if there is none."},
|
{"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."},
|
{"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."},
|
{"quit","quit()","Stop the frame loop and exit."},
|
||||||
{0,0,0}
|
{0,0,0}
|
||||||
};
|
};
|
||||||
|
|
@ -157,7 +157,7 @@ static const LBuiltin LUDIC_INTRINSICS[] = {
|
||||||
{"offset","offset(p: ptr, off: int) -> ptr","Offset a pointer by bytes."},
|
{"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_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)."},
|
{"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_read","file_read(f: ptr, buf: ptr, n: int) -> int","fread."},
|
||||||
{"file_write","file_write(f: ptr, buf: ptr, n: int) -> int","fwrite."},
|
{"file_write","file_write(f: ptr, buf: ptr, n: int) -> int","fwrite."},
|
||||||
{"file_seek","file_seek(f: ptr, off: int, whence: int) -> int","fseek."},
|
{"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."},
|
{"exit","exit(code: int)","Terminate the process."},
|
||||||
{"is_windowed","is_windowed() -> bool","True when the build has a window."},
|
{"is_windowed","is_windowed() -> bool","True when the build has a window."},
|
||||||
{"game_title","game_title() -> str","The name from the `game` declaration."},
|
{"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_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_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."},
|
{"win_running","win_running() -> bool","False once the window has been closed."},
|
||||||
|
|
|
||||||
|
|
@ -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
|
# print the "== N passed, M failed ==" footer and return the process exit code
|
||||||
function report() -> int {
|
function report() -> int {
|
||||||
print("")
|
print("")
|
||||||
print(`== {str(PASS)} passed, {str(FAIL)} failed ==`)
|
print(`== {string(PASS)} passed, {string(FAIL)} failed ==`)
|
||||||
if (FAIL == 0) { return 0 }
|
if (FAIL == 0) { return 0 }
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ function cmd_test() -> int {
|
||||||
write_file("/tmp/x_cli_exit.ludic", "entry { exit(42) }\n")
|
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")
|
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") }
|
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()
|
return report()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ function cmd_test_tools() -> int {
|
||||||
} else { bad("formatter altered non-whitespace bytes") }
|
} else { bad("formatter altered non-whitespace bytes") }
|
||||||
|
|
||||||
# --- multi-byte characters must survive intact -----------------------------
|
# --- 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`) {
|
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")
|
ok("UTF-8 preserved byte for byte")
|
||||||
} else { bad("UTF-8 mangled") }
|
} else { bad("UTF-8 mangled") }
|
||||||
|
|
@ -111,10 +111,10 @@ function cmd_test_tools() -> int {
|
||||||
|
|
||||||
# --- --check exit status, for CI and pre-commit hooks ----------------------
|
# --- --check exit status, for CI and pre-commit hooks ----------------------
|
||||||
let chk1 = sh(`{fmt} --check -q /tmp/x_m.ludic`)
|
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`)
|
run(`{fmt} -w /tmp/x_m.ludic`)
|
||||||
let chk2 = sh(`{fmt} --check -q /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 ---------------------------
|
# --- 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")
|
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")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue