module Strings {
// STRING AND CHARACTER BASICS
// Strings are modeled as an array of characters, but are stored in
// UTF-8 format in memory.
//
// Strings are immutable.
//
// Characters in a string are of type char, which is a numeric
// type corresponding to a UNICODE "scalar", with values in the
// range 0..0x10FFFF, except surrogates 0xD800 to 0xDFFF
//
// Strings are written between double quotes ("), and characters
// are written between single quotes '.
fn test1() {
let s : string = "hello";
let c : char = 'h';
}
// STRING AND CHARACTER ESCAPES
// Strings and character literals support "escaped" characters that are
// preceeded by backslash (\).
//
// The escape \u{n} allows a UNICODE character value n using 1-6 hex digits.
//
// The following additional escapes are supported for string and char:
//
// shortcut equivalent
// \0 \u{0}
// \n \u{a}
// \r \u{d}
// \t \u{9}
// \f \u{c}
// \v \u{b}
// \\ \u{5c} (backslash)
// \xNN \u{NN} (NN represents 2 hex digits)
//
// The following escapes are specific to string:
//
// shortcut equivalent
// \" \u{22} (double quote)
//
// The following escapes are specific to char:
//
// shortcut equivalent
// \' \u{27} (single quote)
// \$ \u{24} (dollar sign)
fn test2() {
let snowman = '\u{2603}'; // snowman character
let newlines = "abc\ndef"; // string with newline (\n)
}
// CHARACTER MATH
// Characters are numeric type, so they support addition, subtraction, etc.
// An exception will be thrown if the resulting of a math operation is not within
// the value defined for a UNICODE "scalar".
fn test3() {
let c1 = '9' - '0'; // 9
let c2 = 'a' + 1; // 'b'
let c3 = '\u{D7FF}' + 1; // exception: character out of range
}
// ACCESSING CHARACTERS IN STRINGS
// A string s can be accessed by character index i using s[i]
fn test4() {
let s = "abc";
let c = s[1]; // b
}
// STRING LENGTH
// The length of a string s is accessed using s#. The result is the count
// of characters in the string. Strings are not \0 terminated.
fn test5() {
let s = "abc\n";
let l = s#; // 4
}
// STRING INTERPOLATION
// To insert values in a string, use ${x}, where x is an expression. If
// x is not of type string, then the format method must be defined for
// the type of x, which will turn the value into a string.
fn test6() {
let s1 = "def";
let i1 = 123;
let s2 = "abc${s1}${i1}"; // "abcdef123"
}
// STRING SEQUENCE
// A given string constant must be on a single line, but multiple string
// constants listed after each other will form a single string.
fn test7() {
let one_string =
"abc" "def"
"ghi"; // "abcdefghi"
}
// STRING PARTS
// By default, a string constant produces a value of type string. By prefixing
// the string with $, the string constant will produce an array of string
// parts. A "string part" is defined as follows:
//
// union StrPart{T} {
// StrLit{lit : string} // a constant string
// StrVal{val : T} // a value x inserted with ${x}
// StrBrk{}; // a \ that appears between strings
// }
//
// This provides a way for custom handling of the values inserted in the
// string, for example for escaping or other custom processing (HTML, SQL, etc.)
fn test8() {
let s1 = "def";
let i1 = 123;
// since the string is preceeded by $, the value produced is an array
// of StrPart, where each element corresponds to either a string constant
// or a value inserted.
let s2 = $"abc${s1}${i1}"; // [StrLit("abc"), StrVal("def"), StrVal(123)]
}
// STRING BREAKS
// When using string parts, a "break" can be inserted between strings
// by using \. This will produce a StrBrk part. The meaning of
// can be interpreted by custom processing, but it could be replaced
// by a newline, for example.
fn test9() {
let s1 = $
"abc" \ "def" \
"ghi" "jkl"; // [StrLit("abc"), StrBrk, StrLit("def"), StrBrk, StrLit("ghijkl")]
}
}