diff options
| -rw-r--r-- | examples/colorful/colorful.tm | 2 | ||||
| -rw-r--r-- | examples/commands/commands.tm | 2 | ||||
| -rw-r--r-- | examples/http-server/http-server.tm | 12 | ||||
| -rw-r--r-- | examples/ini/ini.tm | 18 | ||||
| -rw-r--r-- | examples/log/log.tm | 16 | ||||
| -rw-r--r-- | examples/pthreads/pthreads.tm | 2 | ||||
| -rw-r--r-- | examples/tomo-install/tomo-install.tm | 2 | ||||
| -rw-r--r-- | examples/tomodeps/tomodeps.tm | 12 | ||||
| -rw-r--r-- | examples/wrap/wrap.tm | 10 | ||||
| -rw-r--r-- | src/environment.c | 4 | ||||
| -rw-r--r-- | src/parse.c | 61 | ||||
| -rw-r--r-- | src/stdlib/text.c | 37 | ||||
| -rw-r--r-- | test/lang.tm | 2 | ||||
| -rw-r--r-- | test/text.tm | 32 |
14 files changed, 97 insertions, 115 deletions
diff --git a/examples/colorful/colorful.tm b/examples/colorful/colorful.tm index 30f3fc12..9a8bbbba 100644 --- a/examples/colorful/colorful.tm +++ b/examples/colorful/colorful.tm @@ -5,7 +5,7 @@ HELP := " Usage: colorful [args...] [--by-line] [--files files...] " -CSI := "$\033[" +CSI := "\033[" use patterns diff --git a/examples/commands/commands.tm b/examples/commands/commands.tm index ace7deb5..d72398b9 100644 --- a/examples/commands/commands.tm +++ b/examples/commands/commands.tm @@ -28,7 +28,7 @@ struct ProgramResult(stdout:[Byte], stderr:[Byte], exit_type:ExitType) if status == 0 if text := Text.from_bytes(r.stdout) if trim_newline - text = text.without_suffix(\n) + text = text.without_suffix("\n") return text else return none return none diff --git a/examples/http-server/http-server.tm b/examples/http-server/http-server.tm index 3d72c1e8..5b73d1af 100644 --- a/examples/http-server/http-server.tm +++ b/examples/http-server/http-server.tm @@ -85,14 +85,14 @@ struct HTTPRequest(method:Text, path:Text, version:Text, headers:[Text], body:Te struct HTTPResponse(body:Text, status=200, content_type="text/plain", headers:{Text=Text}={}) func bytes(r:HTTPResponse -> [Byte]) body_bytes := r.body.bytes() - extra_headers := (++: "$k: $v$(\r\n)" for k,v in r.headers) or "" + extra_headers := (++: "$k: $v\r\n" for k,v in r.headers) or "" return " - HTTP/1.1 $(r.status) OK$\r - Content-Length: $(body_bytes.length + 2)$\r - Content-Type: $(r.content_type)$\r - Connection: close$\r + HTTP/1.1 $(r.status) OK\r + Content-Length: $(body_bytes.length + 2)\r + Content-Type: $(r.content_type)\r + Connection: close\r $extra_headers - $\r$\n + \r\n ".bytes() ++ body_bytes func _content_type(file:Path -> Text) diff --git a/examples/ini/ini.tm b/examples/ini/ini.tm index c24cb4b9..4dc27725 100644 --- a/examples/ini/ini.tm +++ b/examples/ini/ini.tm @@ -10,23 +10,23 @@ _HELP := " " func parse_ini(path:Path -> {Text={Text=Text}}) - text := path.read() or exit("Could not read INI file: $\[31;1]$(path)$\[]") + text := path.read() or exit("Could not read INI file: \[31;1]$(path)\[]") sections : @{Text=@{Text=Text}} current_section : @{Text=Text} # Line wraps: - text = text.replace_pattern($Pat/\{1 nl}{0+space}/, " ") + text = text.replace_pattern($Pat/\\{1 nl}{0+space}/, " ") for line in text.lines() line = line.trim() skip if line.starts_with(";") or line.starts_with("#") if line.matches_pattern($Pat/[?]/) - section_name := line.replace($Pat/[?]/, "\1").trim().lower() + section_name := line.replace($Pat/[?]/, "@1").trim().lower() current_section = @{} sections[section_name] = current_section else if line.matches_pattern($Pat/{..}={..}/) - key := line.replace_pattern($Pat/{..}={..}/, "\1").trim().lower() - value := line.replace_pattern($Pat/{..}={..}/, "\2").trim() + key := line.replace_pattern($Pat/{..}={..}/, "@1").trim().lower() + value := line.replace_pattern($Pat/{..}={..}/, "@2").trim() current_section[key] = value return {k=v[] for k,v in sections[]} @@ -46,8 +46,8 @@ func main(path:Path, key:Text?) section := keys[1].lower() section_data := data[section] or exit(" - Invalid section name: $\[31;1]$section$\[] - Valid names: $\[1]$(", ".join([k.quoted() for k in data.keys]))$\[] + Invalid section name: \[31;1]$section\[] + Valid names: \[1]$(", ".join([k.quoted() for k in data.keys]))\[] ") if keys.length < 2 or keys[2] == '*' say("$section_data") @@ -55,7 +55,7 @@ func main(path:Path, key:Text?) section_key := keys[2].lower() value := section_data[section_key] or exit(" - Invalid key: $\[31;1]$section_key$\[] - Valid keys: $\[1]$(", ".join([s.quoted() for s in section_data.keys]))$\[] + Invalid key: \[31;1]$section_key\[] + Valid keys: \[1]$(", ".join([s.quoted() for s in section_data.keys]))\[] ") say(value) diff --git a/examples/log/log.tm b/examples/log/log.tm index 9c3396e7..4b7893fd 100644 --- a/examples/log/log.tm +++ b/examples/log/log.tm @@ -16,24 +16,24 @@ func _timestamp(->Text) return c_str.as_text() func info(text:Text, newline=yes) - say("$\[2]⚫ $text$\[]", newline) + say("\[2]⚫ $text\[]", newline) for file in logfiles - file.append("$(_timestamp()) [info] $text$\n") + file.append("$(_timestamp()) [info] $text\n") func debug(text:Text, newline=yes) - say("$\[32]🟢 $text$\[]", newline) + say("\[32]🟢 $text\[]", newline) for file in logfiles - file.append("$(_timestamp()) [debug] $text$\n") + file.append("$(_timestamp()) [debug] $text\n") func warn(text:Text, newline=yes) - say("$\[33;1]🟡 $text$\[]", newline) + say("\[33;1]🟡 $text\[]", newline) for file in logfiles - file.append("$(_timestamp()) [warn] $text$\n") + file.append("$(_timestamp()) [warn] $text\n") func error(text:Text, newline=yes) - say("$\[31;1]🔴 $text$\[]", newline) + say("\[31;1]🔴 $text\[]", newline) for file in logfiles - file.append("$(_timestamp()) [error] $text$\n") + file.append("$(_timestamp()) [error] $text\n") func add_logfile(file:Path) logfiles.add(file) diff --git a/examples/pthreads/pthreads.tm b/examples/pthreads/pthreads.tm index 7f720d5a..fee7ce5d 100644 --- a/examples/pthreads/pthreads.tm +++ b/examples/pthreads/pthreads.tm @@ -91,7 +91,7 @@ func main() say_mutex := pthread_mutex_t.new() announce := func(speaker:Text, text:Text) do say_mutex.lock() - say("$\033[2m[$speaker]$\033[m $text") + say("\[2][$speaker]\[] $text") say_mutex.unlock() worker := pthread_t.new(func() diff --git a/examples/tomo-install/tomo-install.tm b/examples/tomo-install/tomo-install.tm index c7d752ee..d915b993 100644 --- a/examples/tomo-install/tomo-install.tm +++ b/examples/tomo-install/tomo-install.tm @@ -80,5 +80,5 @@ func main(paths:[Path]) fi ).get_output()!) - say("$\[1]Installed $url!$\[]") + say("\[1]Installed $url!\[]") diff --git a/examples/tomodeps/tomodeps.tm b/examples/tomodeps/tomodeps.tm index 1e6be615..5513290c 100644 --- a/examples/tomodeps/tomodeps.tm +++ b/examples/tomodeps/tomodeps.tm @@ -20,10 +20,10 @@ func _get_file_dependencies(file:Path -> |Dependency|) if lines := file.by_line() for line in lines if line.matches_pattern($Pat/use {..}.tm/) - file_import := Path.from_text(line.replace_pattern($Pat/use {..}/, "\1")).resolved(relative_to=file) + file_import := Path.from_text(line.replace_pattern($Pat/use {..}/, "@1")).resolved(relative_to=file) deps.add(Dependency.File(file_import)) else if line.matches_pattern($Pat/use {id}/) - module_name := line.replace_pattern($Pat/use {..}/, "\1") + module_name := line.replace_pattern($Pat/use {..}/, "@1") deps.add(Dependency.Module(module_name)) return deps[] @@ -64,17 +64,17 @@ func get_dependency_graph(dep:Dependency -> {Dependency=|Dependency|}) func _printable_name(dep:Dependency -> Text) when dep is Module(module) - return "$(\x1b)[34;1m$module$(\x1b)[m" + return "\[34;1]$module\[]" is File(f) f = f.relative_to((.)) if f.exists() return Text(f) else - return "$(\x1b)[31;1m$(f) (not found)$(\x1b)[m" + return "\[31;1]$f (not found)\[]" func _draw_tree(dep:Dependency, dependencies:{Dependency=|Dependency|}, already_printed:@|Dependency|, prefix="", is_last=yes) if already_printed.has(dep) - say(prefix ++ (if is_last then "└── " else "├── ") ++ _printable_name(dep) ++ " $\x1b[2m(recursive)$\x1b[m") + say(prefix ++ (if is_last then "└── " else "├── ") ++ _printable_name(dep) ++ " \[2](recursive)\[]") return say(prefix ++ (if is_last then "└── " else "├── ") ++ _printable_name(dep)) @@ -112,6 +112,6 @@ func main(files:[Text]) dependencies := get_dependency_graph(Module(arg)) draw_tree(Module(arg), dependencies) else - say("$\x1b[2mSkipping $arg$\x1b[m") + say("\[2]Skipping $arg\[]") skip diff --git a/examples/wrap/wrap.tm b/examples/wrap/wrap.tm index 1a29701f..bae01739 100644 --- a/examples/wrap/wrap.tm +++ b/examples/wrap/wrap.tm @@ -11,15 +11,15 @@ HELP := " --hyphen='-': The text to use for hyphenation " -UNICODE_HYPHEN := \{hyphen} +UNICODE_HYPHEN := "\{hyphen}" func unwrap(text:Text, preserve_paragraphs=yes, hyphen=UNICODE_HYPHEN -> Text) if preserve_paragraphs paragraphs := text.split($/{2+ nl}/) if paragraphs.length > 1 - return \n\n.join([unwrap(p, hyphen=hyphen, preserve_paragraphs=no) for p in paragraphs]) + return "\n\n".join([unwrap(p, hyphen=hyphen, preserve_paragraphs=no) for p in paragraphs]) - return text.replace($/$(hyphen)$(\n)/, "") + return text.replace("$(hyphen)\n", "") func wrap(text:Text, width:Int, min_split=3, hyphen="-" -> Text) if width <= 0 @@ -69,7 +69,7 @@ func wrap(text:Text, width:Int, min_split=3, hyphen="-" -> Text) if line != "" lines.insert(line) - return \n.join(lines) + return "\n".join(lines) func _can_fit_word(line:Text, letters:[Text], width:Int -> Bool; inline) if line == "" @@ -99,4 +99,4 @@ func main(files:[Path], width=80, inplace=no, min_split=3, rewrap=yes, hyphen=UN wrap(paragraph, width=width, min_split=min_split, hyphen=hyphen) ) - out.write(\n\n.join(wrapped_paragraphs[]) ++ \n) + out.write("\n\n".join(wrapped_paragraphs[]) ++ "\n") diff --git a/src/environment.c b/src/environment.c index 21d3db9b..8084758e 100644 --- a/src/environment.c +++ b/src/environment.c @@ -327,7 +327,7 @@ env_t *global_env(void) {"at", "Text$cluster", "func(text:Text, index:Int -> Text)"}, {"by_line", "Text$by_line", "func(text:Text -> func(->Text?))"}, {"by_split", "Text$by_split", "func(text:Text, delimiter='' -> func(->Text?))"}, - {"by_split_any", "Text$by_split_any", "func(text:Text, delimiters=\" $\\t\\r\\n\" -> func(->Text?))"}, + {"by_split_any", "Text$by_split_any", "func(text:Text, delimiters=' \\t\\r\\n' -> func(->Text?))"}, {"bytes", "Text$utf8_bytes", "func(text:Text -> [Byte])"}, {"caseless_equals", "Text$equal_ignoring_case", "func(a,b:Text, language='C' -> Bool)"}, {"codepoint_names", "Text$codepoint_names", "func(text:Text -> [Text])"}, @@ -351,7 +351,7 @@ env_t *global_env(void) {"right_pad", "Text$right_pad", "func(text:Text, count:Int, pad=' ', language='C' -> Text)"}, {"slice", "Text$slice", "func(text:Text, from=1, to=-1 -> Text)"}, {"split", "Text$split", "func(text:Text, delimiter='' -> [Text])"}, - {"split_any", "Text$split_any", "func(text:Text, delimiters=\" $\\t\\r\\n\" -> [Text])"}, + {"split_any", "Text$split_any", "func(text:Text, delimiters=' \\t\\r\\n' -> [Text])"}, {"starts_with", "Text$starts_with", "func(text,prefix:Text -> Bool)"}, {"title", "Text$title", "func(text:Text, language='C' -> Text)"}, {"to", "Text$to", "func(text:Text, last:Int -> Text)"}, diff --git a/src/parse.c b/src/parse.c index c31bea64..b9a695b9 100644 --- a/src/parse.c +++ b/src/parse.c @@ -147,7 +147,7 @@ static PARSER(parse_var); static PARSER(parse_when); static PARSER(parse_while); static PARSER(parse_deserialize); -static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open_quote, char close_quote, char open_interp); +static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open_quote, char close_quote, char open_interp, bool allow_escapes); // // Print a parse error and exit (or use the on_err longjmp) @@ -255,6 +255,24 @@ static const char *unescape(parse_ctx_t *ctx, const char **out) { char name[len+1]; memcpy(name, &escape[2], len); name[len] = '\0'; + + if (name[0] == 'U') { + for (char *p = &name[1]; *p; p++) { + if (!isxdigit(*p)) goto look_up_unicode_name; + } + // Unicode codepoints by hex + char *endptr = NULL; + long codepoint = strtol(name+1, &endptr, 16); + uint32_t ustr[2] = {codepoint, 0}; + size_t bufsize = 8; + uint8_t buf[bufsize]; + (void)u32_to_u8(ustr, bufsize, buf, &bufsize); + *endpos = escape + 3 + len; + return GC_strndup((char*)buf, bufsize); + } + + look_up_unicode_name:; + uint32_t codepoint = unicode_name_character(name); if (codepoint == UNINAME_INVALID) parser_err(ctx, escape, escape + 3 + len, @@ -265,16 +283,6 @@ static const char *unescape(parse_ctx_t *ctx, const char **out) { (void)u32_to_u8(&codepoint, 1, (uint8_t*)str, &u8_len); str[u8_len] = '\0'; return str; - } else if (escape[1] == 'U' && escape[2]) { - // Unicode codepoints by hex - char *endptr = NULL; - long codepoint = strtol(escape+2, &endptr, 16); - uint32_t ustr[2] = {codepoint, 0}; - size_t bufsize = 8; - uint8_t buf[bufsize]; - (void)u32_to_u8(ustr, bufsize, buf, &bufsize); - *endpos = endptr; - return GC_strndup((char*)buf, bufsize); } else if (escape[1] == 'x' && escape[2] && escape[3]) { // ASCII 2-digit hex char buf[] = {escape[2], escape[3], 0}; @@ -1187,7 +1195,7 @@ PARSER(parse_bool) { return NULL; } -ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open_quote, char close_quote, char open_interp) +ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open_quote, char close_quote, char open_interp, bool allow_escapes) { const char *pos = *out_pos; int64_t starting_indent = get_indent(ctx, pos); @@ -1203,7 +1211,7 @@ ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open if (chunk) { ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .cord=chunk); chunks = new(ast_list_t, .ast=literal, .next=chunks); - chunk = NULL; + chunk = CORD_EMPTY; } ++pos; ast_t *interp; @@ -1212,6 +1220,9 @@ ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open interp = expect(ctx, interp_start, &pos, parse_term_no_suffix, "I expected an interpolation term here"); chunks = new(ast_list_t, .ast=interp, .next=chunks); chunk_start = pos; + } else if (allow_escapes && *pos == '\\') { + const char *c = unescape(ctx, &pos); + chunk = CORD_cat(chunk, c); } else if (!leading_newline && *pos == open_quote && closing[(int)open_quote]) { // Nested pair begin if (get_indent(ctx, pos) == starting_indent) { ++depth; @@ -1266,35 +1277,22 @@ PARSER(parse_text) { const char *start = pos; const char *lang = NULL; - // Escape sequence, e.g. \r\n - if (*pos == '\\') { - CORD cord = CORD_EMPTY; - do { - const char *c = unescape(ctx, &pos); - cord = CORD_cat(cord, c); - // cord = CORD_cat_char(cord, c); - } while (*pos == '\\'); - return NewAST(ctx->file, start, pos, TextLiteral, .cord=cord); - } - char open_quote, close_quote, open_interp = '$'; if (match(&pos, "\"")) { // Double quote open_quote = '"', close_quote = '"', open_interp = '$'; } else if (match(&pos, "`")) { // Backtick open_quote = '`', close_quote = '`', open_interp = '$'; } else if (match(&pos, "'")) { // Single quote - open_quote = '\'', close_quote = '\'', open_interp = '\x03'; + open_quote = '\'', close_quote = '\'', open_interp = '$'; } else if (match(&pos, "$")) { // Customized strings lang = get_id(&pos); // $"..." or $@"...." static const char *interp_chars = "~!@#$%^&*+=\\?"; - if (match(&pos, "$")) { // Disable interpolation with $ + if (match(&pos, "$")) { // Disable interpolation with $$ open_interp = '\x03'; } else if (strchr(interp_chars, *pos)) { open_interp = *pos; ++pos; - } else if (*pos == '(') { - open_interp = '@'; // For shell commands } static const char *quote_chars = "\"'`|/;([{<"; if (!strchr(quote_chars, *pos)) @@ -1306,7 +1304,8 @@ PARSER(parse_text) { return NULL; } - ast_list_t *chunks = _parse_text_helper(ctx, &pos, open_quote, close_quote, open_interp); + bool allow_escapes = (open_quote != '`'); + ast_list_t *chunks = _parse_text_helper(ctx, &pos, open_quote, close_quote, open_interp, allow_escapes); return NewAST(ctx->file, start, pos, TextJoin, .lang=lang, .children=chunks); } @@ -2277,7 +2276,7 @@ PARSER(parse_inline_c) { if (!match(&pos, "(")) parser_err(ctx, start, pos, "I expected a '(' here"); chunks = new(ast_list_t, .ast=NewAST(ctx->file, pos, pos, TextLiteral, "({"), - .next=_parse_text_helper(ctx, &pos, '(', ')', '@')); + .next=_parse_text_helper(ctx, &pos, '(', ')', '@', false)); if (type) { REVERSE_LIST(chunks); chunks = new(ast_list_t, .ast=NewAST(ctx->file, pos, pos, TextLiteral, "; })"), .next=chunks); @@ -2286,7 +2285,7 @@ PARSER(parse_inline_c) { } else { if (!match(&pos, "{")) parser_err(ctx, start, pos, "I expected a '{' here"); - chunks = _parse_text_helper(ctx, &pos, '{', '}', '@'); + chunks = _parse_text_helper(ctx, &pos, '{', '}', '@', false); } return NewAST(ctx->file, start, pos, InlineCCode, .chunks=chunks, .type_ast=type); diff --git a/src/stdlib/text.c b/src/stdlib/text.c index 621de942..b3e9cebb 100644 --- a/src/stdlib/text.c +++ b/src/stdlib/text.c @@ -1352,12 +1352,9 @@ public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) int32_t quote_char = Text$get_grapheme(quotation_mark, 0); #define add_escaped(str) ({ if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[34;1m")); \ - if (!just_escaped) ret = concat2_assuming_safe(ret, Text("$")); \ ret = concat2_assuming_safe(ret, Text("\\" str)); \ - just_escaped = true; \ if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[0;35m")); }) TextIter_t state = NEW_TEXT_ITER_STATE(text); - bool just_escaped = false; // TODO: optimize for spans of non-escaped text for (int64_t i = 0; i < text.length; i++) { int32_t g = Text$get_grapheme_fast(&state, i); @@ -1371,21 +1368,11 @@ public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) case '\t': add_escaped("t"); break; case '\v': add_escaped("v"); break; case '\\': { - if (just_escaped) { - add_escaped("\\"); - } else { - ret = concat2_assuming_safe(ret, Text("\\")); - just_escaped = false; - } + add_escaped("\\"); break; } case '$': { - if (quote_char == '\'') { - ret = concat2_assuming_safe(ret, Text("$")); - just_escaped = false; - } else { - add_escaped("$"); - } + add_escaped("$"); break; } case '\x00' ... '\x06': case '\x0E' ... '\x1A': @@ -1397,7 +1384,6 @@ public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) ret = concat2_assuming_safe(ret, Text$from_strn(tmp, 2)); if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[0;35m")); - just_escaped = true; break; } default: { @@ -1405,7 +1391,6 @@ public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) ret = concat2_assuming_safe(ret, quotation_mark); } else { ret = concat2_assuming_safe(ret, Text$slice(text, I(i+1), I(i+1))); - just_escaped = false; } break; } @@ -1427,14 +1412,12 @@ public Text_t Text$as_text(const void *vtext, bool colorize, const TypeInfo_t *i Text_t text = *(Text_t*)vtext; // Figure out the best quotation mark to use: - bool has_dollar = false, has_double_quote = false, has_backtick = false, + bool has_double_quote = false, has_backtick = false, has_single_quote = false, needs_escapes = false; TextIter_t state = NEW_TEXT_ITER_STATE(text); for (int64_t i = 0; i < text.length; i++) { int32_t g = Text$get_grapheme_fast(&state, i); - if (g == '$') { - has_dollar = true; - } else if (g == '"') { + if (g == '"') { has_double_quote = true; } else if (g == '`') { has_backtick = true; @@ -1444,15 +1427,15 @@ public Text_t Text$as_text(const void *vtext, bool colorize, const TypeInfo_t *i } Text_t quote; - // If there's dollar signs and/or double quotes in the string, it would - // be nice to avoid needing to escape them by using single quotes, but - // only if we don't have single quotes or need to escape anything else - // (because single quotes don't have interpolation): - if ((has_dollar || has_double_quote) && !has_single_quote && !needs_escapes) + // If there's double quotes in the string, it would be nice to avoid + // needing to escape them by using single quotes, but only if we don't have + // single quotes or need to escape anything else (because single quotes + // don't have interpolation): + if (has_double_quote && !has_single_quote) quote = Text("'"); // If there is a double quote, but no backtick, we can save a bit of // escaping by using backtick instead of double quote: - else if (has_double_quote && !has_backtick) + else if (has_double_quote && has_single_quote && !has_backtick && !needs_escapes) quote = Text("`"); // Otherwise fall back to double quotes as the default quoting style: else diff --git a/test/lang.tm b/test/lang.tm index 081438ed..21b70f96 100644 --- a/test/lang.tm +++ b/test/lang.tm @@ -47,7 +47,7 @@ func main() = $HTML"<p>Hello I <3 hax!</p>" >> Text(html) - = '$HTML"Hello I <3 hax!"' + = '\$HTML"Hello I <3 hax!"' >> b := Bold("Some <text> with junk") >> $HTML"Your text: $b" diff --git a/test/text.tm b/test/text.tm index 1cabbdea..812ecd3f 100644 --- a/test/text.tm +++ b/test/text.tm @@ -34,22 +34,22 @@ func main() >> str[9] = "é" - >> \UE9 + >> "\{UE9}" = "é" - >> \U65\U301 + >> "\{U65}\{U301}" = "é" - >> \{Penguin}.codepoint_names() + >> "\{Penguin}".codepoint_names() = ["PENGUIN"] - >> \[31;1] - = "$\e[31;1m" + >> "\[31;1]" + = "\e[31;1m" - >> \UE9 == \U65\U301 + >> "\{UE9}" == "\{U65}\{U301}" = yes - amelie := "Am$(\UE9)lie" + amelie := "Am\{UE9}lie" >> amelie.split() = ["A", "m", "é", "l", "i", "e"] >> amelie.utf32_codepoints() @@ -61,7 +61,7 @@ func main() >> Text.from_bytes([Byte(0xFF)]) = none - amelie2 := "Am$(\U65\U301)lie" + amelie2 := "Am\{U65}\{U301}lie" >> amelie2.split() = ["A", "m", "é", "l", "i", "e"] >> amelie2.utf32_codepoints() @@ -98,20 +98,20 @@ func main() line one line two " - = "line one$\nline two" + = "line one\nline two" say("Interpolation tests:") >> "A $(1+2)" = "A 3" - >> 'A $(1+2)' - = 'A $(1+2)' + >> "A \$(1+2)" + = "A \$(1+2)" >> `A $(1+2)` = "A 3" >> $"A $(1+2)" = "A 3" >> $$"A $(1+2)" - = 'A $(1+2)' + = "A \$(1+2)" >> $="A =(1+2)" = "A 3" >> ${one {nested} two $(1+2)} @@ -127,13 +127,13 @@ func main() >> c == Text.from_bytes(c.bytes())! = yes - >> "one$(\n)two$(\n)three".lines() + >> "one\ntwo\nthree".lines() = ["one", "two", "three"] - >> "one$(\n)two$(\n)three$(\n)".lines() + >> "one\ntwo\nthree\n".lines() = ["one", "two", "three"] - >> "one$(\n)two$(\n)three$(\n\n)".lines() + >> "one\ntwo\nthree\n\n".lines() = ["one", "two", "three", ""] - >> "one$(\r\n)two$(\r\n)three$(\r\n)".lines() + >> "one\r\ntwo\r\nthree\r\n".lines() = ["one", "two", "three"] >> "".lines() = [] |
