JSFiddle - React, Tailwind, and code Playground
by kasheftin
HTML
<div id="container" class="container" />
CSS
.container {
font-size: 30px;
line-height: 30px;
font-family: monospace;
margin-top: 400px;
}
span {
margin: 0 2px;
position: relative;
}
span::after {
font-size: 12px;
line-height: 12px;
content: var(--content);
position: absolute;
top: -10px;
left: 10px;
padding: 0 5px;
transform-origin: 0 0;
transform: rotate(-45deg);
border: 1px solid #000;
}
.BracketStart, .BracketEnd {
background-color: #2dd4bf;
}
.ReferenceBracketStart, .ReferenceBracketEnd {
background-color: #f472b6;
}
.ReferenceName {
background-color: #fb7185;
}
.Number, .String {
background-color: #818cf8;
}
.DoubleQuoteStart, .DoubleQuoteEnd {
background-color: #38bdf8;
}
.Operator {
background-color: #a1c420;
}
.Whitespace {
background-color: #cbd5e1;
}
.FunctionName {
background-color: #34d399;
}
TypeScript
enum TokenType {
Number = 'Number',
String = 'String',
Whitespace = 'Whitespace',
Operator = 'Operator',
BracketStart = 'BracketStart',
BracketEnd = 'BracketEnd',
ReferenceBracketStart = 'ReferenceBracketStart',
ReferenceBracketEnd = 'ReferenceBracketEnd',
ReferenceName = 'ReferenceName',
FunctionName = 'FunctionName',
Comma = 'Comma',
QuoteStart = 'QuoteStart',
QuoteEnd = 'QuoteEnd',
EmptyStringAndQuoteEnd = 'EmptyStringAndQuoteEnd',
DoubleQuoteStart = 'DoubleQuoteStart',
DoubleQuoteEnd = 'DoubleQuoteEnd',
EmptyStringAndDoubleQuoteEnd = 'EmptyStringAndDoubleQuoteEnd',
Group = 'Group',
Error = 'Error'
}
type Token = {
type: TokenType
value: string
}
interface LexerStream {
match: (pattern: RegExp, consume: boolean) => string | undefined
skip: () => void
prev: TokenType | null
}
function getNextToken ({ match, skip, prev }: LexerStream): TokenType {
if (prev !== TokenType.QuoteStart && match(/^"/, true)) {
if (prev === TokenType.String) {
return TokenType.DoubleQuoteEnd
} else if (prev === TokenType.DoubleQuoteStart) {
return TokenType.EmptyStringAndDoubleQuoteEnd
} else {
return TokenType.DoubleQuoteStart
}
}
if (match(/^'/, true)) {
if (prev === TokenType.String) {
return TokenType.QuoteEnd
} else if (prev === TokenType.QuoteStart) {
return TokenType.EmptyStringAndQuoteEnd
} else {
return TokenType.QuoteStart
}
}
if (prev === TokenType.DoubleQuoteStart) {
if (match(/^([^"\\]|\\.)+(?=")/, false)) {
match(/^([^"\\]|\\.)+(?=")/, true)
return TokenType.String
} else {
match(/^([^"\\]|\\.)+/, true)
return TokenType.String
}
}
if (prev === TokenType.QuoteStart) {
if (match(/^([^'\\]|\\.)+(?=')/, false)) {
match(/^([^'\\]|\\.)+(?=')/, true)
return TokenType.String
} else {
match(/^([^'\\]|\\.)+/, true)
return TokenType.String
}
}
const numberRegex =...