feat: update code snippet to use new compiler error interface
This commit is contained in:
parent
e6df715955
commit
62cc887797
@ -5,13 +5,13 @@ import CodeError from "./docs/CodeError.astro";
|
|||||||
|
|
||||||
const { thpcode, no_warnings, level } = Astro.props;
|
const { thpcode, no_warnings, level } = Astro.props;
|
||||||
|
|
||||||
const [native_html, error_type, error_message] = await native_highlighter(thpcode, level as HighlightLevel);
|
const [native_html, error_message] = await native_highlighter(thpcode, level as HighlightLevel);
|
||||||
---
|
---
|
||||||
|
|
||||||
<pre
|
<pre
|
||||||
class="language-thp"><code class="language-thp" set:html={native_html} /><span class="absolute top-1 right-1 text-right inline-block text-sm select-none opacity-75">thp</span></pre>
|
class="language-thp"><code class="language-thp" set:html={native_html} /><span class="absolute top-1 right-1 text-right inline-block text-sm select-none opacity-75">thp</span></pre>
|
||||||
{
|
{
|
||||||
no_warnings !== true && error_message !== null && (
|
no_warnings !== true && error_message !== null && (
|
||||||
<CodeError error_type={error_type} error_message={error_message} />
|
<CodeError error_message={error_message} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
const { error_type = "Unknown", error_message } = Astro.props;
|
const { error_message } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="px-4 py-2 rounded bg-red-200 dark:bg-red-950">
|
<div class="px-4 py-2 rounded bg-red-200 dark:bg-red-950">
|
||||||
<span class="inline-block font-bold">{error_type} error:</span>
|
<span class="inline-block font-bold">Compilation error:</span>
|
||||||
<span class="whitespace-pre-wrap">{error_message}</span>
|
<span class="whitespace-pre-wrap">{error_message}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,93 +5,59 @@ import type { MistiErr, Token, TokenizeResult, TokenType } from "./types";
|
|||||||
|
|
||||||
const error_classes = "underline underline-offset-4 decoration-wavy decoration-red-500";
|
const error_classes = "underline underline-offset-4 decoration-wavy decoration-red-500";
|
||||||
|
|
||||||
export async function native_highlighter(code: string, level = HighlightLevel.Syntactic): Promise<[string, string, string | null]> {
|
/**
|
||||||
|
* Highlights code using the compiler
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* - The tokens as a list of <span /> elements
|
||||||
|
* - An error message, if any
|
||||||
|
*/
|
||||||
|
export async function native_highlighter(code: string, level = HighlightLevel.Syntactic): Promise<[string, string | null]> {
|
||||||
let formatted_code = leftTrimDedent(code).join("\n");
|
let formatted_code = leftTrimDedent(code).join("\n");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let result = await native_lex(formatted_code);
|
let result = await native_lex(formatted_code, level);
|
||||||
return highlight_syntax(formatted_code, result, level);
|
return highlight_syntax(formatted_code, result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return compiler_error(formatted_code, error as MistiErr);
|
return compiler_error(formatted_code, error as MistiErr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlight_syntax(code: string, result: TokenizeResult, level: HighlightLevel): [string, string, string | null] {
|
/**
|
||||||
let tokens_final: Array<Token>;
|
* Highlights code using the compiler
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* - The tokens as a list of <span /> elements
|
||||||
|
* - An error message, if any
|
||||||
|
*/
|
||||||
|
function highlight_syntax(code: string, result: TokenizeResult): [string, string | null] {
|
||||||
|
if (result.Ok) {
|
||||||
|
const tokens_html = render_tokens(code, result.Ok);
|
||||||
|
|
||||||
if (result.SemanticError) {
|
return [tokens_html, null];
|
||||||
const [tokens, semanticError] = result.SemanticError;
|
} else if (result.MixedErr) {
|
||||||
|
const [tokens, errors] = result.MixedErr;
|
||||||
|
// TODO: Implement error rendering, based on the new error schema
|
||||||
|
|
||||||
if (level === HighlightLevel.Semantic) {
|
const tokens_html = render_tokens(code, tokens);
|
||||||
return semantic_error_highlighter(code, tokens, semanticError);
|
return [tokens_html, `error code ${errors.error_code}`];
|
||||||
} else {
|
} else if (result.Err) {
|
||||||
tokens_final = tokens;
|
// TODO: Implement error rendering, based on the new error schema
|
||||||
}
|
|
||||||
} else if (result.SyntaxError) {
|
|
||||||
const [tokens, syntaxError] = result.SyntaxError;
|
|
||||||
|
|
||||||
if (level === HighlightLevel.Semantic || level === HighlightLevel.Syntactic) {
|
return [code, `lexical error ${result.Err.error_code}`]
|
||||||
return syntax_error_highlighter(code, tokens, syntaxError);
|
|
||||||
} else {
|
|
||||||
tokens_final = tokens;
|
|
||||||
}
|
|
||||||
} else if (result.LexError) {
|
|
||||||
// There is no error level that bypasses a lex error
|
|
||||||
return lex_error_highlighter(code, result.LexError!);
|
|
||||||
} else if (result.Ok) {
|
|
||||||
tokens_final = result.Ok;
|
|
||||||
} else {
|
} else {
|
||||||
console.error(result);
|
console.error(result);
|
||||||
throw new Error("Web page error: The compiler returned a case that wasn't handled.");
|
throw new Error("Web page error: The compiler returned a case that wasn't handled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point all error cases have been handled
|
|
||||||
// and tokens_final contains valid tokens.
|
|
||||||
|
|
||||||
const output = highlight_tokens(code, tokens_final);
|
|
||||||
return [output, "", null];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** A fatal error with the THP compiler */
|
||||||
* Highlights code that has a lexic error
|
function compiler_error(code: string, error: MistiErr): [string, string] {
|
||||||
*/
|
console.log(error);
|
||||||
function lex_error_highlighter(code: string, error: MistiErr): [string, string, string] {
|
return [code, "Fatal compiler error"];
|
||||||
// Create a single error token
|
|
||||||
|
|
||||||
const err_pos = error.position;
|
|
||||||
const before_err = code.substring(0, err_pos);
|
|
||||||
const err_str = code[err_pos];
|
|
||||||
const after_err = code.substring(err_pos + 1);
|
|
||||||
|
|
||||||
const token = `<span class="token ${error_classes}">${err_str}</span>`;
|
|
||||||
|
|
||||||
const all = `${before_err}${token}${after_err}`;
|
|
||||||
const [error_line, error_column] = absolute_to_line_column(code, error.position);
|
|
||||||
|
|
||||||
// TODO: Transform absolute posijion (error.position) into line:column
|
|
||||||
return [all, "Lexical", error.reason + ` at line ${error_line}:${error_column} `]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function syntax_error_highlighter(code: string, tokens: Array<Token>, error: MistiErr): [string, string, string] {
|
|
||||||
const highlighted = highlight_tokens(code, tokens, error.error_start, error.error_end);
|
|
||||||
const [error_line, error_column] = absolute_to_line_column(code, error.error_start);
|
|
||||||
|
|
||||||
const error_message = `${error.reason} at line ${error_line}:${error_column}`;
|
|
||||||
return [highlighted, "Syntax", error_message];
|
|
||||||
}
|
|
||||||
|
|
||||||
function semantic_error_highlighter(code: string, tokens: Array<Token>, error: MistiErr): [string, string, string] {
|
|
||||||
const highlighted = highlight_tokens(code, tokens, error.error_start, error.error_end);
|
|
||||||
const [error_line, error_column] = absolute_to_line_column(code, error.error_start);
|
|
||||||
|
|
||||||
const error_message = `${error.reason} at line ${error_line}:${error_column}`;
|
|
||||||
return [highlighted, "Semantic", error_message];
|
|
||||||
}
|
|
||||||
|
|
||||||
function compiler_error(code: string, error: MistiErr): [string, string, string] {
|
|
||||||
return [code, "Fatal Compiler", error.message];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms a list of tokens into colored HTML, and underlines errors
|
* Transforms a list of tokens into colored HTML, and underlines errors
|
||||||
@ -102,7 +68,7 @@ function compiler_error(code: string, error: MistiErr): [string, string, string]
|
|||||||
* @param error_end Absolute position to where the error ends.
|
* @param error_end Absolute position to where the error ends.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function highlight_tokens(input: string, tokens: Array<Token>, error_start = -1, error_end = -1): string {
|
function render_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 = "";
|
||||||
|
|
||||||
@ -233,14 +199,14 @@ function translate_token_type(tt: TokenType, value: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const native_lex = (code: string) => new Promise<TokenizeResult>((resolve, reject) => {
|
const native_lex = (code: string, level: HighlightLevel) => new Promise<TokenizeResult>((resolve, reject) => {
|
||||||
// Get binary path from .env
|
// Get binary path from .env
|
||||||
const binary = import.meta.env.THP_BINARY;
|
const binary = import.meta.env.THP_BINARY;
|
||||||
if (!binary) {
|
if (!binary) {
|
||||||
throw new Error("THP_BINARY not set in .env");
|
throw new Error("THP_BINARY not set in .env");
|
||||||
}
|
}
|
||||||
|
|
||||||
const subprocess = spawn(binary, ["tokenize"]);
|
const subprocess = spawn(binary, ["tokenize", "-l", level.toString()]);
|
||||||
let response = "";
|
let response = "";
|
||||||
let error = "";
|
let error = "";
|
||||||
|
|
||||||
|
@ -60,12 +60,10 @@ export interface ErrorLabel {
|
|||||||
export interface TokenizeResult {
|
export interface TokenizeResult {
|
||||||
/** All checks passed */
|
/** All checks passed */
|
||||||
Ok?: Array<Token>,
|
Ok?: Array<Token>,
|
||||||
/** There were semantic errors */
|
/** A non lexic error was found */
|
||||||
SemanticError?: [Array<Token>, MistiErr],
|
MixedErr?: [Array<Token>, MistiErr],
|
||||||
/** There were syntax errors */
|
/** A lexic error was found */
|
||||||
SyntaxError?: [Array<Token>, MistiErr],
|
Err?: MistiErr,
|
||||||
/** No checks passed */
|
|
||||||
LexError?: MistiErr,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum HighlightLevel {
|
export enum HighlightLevel {
|
||||||
|
Loading…
Reference in New Issue
Block a user