Highlight syntax errors in code snippets

This commit is contained in:
Araozu 2024-07-28 20:12:53 -05:00
parent bb6478b474
commit c038f6d55a
2 changed files with 19 additions and 7 deletions

View File

@ -52,6 +52,7 @@ export interface TokenizeResult {
Err?: Err, Err?: Err,
} }
const error_classes = "underline decoration-wavy decoration-red-500";
export async function native_highlighter(code: string): Promise<[string, string, string | null]> { export async function native_highlighter(code: string): Promise<[string, string, string | null]> {
let formatted_code = leftTrimDedent(code).join("\n"); let formatted_code = leftTrimDedent(code).join("\n");
@ -67,7 +68,6 @@ export async function native_highlighter(code: string): Promise<[string, string,
return lex_error_highlighter(formatted_code, result.Err!.Lex!); return lex_error_highlighter(formatted_code, result.Err!.Lex!);
} }
else if (result.TokensOnly) { else if (result.TokensOnly) {
// TODO
const [tokens, error] = result.TokensOnly!; const [tokens, error] = result.TokensOnly!;
return syntax_error_highlighter(formatted_code, tokens, error.Syntax!); return syntax_error_highlighter(formatted_code, tokens, error.Syntax!);
} }
@ -91,7 +91,7 @@ function lex_error_highlighter(code: string, error: LexError): [string, string,
const err_str = code[err_pos]; const err_str = code[err_pos];
const after_err = code.substring(err_pos + 1); const after_err = code.substring(err_pos + 1);
const token = `<span class="token underline decoration-wavy decoration-red-500">${err_str}</span>`; const token = `<span class="token ${error_classes}">${err_str}</span>`;
const all = `${before_err}${token}${after_err}`; const all = `${before_err}${token}${after_err}`;
@ -100,7 +100,7 @@ function lex_error_highlighter(code: string, error: LexError): [string, string,
} }
function syntax_error_highlighter(code: string, tokens: Array<Token>, error: SyntaxError): [string, string, string] { function syntax_error_highlighter(code: string, tokens: Array<Token>, error: SyntaxError): [string, string, string] {
const highlighted = highlight_tokens(code, tokens); const highlighted = highlight_tokens(code, tokens, error.error_start, error.error_end);
const error_message = `${error.reason} from position ${error.error_start} to ${error.error_end}`; const error_message = `${error.reason} from position ${error.error_start} to ${error.error_end}`;
return [highlighted, "Syntax", error_message]; return [highlighted, "Syntax", error_message];
@ -110,7 +110,16 @@ function compiler_error(code: string, error: Error): [string, string, string] {
return [code, "Fatal Compiler", error.message]; return [code, "Fatal Compiler", error.message];
} }
function highlight_tokens(input: string, tokens: Array<Token>): string { /**
* Transforms a list of tokens into colored HTML, and underlines errors
* if present
* @param input The original source code
* @param tokens The list of tokens
* @param error_start Absolute position from where the error starts.
* @param error_end Absolute position to where the error ends.
* @returns
*/
function highlight_tokens(input: string, tokens: Array<Token>, error_start = -1, error_end = -1): string {
const input_chars = input.split(""); const input_chars = input.split("");
let output = ""; let output = "";
@ -120,6 +129,9 @@ function highlight_tokens(input: string, tokens: Array<Token>): string {
const token_start = t.position; const token_start = t.position;
const token_end = t.position + t.value.length; const token_end = t.position + t.value.length;
let is_errored = (token_start == error_start);
// There are some tokens that are empty, ignore them // There are some tokens that are empty, ignore them
if (t.value == "") { if (t.value == "") {
continue; continue;
@ -131,7 +143,7 @@ function highlight_tokens(input: string, tokens: Array<Token>): string {
// Append the token // Append the token
const token_value = t.value.replaceAll(/</g, "&lt;").replaceAll(/>/g, "&gt;"); const token_value = t.value.replaceAll(/</g, "&lt;").replaceAll(/>/g, "&gt;");
const token_type = translate_token_type(t.token_type, token_value); const token_type = translate_token_type(t.token_type, token_value);
output += `<span class="token ${token_type}">${token_value}</span>`; output += `<span class="token ${token_type} ${is_errored ? error_classes : ""}">${token_value}</span>`;
current_pos = token_end; current_pos = token_end;
} }

View File

@ -117,8 +117,8 @@ doesn't match a previous level.
<Code thpcode={` <Code thpcode={`
if true { // 0 indentation if true { // 0 indentation
// print() // 4 indentation print() // 4 indentation
// print() // 2 indentation. Error. There is no 2-indentation level print() // 2 indentation. Error. There is no 2-indentation level
} }
`} /> `} />