Adds support for backtick escaping in a raw string
This commit is contained in:
parent
b90b979856
commit
2e303aea73
|
@ -58,8 +58,9 @@ slope recognizes a few types, that are generally created and used dynamically:
|
|||
- as `#t` and `#f`
|
||||
- anything can be cast to bool with a `#t` value, except `#f` (the only truly falsy value without using `~bool`, see below)
|
||||
- `string`
|
||||
- anything in "quotes"
|
||||
- allows for backslash escapes within the quotes (for chars by number or shortcuts to tab, newline, etc)
|
||||
- anything in "quotes" is a standard string literal
|
||||
- allows for backslash escapes within the quotes (for chars by number or shortcuts to tab, newline, etc)
|
||||
- anything in `backticks` is a raw string literal, no escapes occur and strings can span multiple lines
|
||||
- `list`/`pair`
|
||||
- includes the empty list (null)
|
||||
- lists are the primary data structure
|
||||
|
|
19
helpers.go
19
helpers.go
|
@ -542,20 +542,29 @@ func createTimeFormatString(s string) string {
|
|||
|
||||
// Used by REPL to know if another input line
|
||||
// should be offered before parsing
|
||||
func stringParensMatch(s string) bool {
|
||||
func stringParensMatch(s string) (bool, bool) {
|
||||
count := 0
|
||||
inString := false
|
||||
prevPrev := rune(0)
|
||||
inrawString := false
|
||||
prev := ' '
|
||||
|
||||
for _, c := range s {
|
||||
switch c {
|
||||
case '(':
|
||||
if !inString && prev != '\'' {
|
||||
if !inString && !inrawString && prev != '\'' {
|
||||
count++
|
||||
}
|
||||
case ')':
|
||||
if !inString {
|
||||
if !inString && !inrawString {
|
||||
count--
|
||||
}
|
||||
case '`':
|
||||
if !inrawString {
|
||||
inrawString = true
|
||||
count++
|
||||
} else if prev != '\\' || (prev == '\\' && prevPrev == '\\') {
|
||||
inrawString = false
|
||||
count--
|
||||
}
|
||||
case '"':
|
||||
|
@ -570,12 +579,12 @@ func stringParensMatch(s string) bool {
|
|||
}
|
||||
|
||||
if count > 0 {
|
||||
return false
|
||||
return false, inrawString
|
||||
}
|
||||
|
||||
// If count is negative still return true, the
|
||||
// parser will handle erroring
|
||||
return true
|
||||
return true, inrawString
|
||||
}
|
||||
|
||||
func variadic(l []expression) int {
|
||||
|
|
|
@ -548,6 +548,8 @@ func eval(exp expression, en *env) (value expression) {
|
|||
}
|
||||
var text strings.Builder
|
||||
var cont bool
|
||||
var raw bool
|
||||
var match bool
|
||||
for {
|
||||
globalenv.vars[symbol("slope-interactive?")] = true
|
||||
if linerState != nil {
|
||||
|
@ -560,12 +562,14 @@ func eval(exp expression, en *env) (value expression) {
|
|||
if in == "uninspect" || in == "(uninspect)" {
|
||||
break
|
||||
}
|
||||
if len(strings.TrimSpace(in)) == 0 {
|
||||
if len(strings.TrimSpace(in)) == 0 && !raw {
|
||||
continue
|
||||
}
|
||||
text.WriteString(in)
|
||||
text.WriteRune('\n')
|
||||
if !stringParensMatch(text.String()) {
|
||||
|
||||
match, raw = stringParensMatch(text.String())
|
||||
if !match {
|
||||
cont = true
|
||||
} else {
|
||||
cont = false
|
||||
|
|
12
lexer.go
12
lexer.go
|
@ -47,11 +47,17 @@ func eatString(r *strings.Reader, delim rune) string {
|
|||
if err != nil {
|
||||
panic("Lexing error while eating string")
|
||||
}
|
||||
buf.WriteRune(c)
|
||||
if delim == '`' && c == delim && (escapeCount > 0 && escapeCount%2 != 0) {
|
||||
out := buf.String()
|
||||
buf.Reset()
|
||||
buf.WriteString(out[:len(out)-1])
|
||||
buf.WriteRune(c)
|
||||
} else {
|
||||
buf.WriteRune(c)
|
||||
}
|
||||
if c == delim && (escapeCount == 0 || escapeCount%2 == 0) {
|
||||
break
|
||||
} else if c == '\n' || (c != delim && r.Len() == 0) {
|
||||
fmt.Println(delim, c, r.Len())
|
||||
} else if (delim == '"' && c == '\n') || (c != delim && r.Len() == 0) {
|
||||
panic(fmt.Sprintf("Parse error: Unclosed string on line %d ", lexLine))
|
||||
}
|
||||
if c == '\\' {
|
||||
|
|
8
main.go
8
main.go
|
@ -141,6 +141,8 @@ func Repl() {
|
|||
|
||||
var text strings.Builder
|
||||
var cont bool
|
||||
var raw bool
|
||||
var match bool
|
||||
for {
|
||||
globalenv.vars[symbol("slope-interactive?")] = true
|
||||
if linerTerm != nil {
|
||||
|
@ -150,12 +152,14 @@ func Repl() {
|
|||
if initialTerm != nil {
|
||||
initialTerm.ApplyMode()
|
||||
}
|
||||
if len(strings.TrimSpace(in)) == 0 {
|
||||
if len(strings.TrimSpace(in)) == 0 && !raw {
|
||||
continue
|
||||
}
|
||||
text.WriteString(in)
|
||||
text.WriteRune('\n')
|
||||
if !stringParensMatch(text.String()) {
|
||||
|
||||
match, raw = stringParensMatch(text.String())
|
||||
if !match {
|
||||
cont = true
|
||||
} else {
|
||||
cont = false
|
||||
|
|
Loading…
Reference in New Issue