Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/scanner.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ static Token identifier(Scanner *scanner);
static Token number(Scanner *scanner);
static Token string(Scanner *scanner);
static void skipWhitespace(Scanner *scanner);
static Token interpolatedString(Scanner *scanner);

/**
* Initialize the scanner's state
Expand Down Expand Up @@ -111,6 +112,11 @@ Token scanToken(Scanner *scanner) {
return makeToken(scanner, TOKEN_MODULO);
case '"':
return string(scanner);
case '$':
if (match(scanner, '"')) {
return interpolatedString(scanner);
}
break;
}

return errorToken(scanner, "Unexpected character.");
Expand Down Expand Up @@ -277,6 +283,20 @@ static Token number(Scanner *scanner) {
return makeToken(scanner, TOKEN_NUMBER);
}

static Token interpolatedString(Scanner *scanner) {
while (peek(scanner) != '"' && !isAtEnd(scanner)) {
advance(scanner);
}

if (isAtEnd(scanner)) {
return errorToken(scanner, "Unterminated interpolated string.");
}

advance(scanner); // closing quote

return makeToken(scanner, TOKEN_INTERPOLATED_STRING);
}

static Token string(Scanner *scanner) {
TRACELN("scanner.string()");

Expand Down
2 changes: 2 additions & 0 deletions src/token.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ const char *tokenTypeToString(TokenType type) {
return "TOKEN_IDENTIFIER";
case TOKEN_STRING:
return "TOKEN_STRING";
case TOKEN_INTERPOLATED_STRING:
return "TOKEN_INTERPOLATED_STRING";
case TOKEN_NUMBER:
return "TOKEN_NUMBER";
case TOKEN_AND:
Expand Down
1 change: 1 addition & 0 deletions src/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef enum {
// Literals.
TOKEN_IDENTIFIER,
TOKEN_STRING,
TOKEN_INTERPOLATED_STRING,
TOKEN_NUMBER,
// Keywords.
TOKEN_AND,
Expand Down
3 changes: 3 additions & 0 deletions tests/strings/string_interpolation.lox
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
var name = "World";

print $"Hello {name}";
81 changes: 81 additions & 0 deletions tests/strings/string_interpolation.lox.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
== is ==
0000 2 OP_GET_GLOBAL 0 'typeof'
0002 | OP_GET_LOCAL 1
0004 | OP_CALL 1
0006 | OP_GET_LOCAL 2
0008 | OP_EQUAL
0009 | OP_RETURN
0010 3 OP_NIL
0011 | OP_RETURN
== is_function ==
0000 6 OP_GET_GLOBAL 0 'is'
0002 | OP_GET_LOCAL 1
0004 | OP_CONSTANT 1 'function'
0006 | OP_CALL 2
0008 | OP_RETURN
0009 7 OP_NIL
0010 | OP_RETURN
== is_number ==
0000 10 OP_GET_GLOBAL 0 'is'
0002 | OP_GET_LOCAL 1
0004 | OP_CONSTANT 1 'number'
0006 | OP_CALL 2
0008 | OP_RETURN
0009 11 OP_NIL
0010 | OP_RETURN
== is_string ==
0000 14 OP_GET_GLOBAL 0 'is'
0002 | OP_GET_LOCAL 1
0004 | OP_CONSTANT 1 'string'
0006 | OP_CALL 2
0008 | OP_RETURN
0009 15 OP_NIL
0010 | OP_RETURN
== is_bool ==
0000 18 OP_GET_GLOBAL 0 'is'
0002 | OP_GET_LOCAL 1
0004 | OP_CONSTANT 1 'bool'
0006 | OP_CALL 2
0008 | OP_RETURN
0009 19 OP_NIL
0010 | OP_RETURN
== is_nil ==
0000 22 OP_GET_GLOBAL 0 'is'
0002 | OP_GET_LOCAL 1
0004 | OP_CONSTANT 1 'nil'
0006 | OP_CALL 2
0008 | OP_RETURN
0009 23 OP_NIL
0010 | OP_RETURN
== is_empty ==
0000 26 OP_GET_GLOBAL 0 'is_string'
0002 | OP_GET_LOCAL 1
0004 | OP_CALL 1
0006 | OP_JUMP_IF_FALSE 6 -> 19
0009 | OP_POP
0010 | OP_GET_GLOBAL 1 'len'
0012 | OP_GET_LOCAL 1
0014 | OP_CALL 1
0016 | OP_CONSTANT 2 '0.000000'
0018 | OP_EQUAL
0019 | OP_RETURN
0020 27 OP_NIL
0021 | OP_RETURN
== <script> ==
0000 3 OP_CLOSURE 1 <fn is>
0002 | OP_DEFINE_GLOBAL 0 'is'
0004 7 OP_CLOSURE 3 <fn is_function>
0006 | OP_DEFINE_GLOBAL 2 'is_function'
0008 11 OP_CLOSURE 5 <fn is_number>
0010 | OP_DEFINE_GLOBAL 4 'is_number'
0012 15 OP_CLOSURE 7 <fn is_string>
0014 | OP_DEFINE_GLOBAL 6 'is_string'
0016 19 OP_CLOSURE 9 <fn is_bool>
0018 | OP_DEFINE_GLOBAL 8 'is_bool'
0020 23 OP_CLOSURE 11 <fn is_nil>
0022 | OP_DEFINE_GLOBAL 10 'is_nil'
0024 27 OP_CLOSURE 13 <fn is_empty>
0026 | OP_DEFINE_GLOBAL 12 'is_empty'
0028 28 OP_NIL
0029 | OP_RETURN
[line 3] Error at '$"Hello {name}"' (TOKEN_INTERPOLATED_STRING): Expect expression.
1 change: 1 addition & 0 deletions tests/strings/string_interpolation.lox.exit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
65
Empty file.
Loading