-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
StringLiteral
#4
Changes from all commits
b6af384
6d8e517
f56c6dd
e158033
d2d3efd
53ae450
0b5d70f
a1df2c7
4e4d434
3d70d3b
ba4c745
60ceb41
bc76e30
c5e8220
ead71e2
b04fc8a
191b18c
0958d11
65a3270
282af71
d8cae0e
de468a7
459e037
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
"var s = 1" | ||
"var s = 1;\nvar n = 'test'" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
[] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"var singleQuote = 'singleQuote';\nvar doubleQuote = \"doubleQuote\";\nvar escapedSingleQuote = 'escapedSingle\\'Quote';\nvar escapedDoubleQuote = \"escapedDouble\\\"Quote\";\nvar escapedB = 'escaped\\nB';\nvar escapedT = 'escaped\\nT';\nvar escapedN = 'escaped\\nN';\nvar escapedR = 'escaped\\nR'" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
{ | ||
"locals": { | ||
"singleQuote": [ | ||
{ | ||
"kind": "Var", | ||
"pos": 3 | ||
} | ||
], | ||
"doubleQuote": [ | ||
{ | ||
"kind": "Var", | ||
"pos": 36 | ||
} | ||
], | ||
"escapedSingleQuote": [ | ||
{ | ||
"kind": "Var", | ||
"pos": 69 | ||
} | ||
], | ||
"escapedDoubleQuote": [ | ||
{ | ||
"kind": "Var", | ||
"pos": 118 | ||
} | ||
], | ||
"escapedB": [ | ||
{ | ||
"kind": "Var", | ||
"pos": 167 | ||
} | ||
], | ||
"escapedT": [ | ||
{ | ||
"kind": "Var", | ||
"pos": 196 | ||
} | ||
], | ||
"escapedN": [ | ||
{ | ||
"kind": "Var", | ||
"pos": 225 | ||
} | ||
], | ||
"escapedR": [ | ||
{ | ||
"kind": "Var", | ||
"pos": 254 | ||
} | ||
] | ||
}, | ||
"statements": [ | ||
{ | ||
"kind": "Var", | ||
"name": { | ||
"kind": "Identifier", | ||
"text": "singleQuote" | ||
}, | ||
"init": { | ||
"kind": "StringLiteral", | ||
"value": "singleQuote", | ||
"isSingleQuote": true | ||
} | ||
}, | ||
{ | ||
"kind": "Var", | ||
"name": { | ||
"kind": "Identifier", | ||
"text": "doubleQuote" | ||
}, | ||
"init": { | ||
"kind": "StringLiteral", | ||
"value": "doubleQuote", | ||
"isSingleQuote": false | ||
} | ||
}, | ||
{ | ||
"kind": "Var", | ||
"name": { | ||
"kind": "Identifier", | ||
"text": "escapedSingleQuote" | ||
}, | ||
"init": { | ||
"kind": "StringLiteral", | ||
"value": "escapedSingle'Quote", | ||
"isSingleQuote": true | ||
} | ||
}, | ||
{ | ||
"kind": "Var", | ||
"name": { | ||
"kind": "Identifier", | ||
"text": "escapedDoubleQuote" | ||
}, | ||
"init": { | ||
"kind": "StringLiteral", | ||
"value": "escapedDouble\"Quote", | ||
"isSingleQuote": false | ||
} | ||
}, | ||
{ | ||
"kind": "Var", | ||
"name": { | ||
"kind": "Identifier", | ||
"text": "escapedB" | ||
}, | ||
"init": { | ||
"kind": "StringLiteral", | ||
"value": "escaped\nB", | ||
"isSingleQuote": true | ||
} | ||
}, | ||
{ | ||
"kind": "Var", | ||
"name": { | ||
"kind": "Identifier", | ||
"text": "escapedT" | ||
}, | ||
"init": { | ||
"kind": "StringLiteral", | ||
"value": "escaped\nT", | ||
"isSingleQuote": true | ||
} | ||
}, | ||
{ | ||
"kind": "Var", | ||
"name": { | ||
"kind": "Identifier", | ||
"text": "escapedN" | ||
}, | ||
"init": { | ||
"kind": "StringLiteral", | ||
"value": "escaped\nN", | ||
"isSingleQuote": true | ||
} | ||
}, | ||
{ | ||
"kind": "Var", | ||
"name": { | ||
"kind": "Identifier", | ||
"text": "escapedR" | ||
}, | ||
"init": { | ||
"kind": "StringLiteral", | ||
"value": "escaped\nR", | ||
"isSingleQuote": true | ||
} | ||
}, | ||
{ | ||
"kind": "EmptyStatement" | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import { Token, Lexer } from './types'; | ||
import { Token, Lexer, CharCodes } from './types'; | ||
|
||
const keywords = { | ||
function: Token.Function, | ||
|
@@ -11,12 +11,14 @@ export function lex(s: string): Lexer { | |
let pos = 0; | ||
let text = ''; | ||
let token = Token.BOF; | ||
let firstChar: string; | ||
|
||
return { | ||
scan, | ||
token: () => token, | ||
pos: () => pos, | ||
text: () => text, | ||
isSingleQuote: () => firstChar === "'", | ||
}; | ||
|
||
function scan() { | ||
|
@@ -40,6 +42,10 @@ export function lex(s: string): Lexer { | |
text in keywords | ||
? keywords[text as keyof typeof keywords] | ||
: Token.Identifier; | ||
} else if (['"', "'"].includes(s.charAt(pos))) { | ||
firstChar = s.charAt(pos); | ||
text = scanString(); | ||
token = Token.String; | ||
} else { | ||
pos++; | ||
switch (s.charAt(pos - 1)) { | ||
|
@@ -62,6 +68,64 @@ export function lex(s: string): Lexer { | |
function scanForward(pred: (x: string) => boolean) { | ||
while (pos < s.length && pred(s.charAt(pos))) pos++; | ||
} | ||
|
||
function scanString() { | ||
const quote = s.charCodeAt(pos); | ||
pos++; | ||
|
||
let stringValue = ''; | ||
let start = pos; | ||
|
||
while (true) { | ||
if (pos >= s.length) { | ||
// report unterminated string literal error | ||
} | ||
Comment on lines
+80
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still not sure how to report this kind of error in the lexer scope 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you'll probably have to make the lexer able to report errors the same way the other phases do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided to add a new exercise to add the support for the lexer to report errors (imteekay/mini-typescript@65a3270). I also saw an interesting tweet by Maria about reporting errors for string literals. |
||
|
||
const char = s.charCodeAt(pos); | ||
|
||
if (char === quote) { | ||
stringValue += s.slice(start, pos); | ||
pos++; | ||
break; | ||
} | ||
|
||
if (char === CharCodes.backslash) { | ||
stringValue += s.slice(start, pos); | ||
stringValue += scanEscapeSequence(); | ||
start = pos; | ||
continue; | ||
} | ||
|
||
pos++; | ||
} | ||
|
||
return stringValue; | ||
} | ||
|
||
function scanEscapeSequence() { | ||
pos++; | ||
const char = s.charCodeAt(pos); | ||
pos++; | ||
|
||
switch (char) { | ||
case CharCodes.b: | ||
return '\b'; | ||
case CharCodes.t: | ||
return '\t'; | ||
case CharCodes.n: | ||
return '\n'; | ||
case CharCodes.r: | ||
return '\r'; | ||
case CharCodes.singleQuote: | ||
// prettier-ignore | ||
return "\'"; | ||
case CharCodes.doubleQuote: | ||
// prettier-ignore | ||
return '\"'; | ||
default: | ||
return String.fromCharCode(char); | ||
} | ||
} | ||
} | ||
|
||
export function lexAll(s: string) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
feels like this code needs a lot more tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just made some adjustments to how I scan, parse, and emit escape characters. And separated the
StringLiteral
node from theLiteral
(I will rename theLiteral
toNumericLiteral
and refactor the code in the future) (imteekay/mini-typescript@c5e8220).Also added more tests as you recommended (imteekay/mini-typescript@ead71e2 and imteekay/mini-typescript@b04fc8a).