13bool isIdentifierStart(
char c) {
14 return std::isalpha(
static_cast<unsigned char>(
c)) != 0 ||
c ==
'_';
17bool isIdentifierBody(
char c) {
18 return std::isalnum(
static_cast<unsigned char>(
c)) != 0 ||
c ==
'_' ||
c ==
'.';
21bool isDigit(
char c) {
return c >=
'0' &&
c <=
'9'; }
27 {{
"line", std::to_string(
line)}, {
"column", std::to_string(
column)}},
32std::size_t twoCharacterPunctuatorLength(std::string_view
source, std::size_t i) {
33 if (i + 1 >=
source.size())
return 0;
34 const std::string_view pair =
source.substr(i, 2);
35 for (
const std::string_view candidate : {
"==",
"!=",
">=",
"<=",
"&&",
"||",
"->"}) {
36 if (pair == candidate)
return 2;
41bool isSingleCharacterPunctuator(
char c) {
59 case '|':
return true;
60 default:
return false;
65bool appendEscape(
char escape, std::string& out) {
67 case 'n': out +=
'\n';
return true;
68 case 't': out +=
'\t';
return true;
69 case 'r': out +=
'\r';
return true;
70 case '"': out +=
'"';
return true;
71 case '\'': out +=
'\'';
return true;
72 case '\\': out +=
'\\';
return true;
73 case '{': out +=
'{';
return true;
74 case '}': out +=
'}';
return true;
98 std::vector<DnutToken>
tokens;
104 const auto advanceOne = [&]() {
117 if (
c ==
'\n' ||
c ==
' ' ||
c ==
'\t' ||
c ==
'\r') {
121 if (
c ==
'/' && i + 1 <
size &&
source[i + 1] ==
'/') {
125 if (
c ==
'/' && i + 1 <
size &&
source[i + 1] ==
'*') {
126 const int startLine =
line;
127 const int startColumn =
column;
141 return lexFailure(
path, startLine, startColumn,
"unterminated block comment");
144 if (
c ==
'"' ||
c ==
'\'') {
146 const int startLine =
line;
147 const int startColumn =
column;
150 bool terminated =
false;
159 if (i >=
size)
break;
162 std::string(
"unknown escape sequence '\\") +
source[i] +
"'");
169 if (!terminated)
return lexFailure(
path, startLine, startColumn,
"unterminated string literal");
173 if (isDigit(
c) || (
c ==
'.' && i + 1 <
size && isDigit(
source[i + 1]))) {
174 const int startLine =
line;
175 const int startColumn =
column;
176 const std::size_t
start = i;
179 if (isDigit(
d) ||
d ==
'.') {
181 }
else if ((
d ==
'e' ||
d ==
'E') && i + 1 <
size &&
193 if (isIdentifierStart(
c)) {
194 const int startLine =
line;
195 const int startColumn =
column;
196 const std::size_t
start = i;
204 while (i <
size && continuesIdentifier(i)) advanceOne();
209 if (
const std::size_t pairLength = twoCharacterPunctuatorLength(
source, i); pairLength != 0) {
210 const int startLine =
line;
211 const int startColumn =
column;
212 const std::string
text(
source.substr(i, pairLength));
218 if (isSingleCharacterPunctuator(
c)) {
219 const int startLine =
line;
220 const int startColumn =
column;
221 const std::string
text(1,
c);
226 return lexFailure(
path,
line,
column, std::string(
"unexpected character '") +
c +
"'");
233bool hasErrors(
const std::vector<DnutDiagnostic>& diagnostics) {
234 for (
const auto& diagnostic : diagnostics) {
Shared lexer for every `.dnut` dialect.
std::unordered_map< const Graphics *, std::shared_ptr< Lifetime > > tokens
std::array< float, 3 > position
const UnitySourceAsset & source
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Move-only operation result carrying either a value or Status.
EVENGINE_API_PLATFORM bool hasErrors(const std::vector< DnutDiagnostic > &diagnostics)
Return whether any diagnostic is an error.
eve::Result< std::vector< DnutToken > > lexDnut(std::string_view source, const std::string &path)
Lex one .dnut source buffer into owned tokens.
const char * dnutTokenKindName(DnutTokenKind kind) noexcept
Return the stable lowercase spelling of a token kind.
DnutTokenKind
Token classes produced by the shared .dnut lexer.
@ String
Quoted string with escapes already resolved.
@ Identifier
Bare word: keyword, field name, identifier, or bare enum value.
@ Punctuator
One- or two-character punctuator such as {, =, ==, ->.
@ EndOfFile
Synthetic terminal token; always the last element.
@ Number
Unsigned numeric literal; sign handling belongs to the parser.