---
title: "Lexical Structure"
description: "Identifiers, contextual keywords, and element type names in the Slint language."
---
import SC from '@slint/common-files/src/components/SC.astro';

<SC>
## Tokens

After whitespace and comments are removed (see [Source Files](../source-files/)),
the remaining input is a sequence of tokens.
The token kinds are tried in a fixed order and the first that matches at the current position is taken,
so an input that could be read as either a number or an identifier is a number. \{#sls.lex.tokens}

## Numbers

A number begins with a decimal digit (`U+0030`–`U+0039`),
and consists of one or more decimal digits, an optional fractional part introduced by a `U+002E` (FULL STOP, `.`),
and an optional suffix that is either a sequence of ASCII letters (a unit)
or a single `U+0025` (PERCENT SIGN, `%`). \{#sls.lex.number}

## Identifiers

An identifier is a token that is not a [number](#sls.lex.number).
Its characters have the Unicode identifier properties defined by
Unicode Standard Annex #31: \{#sls.lex.identifier.classes}

- The first character shall have the `XID_Start` property or be `U+005F` (LOW LINE, `_`).
- Each subsequent character shall have the `XID_Continue` property or be `U+002D` (HYPHEN-MINUS, `-`).
- A character with neither property is not part of an identifier.

A decimal digit has the `XID_Continue` property but not `XID_Start`,
so it may appear in an identifier but not as its first character;
a token that begins with a digit is a number. \{#sls.lex.identifier.no-leading-digit}

A `U+002D` (`-`) shall not appear as the first character of an identifier. \{#sls.lex.identifier.no-leading-hyphen}

## Identifier Normalization

Two identifiers are considered the same if and only if their *normalized forms* are equal.
The normalized form of an identifier is obtained by applying the following replacements over the characters of the source identifier: \{#sls.lex.identifier.normalization}

- Each `U+005F` (`_`) is replaced with `U+002D` (`-`), except as the first character.
- All other characters are left unchanged.

For example, `foo_bar` and `foo-bar` are the same identifier, and so are `_foo_bar` and `_foo-bar`. \{#sls.lex.identifier.normalization-example}

The kebab-case form (with `U+002D`) is the canonical written form. \{#sls.lex.identifier.canonical-form}

## Contextual Keywords

Slint has no globally reserved words.
Each language construct is introduced by a *contextual keyword*: an identifier that has a special meaning only when it appears in a position where the grammar expects that construct. \{#sls.lex.contextual-keywords}
</SC>

:::note[The @ sigil]
The `@` character introduces a fixed set of built-in constructs that can't be declared, each with its own parsing rules.
Writing any other name after `@` is an error.
The constructs are:

- [`@tr`](../../../guide/development/translations/) marks a string for translation.
- [`@image-url`](../../property-types/images/#image), [`@markdown`](../../property-types/strings/#styled-text), and [`@keys`](../../property-types/other-types/#keys) build an `image`, `styled-text`, or `keys` value.
- [`@linear-gradient`, `@radial-gradient`, and `@conic-gradient`](../../property-types/colors-and-brushes/) build a gradient `brush`.
- [`@children`](../container-components/) marks where a container component places its children.
:::