turbo-editors/turbo-golopublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-golo.git
git clone ssh://git@rickub.com/turbo-editors/turbo-golo.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

literals.go · 80 lines · 3.4 KBGo Blame HistoryRaw
📦 Turbo Golo d710c1b k33g 12h ago1package gololang
2
3// The quoted literals of Golo: "strings", """multi-line strings""" and
4// 'characters', and the one rule that governs all three — each runs to its
5// closing quote, wherever that quote is.
6
7import "rickub.com/turbo-editors/turbo-core/syntax"
8
9// multilineStringQuote opens and closes a multi-line string. Inside one the
10// lexer interprets nothing — no escape, no interpolation — so the only thing
11// that can end it is these three runes.
12const multilineStringQuote = `"""`
13
14// takeQuoted colours a "…" or '…' literal from its opening quote to its
15// closing one, and reports it as still open when the line ends first.
16//
17// Carrying it is the honest reading of the language. The interpreter reads a
18// string to its closing quote and nothing stops it at a newline, so a line
19// ending inside a literal is not broken source — it is a literal with a line
20// break in it — and stopping the colour at the line would draw the next line
21// as code the interpreter will never run as code.
22//
23// A character literal is read the same way, by the same loop in lexer.go, so
24// it is carried the same way. That a 'character' spanning lines is nonsense to
25// a reader is beside the point: the colour says what the interpreter will do.
26func takeQuoted(s *syntax.LineScanner, quote rune, class syntax.Class, ifOpen carry) carry {
27 start := s.Pos()
28 s.Advance(1) // the opening quote
29
30 closed := consumeQuoted(s, quote)
31 s.Emit(start, s.Pos(), class)
32 return stillOpen(closed, ifOpen)
33}
34
35// finishQuoted colours the rest of a literal opened on an earlier line, and
36// says whether it is still open at the end of this one.
37func finishQuoted(s *syntax.LineScanner, quote rune, class syntax.Class, ifOpen carry) carry {
38 closed := consumeQuoted(s, quote)
39 s.Emit(0, s.Pos(), class)
40 return stillOpen(closed, ifOpen)
41}
42
43// consumeQuoted runs to the closing quote, or to the end of the line, and
44// reports which it found.
45//
46// A backslash takes the rune after it out of consideration. That one rule
47// covers every escape the lexer knows — \n, \t, \r, \\, \", \', \0 and \xHH —
48// and the ones it does not, which it keeps as the character itself; all any of
49// them need from this scanner is that the rune after the backslash cannot
50// close the literal. A backslash that ends the line escapes the newline, which
51// the lexer also reads as part of the string, and the carry covers that.
52func consumeQuoted(s *syntax.LineScanner, quote rune) bool {
53 for !s.AtEnd() {
54 switch s.Peek(0) {
55 case '\\':
56 s.Advance(2)
57 case quote:
58 s.Advance(1)
59 return true
60 default:
61 s.Advance(1)
62 }
63 }
64 return false
65}
66
67// takeMultilineString colours a """…""" literal from its opening quotes to its
68// closing ones, and reports it as still open when the line ends first.
69//
70// syntax.OpenBlockComment is named for comments, and what it does is exactly
71// this: from an opener to the first closer, or to the end of the line, in one
72// class, with no escapes considered. A multi-line string in Golo has no
73// escapes either — the lexer appends every rune it meets until the three
74// quotes — so the helper is the right tool under a misleading name, and the
75// continuation on later lines goes through FinishBlockComment for the same
76// reason.
77func takeMultilineString(s *syntax.LineScanner) carry {
78 closed := syntax.OpenBlockComment(s, multilineStringQuote, multilineStringQuote, syntax.ClassString)
79 return stillOpen(closed, multilineStringOpen)
80}