From 20e82c6f4f577e3ada4a607c63f923ab9c0f6995 Mon Sep 17 00:00:00 2001 From: ichirinko <1621543655@qq.com> Date: Mon, 13 May 2024 22:29:32 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E5=89=8D=E7=AB=AFbug=20(?= =?UTF-8?q?#83)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: jackfiled Reviewed-on: https://git.rrricardo.top/PostGuard/Canon/pulls/83 Co-authored-by: ichirinko <1621543655@qq.com> Co-committed-by: ichirinko <1621543655@qq.com> --- Canon.Core/Exceptions/CanonException.cs | 19 +++++ Canon.Core/Exceptions/GrammarException.cs | 2 +- Canon.Core/Exceptions/LexemeException.cs | 18 ++--- .../Controllers/CompilerController.cs | 5 +- .../DataTransferObjects/CompileResponse.cs | 6 +- Canon.Server/Entities/CompileResult.cs | 3 +- Canon.Server/Program.cs | 1 - Canon.Server/Services/CompilerService.cs | 34 ++++++++- Canon.Server/client-app/src/Pages/Index.tsx | 75 ++++++++++--------- Canon.Server/client-app/src/openapi.d.ts | 1 + 10 files changed, 109 insertions(+), 55 deletions(-) create mode 100644 Canon.Core/Exceptions/CanonException.cs diff --git a/Canon.Core/Exceptions/CanonException.cs b/Canon.Core/Exceptions/CanonException.cs new file mode 100644 index 0000000..d18ff0f --- /dev/null +++ b/Canon.Core/Exceptions/CanonException.cs @@ -0,0 +1,19 @@ +namespace Canon.Core.Exceptions; + +/// +/// 编译器中的统一异常基类 +/// +public class CanonException : Exception +{ + public CanonException() + { + } + + public CanonException(string message) : base(message) + { + } + + public CanonException(string message, Exception innerException) : base(message, innerException) + { + } +} diff --git a/Canon.Core/Exceptions/GrammarException.cs b/Canon.Core/Exceptions/GrammarException.cs index 6002bae..9604c0d 100644 --- a/Canon.Core/Exceptions/GrammarException.cs +++ b/Canon.Core/Exceptions/GrammarException.cs @@ -8,7 +8,7 @@ namespace Canon.Core.Exceptions; /// /// 语法分析中引发的异常 /// -public class GrammarException : Exception +public class GrammarException : CanonException { public override string Message { get; } diff --git a/Canon.Core/Exceptions/LexemeException.cs b/Canon.Core/Exceptions/LexemeException.cs index 40ec791..0e6f454 100644 --- a/Canon.Core/Exceptions/LexemeException.cs +++ b/Canon.Core/Exceptions/LexemeException.cs @@ -3,32 +3,32 @@ using Enums; /// /// 词法分析中引发的异常 /// -public class LexemeException : Exception +public class LexemeException : CanonException { public LexemeErrorType ErrorType { get; } + public uint Line { get; } + public uint CharPosition { get; } - public LexemeException() { } - public LexemeException(string message) : base(message) { } - - public LexemeException(string message, Exception innerException) : - base(message, innerException) { } + private readonly string _message; /// 错误类型 /// 单词的行号 /// 单词的列号 /// 错误信息 - public LexemeException(LexemeErrorType errorType, uint line, uint charPosition, string message) : - base("line:" + line + ", charPosition:" + charPosition + " :" + message) + public LexemeException(LexemeErrorType errorType, uint line, uint charPosition, string message) { ErrorType = errorType; Line = line; CharPosition = charPosition; + _message = message; } + public override string Message => ToString(); + public override string ToString() { - return $"LexemeException: ErrorType={ErrorType}, Line={Line}, CharPosition={CharPosition}, Message={Message}\n"; + return $"LexemeException: ErrorType={ErrorType}, Line={Line}, CharPosition={CharPosition}, Message={_message}\n"; } } diff --git a/Canon.Server/Controllers/CompilerController.cs b/Canon.Server/Controllers/CompilerController.cs index 872006e..310b8b0 100644 --- a/Canon.Server/Controllers/CompilerController.cs +++ b/Canon.Server/Controllers/CompilerController.cs @@ -3,6 +3,7 @@ using Canon.Server.Entities; using Canon.Server.Services; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using MongoDB.Bson; namespace Canon.Server.Controllers; @@ -35,7 +36,7 @@ public class CompilerController(CompileDbContext dbContext, CompilerService comp public async Task> GetResponse(string compileId) { CompileResult? result = await (from item in dbContext.CompileResults.AsNoTracking() - where item.CompileId == compileId + where item.Id == new ObjectId(compileId) select item).FirstOrDefaultAsync(); if (result is null) @@ -59,7 +60,7 @@ public class CompilerController(CompileDbContext dbContext, CompilerService comp public async Task DeleteCompileResult(string compileId) { CompileResult? result = await (from item in dbContext.CompileResults - where item.CompileId == compileId + where item.Id == new ObjectId(compileId) select item).FirstOrDefaultAsync(); if (result is null) diff --git a/Canon.Server/DataTransferObjects/CompileResponse.cs b/Canon.Server/DataTransferObjects/CompileResponse.cs index 2598410..cb952e7 100644 --- a/Canon.Server/DataTransferObjects/CompileResponse.cs +++ b/Canon.Server/DataTransferObjects/CompileResponse.cs @@ -8,6 +8,9 @@ public class CompileResponse [Required] public string Id { get; set; } + [Required] + public bool Error { get; set; } + [Required] public string SourceCode { get; set; } @@ -35,7 +38,8 @@ public class CompileResponse public CompileResponse(CompileResult result) { - Id = result.CompileId; + Id = result.Id.ToString(); + Error = result.Error; SourceCode = result.SourceCode; CompiledCode = result.CompiledCode; ImageAddress = $"/api/file/{result.SytaxTreeImageFilename}"; diff --git a/Canon.Server/Entities/CompileResult.cs b/Canon.Server/Entities/CompileResult.cs index 95c47c2..23ab1d4 100644 --- a/Canon.Server/Entities/CompileResult.cs +++ b/Canon.Server/Entities/CompileResult.cs @@ -7,8 +7,7 @@ public class CompileResult { public ObjectId Id { get; set; } - [MaxLength(40)] - public string CompileId { get; set; } = string.Empty; + public bool Error { get; set; } public string SourceCode { get; set; } = string.Empty; diff --git a/Canon.Server/Program.cs b/Canon.Server/Program.cs index c90bb18..00b4ca4 100644 --- a/Canon.Server/Program.cs +++ b/Canon.Server/Program.cs @@ -22,7 +22,6 @@ builder.Services.AddDbContext(options => options.UseMongoDB(connectionString, "Canon"); }); builder.Services.AddGridFs(connectionString, "Canon"); -builder.Services.AddSingleton(); builder.Services.AddTransient(); builder.Services.AddSingleton( _ => GeneratedGrammarParser.Instance); diff --git a/Canon.Server/Services/CompilerService.cs b/Canon.Server/Services/CompilerService.cs index d469961..e96a17a 100644 --- a/Canon.Server/Services/CompilerService.cs +++ b/Canon.Server/Services/CompilerService.cs @@ -1,4 +1,5 @@ using Canon.Core.Abstractions; +using Canon.Core.Exceptions; using Canon.Core.LexicalParser; using Canon.Core.SemanticParser; using Canon.Core.SyntaxNodes; @@ -6,6 +7,7 @@ using Canon.Server.DataTransferObjects; using Canon.Server.Entities; using Canon.Server.Models; using Microsoft.EntityFrameworkCore; +using MongoDB.Bson; namespace Canon.Server.Services; @@ -13,7 +15,6 @@ public class CompilerService( ILexer lexer, IGrammarParser grammarParser, SyntaxTreeTraveller traveller, - ICompilerLogger compilerLogger, CompileDbContext dbContext, GridFsService gridFsService, SyntaxTreePresentationService syntaxTreePresentationService, @@ -34,19 +35,44 @@ public class CompilerService( } CodeReader reader = new(sourceCode); - IEnumerable tokens = lexer.Tokenize(reader); - ProgramStruct root = grammarParser.Analyse(tokens); + + ProgramStruct root; + try + { + IEnumerable tokens = lexer.Tokenize(reader); + root = grammarParser.Analyse(tokens); + } + catch (CanonException e) + { + CompileResult errorResult = new() + { + Id = ObjectId.GenerateNewId(), + Error = true, + SourceCode = sourceCode.Code, + CompiledCode = string.Empty, + SytaxTreeImageFilename = string.Empty, + CompileTime = DateTime.Now, + CompileInformation = e.Message + }; + + await dbContext.CompileResults.AddAsync(errorResult); + await dbContext.SaveChangesAsync(); + + return new CompileResponse(errorResult); + } await using Stream imageStream = syntaxTreePresentationService.Present(root); string filename = await gridFsService.UploadStream(imageStream, "image/png"); + ICompilerLogger compilerLogger = new CompilerLogger(); CodeGeneratorVisitor visitor = new(compilerLogger); traveller.Travel(root, visitor); CompileResult result = new() { + Id = ObjectId.GenerateNewId(), + Error = visitor.IsError, SourceCode = sourceCode.Code, - CompileId = Guid.NewGuid().ToString(), CompiledCode = visitor.Builder.Build(), SytaxTreeImageFilename = filename, CompileTime = DateTime.Now, diff --git a/Canon.Server/client-app/src/Pages/Index.tsx b/Canon.Server/client-app/src/Pages/Index.tsx index e7bfd52..ea6218a 100644 --- a/Canon.Server/client-app/src/Pages/Index.tsx +++ b/Canon.Server/client-app/src/Pages/Index.tsx @@ -1,12 +1,12 @@ -import {AppBar, Button, Grid, Toolbar, Typography} from "@mui/material"; -import {InputField} from "./InputField.tsx"; -import {CSSProperties, useEffect, useState} from "react"; -import {OutputField} from "./OutputField.tsx"; +import { AppBar, Button, Grid, Toolbar, Typography } from "@mui/material"; +import { InputField } from "./InputField.tsx"; +import { CSSProperties, useEffect, useState } from "react"; +import { OutputField } from "./OutputField.tsx"; import createClient from "openapi-fetch"; import * as openapi from '../openapi'; -import {enqueueSnackbar} from "notistack"; -import {useNavigate} from "react-router-dom"; -import {HistoryPage} from "./HistoryPage.tsx"; +import { enqueueSnackbar } from "notistack"; +import { useNavigate } from "react-router-dom"; +import { HistoryPage } from "./HistoryPage.tsx"; const client = createClient(); @@ -16,13 +16,14 @@ export function Index() { const [inputValue, setInputValue] = useState(''); const [outputValue, setOutputValue] = useState({ compiledCode: "", + error: false, sourceCode: "", id: "", imageAddress: "", compileTime: "", compileInformation: "" }); - const [historyPageState,setHistoryPageState] = useState(false); + const [historyPageState, setHistoryPageState] = useState(false); const navigate = useNavigate(); // 跳转hook useEffect(() => { @@ -32,6 +33,7 @@ export function Index() { setInputValue(""); setOutputValue({ compiledCode: "", + error: false, sourceCode: "", id: "", imageAddress: "pic/uncompiled.png", @@ -41,14 +43,14 @@ export function Index() { return; } const getCompileInstance = async () => { - const {data} = await client.GET("/api/Compiler/{compileId}", { + const { data } = await client.GET("/api/Compiler/{compileId}", { params: + { + path: { - path: - { - compileId: path - } + compileId: path } + } }) if (data !== undefined) { setInputValue(data.sourceCode); @@ -66,21 +68,24 @@ export function Index() { async function compilerButtonClick() { - const {data} = await client.POST("/api/Compiler", { + const { data } = await client.POST("/api/Compiler", { body: { code: inputValue } - }) + }); - if (data !== undefined) { - setOutputValue(data); - enqueueSnackbar("编译成功", {variant: "success", anchorOrigin: {vertical: 'bottom', horizontal: 'right'}}); - navigate(`/${data.id}`, {}) + if (data == undefined) { + enqueueSnackbar("内部错误", { variant: "error", anchorOrigin: { vertical: 'bottom', horizontal: 'right' } }); + return; + } + if (!data.error) { + enqueueSnackbar("编译成功", { variant: "success", anchorOrigin: { vertical: 'bottom', horizontal: 'right' } }); } else { // error - enqueueSnackbar("编译失败", {variant: "error", anchorOrigin: {vertical: 'bottom', horizontal: 'right'}}); + enqueueSnackbar("编译失败", { variant: "error", anchorOrigin: { vertical: 'bottom', horizontal: 'right' } }); } + navigate(`/${data.id}`, {}) } function historyButtonClick() { @@ -89,9 +94,9 @@ export function Index() { return <>
- - + style={titleClassCss}> + + Canon @@ -101,9 +106,9 @@ export function Index() { transform: "translateX(-50%)", fontSize: "medium", }} - variant="outlined" - color="inherit" - onClick={compilerButtonClick} + variant="outlined" + color="inherit" + onClick={compilerButtonClick} > 编译 @@ -113,29 +118,29 @@ export function Index() { right: "10%", fontSize: "medium", }} - variant="text" - color="inherit" - onClick={historyButtonClick}> - 历史记录 + variant="text" + color="inherit" + onClick={historyButtonClick}> + 历史记录
- - + style={contentClassCss}> + + - +
- + diff --git a/Canon.Server/client-app/src/openapi.d.ts b/Canon.Server/client-app/src/openapi.d.ts index a8fa80b..972094d 100644 --- a/Canon.Server/client-app/src/openapi.d.ts +++ b/Canon.Server/client-app/src/openapi.d.ts @@ -115,6 +115,7 @@ export interface components { schemas: { CompileResponse: { id: string; + error: boolean; sourceCode: string; compiledCode: string; imageAddress: string;