Skip to content

Commit

Permalink
Add support for single quotes and escape double quotes (#96)
Browse files Browse the repository at this point in the history
* Add support for single quotes and escape double quotes

Signed-off-by: Flipez <code@brauser.io>

* add single quote test

Signed-off-by: Flipez <code@brauser.io>

* please the linter

Signed-off-by: Flipez <code@brauser.io>

* update tests and docs

Signed-off-by: Flipez <code@brauser.io>
  • Loading branch information
Flipez authored Jul 24, 2022
1 parent abd3389 commit 321f478
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 5 deletions.
7 changes: 7 additions & 0 deletions docs/content/docs/literals/string.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ puts(s)
"ef"
"bcd"
"abCdEf"

// you can also use single quotes
'test "string" with doublequotes'

// and you can scape a double quote in a double quote string
"te\"st" == 'te"st'

```

## Literal Specific Methods
Expand Down
9 changes: 8 additions & 1 deletion docs/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@ puts(s)
"cdef"
"ef"
"bcd"
"abCdEf"`,
"abCdEf"
// you can also use single quotes
'test "string" with doublequotes'
// and you can scape a double quote in a double quote string
"te\"st" == 'te"st'
`,
LiteralMethods: string_methods,
DefaultMethods: default_methods}
create_doc("docs/templates/literal.md", "docs/content/docs/literals/string.md", tempData)
Expand Down
27 changes: 24 additions & 3 deletions lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ func (l *Lexer) NextToken() token.Token {
tok.Type = token.EOF
case '"':
tok.Type = token.STRING
tok.Literal = l.readString()
tok.Literal = l.readDoubleQuoteString()
case '\'':
tok.Type = token.STRING
tok.Literal = l.readSingleQuoteString()
default:
if isLetter(l.ch) {
tok.Literal = l.readIdentifier()
Expand Down Expand Up @@ -177,11 +180,29 @@ func (l *Lexer) NextToken() token.Token {
return tok
}

func (l *Lexer) readString() string {
func (l *Lexer) readDoubleQuoteString() string {
var escapedString string

for {
l.readChar()

if l.ch == '\\' && l.peekChar() == '"' {
l.readChar()
} else if l.ch == '"' || l.ch == 0 {
break
}

escapedString += string(l.ch)
}

return escapedString
}

func (l *Lexer) readSingleQuoteString() string {
position := l.position + 1
for {
l.readChar()
if l.ch == '"' || l.ch == 0 {
if l.ch == '\'' || l.ch == 0 {
break
}
}
Expand Down
15 changes: 14 additions & 1 deletion object/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,20 @@ func init() {
}

func (s *String) Type() ObjectType { return STRING_OBJ }
func (s *String) Inspect() string { return `"` + s.Value + `"` }
func (s *String) Inspect() string {
var output string

for _, char := range s.Value {
if char == '"' {
output += string('\\')
}

output += string(char)
}

return `"` + output + `"`
}

func (s *String) InvokeMethod(method string, env Environment, args ...Object) Object {
return objectMethodLookup(s, method, env, args)
}
Expand Down
4 changes: 4 additions & 0 deletions object/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ func TestStringObjectMethods(t *testing.T) {
{`2 * "test"`, "testtest"},
{`"test".to_json()`, `"test"`},
{`{"test": HTTP.new()}.to_json()`, `Error while marshal value: json: error calling MarshalJSON for type *object.Hash: unable to serialize value: "test"`},
{`"te\nst".size()`, 6},
{`"te\"st".size()`, 5},
{`'te\"st'.size()`, 6},
{`"te\"st" == 'te"st'`, true},
}

testInput(t, tests)
Expand Down

1 comment on commit 321f478

@vercel
Copy link

@vercel vercel bot commented on 321f478 Jul 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.