parent
4d325569fa
commit
911c813996
12
Canon.Core/Abstractions/ICompilerLogger.cs
Normal file
12
Canon.Core/Abstractions/ICompilerLogger.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Canon.Core.Abstractions;
|
||||||
|
|
||||||
|
public interface ICompilerLogger : ILogger
|
||||||
|
{
|
||||||
|
IDisposable ILogger.BeginScope<TState>(TState state) => default!;
|
||||||
|
|
||||||
|
bool ILogger.IsEnabled(LogLevel logLevel) => true;
|
||||||
|
|
||||||
|
public string Build();
|
||||||
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
using Canon.Core.CodeGenerators;
|
using Canon.Core.Abstractions;
|
||||||
|
using Canon.Core.CodeGenerators;
|
||||||
using Canon.Core.SyntaxNodes;
|
using Canon.Core.SyntaxNodes;
|
||||||
|
|
||||||
namespace Canon.Core.SemanticParser;
|
namespace Canon.Core.SemanticParser;
|
||||||
|
|
||||||
public class CCodeGenerateVisitor : TypeCheckVisitor
|
public class CCodeGenerateVisitor(ICompilerLogger? logger = null) : TypeCheckVisitor(logger)
|
||||||
{
|
{
|
||||||
public CCodeBuilder Builder { get; } = new();
|
public CCodeBuilder Builder { get; } = new();
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ using Expression = Canon.Core.SyntaxNodes.Expression;
|
||||||
|
|
||||||
namespace Canon.Core.SemanticParser;
|
namespace Canon.Core.SemanticParser;
|
||||||
|
|
||||||
public class TypeCheckVisitor(ILogger<TypeCheckVisitor>? logger = null) : SyntaxNodeVisitor
|
public class TypeCheckVisitor(ICompilerLogger? logger = null) : SyntaxNodeVisitor
|
||||||
{
|
{
|
||||||
public SymbolTable SymbolTable { get; private set; } = new();
|
public SymbolTable SymbolTable { get; private set; } = new();
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,9 @@ public class CompileResponse
|
||||||
[Required]
|
[Required]
|
||||||
public string CompileTime { get; set; }
|
public string CompileTime { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string CompileInformation { get; set; }
|
||||||
|
|
||||||
public CompileResponse()
|
public CompileResponse()
|
||||||
{
|
{
|
||||||
Id = string.Empty;
|
Id = string.Empty;
|
||||||
|
@ -27,6 +30,7 @@ public class CompileResponse
|
||||||
CompiledCode = string.Empty;
|
CompiledCode = string.Empty;
|
||||||
ImageAddress = string.Empty;
|
ImageAddress = string.Empty;
|
||||||
CompileTime = string.Empty;
|
CompileTime = string.Empty;
|
||||||
|
CompileInformation = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompileResponse(CompileResult result)
|
public CompileResponse(CompileResult result)
|
||||||
|
@ -36,5 +40,6 @@ public class CompileResponse
|
||||||
CompiledCode = result.CompiledCode;
|
CompiledCode = result.CompiledCode;
|
||||||
ImageAddress = $"/api/file/{result.SytaxTreeImageFilename}";
|
ImageAddress = $"/api/file/{result.SytaxTreeImageFilename}";
|
||||||
CompileTime = result.CompileTime.AddHours(8).ToString("yyyy-MM-dd HH:mm:ss");
|
CompileTime = result.CompileTime.AddHours(8).ToString("yyyy-MM-dd HH:mm:ss");
|
||||||
|
CompileInformation = result.CompileInformation;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,5 +17,7 @@ public class CompileResult
|
||||||
|
|
||||||
public string CompiledCode { get; set; } = string.Empty;
|
public string CompiledCode { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string CompileInformation { get; set; } = string.Empty;
|
||||||
|
|
||||||
public DateTime CompileTime { get; set; }
|
public DateTime CompileTime { get; set; }
|
||||||
}
|
}
|
||||||
|
|
30
Canon.Server/Models/CompilerLogger.cs
Normal file
30
Canon.Server/Models/CompilerLogger.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Text;
|
||||||
|
using Canon.Core.Abstractions;
|
||||||
|
|
||||||
|
namespace Canon.Server.Models;
|
||||||
|
|
||||||
|
public class CompilerLogger : ICompilerLogger
|
||||||
|
{
|
||||||
|
private readonly ThreadLocal<StringBuilder> _builder = new(() => new StringBuilder());
|
||||||
|
|
||||||
|
public string Build()
|
||||||
|
{
|
||||||
|
if (_builder.Value is not null)
|
||||||
|
{
|
||||||
|
string result = _builder.Value.ToString();
|
||||||
|
_builder.Value.Clear();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
|
||||||
|
Func<TState, Exception?, string> formatter)
|
||||||
|
{
|
||||||
|
if (_builder.Value is not null)
|
||||||
|
{
|
||||||
|
_builder.Value.Append(logLevel).Append(": ").Append(formatter(state, exception)).Append('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ using Canon.Core.GrammarParser;
|
||||||
using Canon.Core.LexicalParser;
|
using Canon.Core.LexicalParser;
|
||||||
using Canon.Core.SemanticParser;
|
using Canon.Core.SemanticParser;
|
||||||
using Canon.Server.Extensions;
|
using Canon.Server.Extensions;
|
||||||
|
using Canon.Server.Models;
|
||||||
using Canon.Server.Services;
|
using Canon.Server.Services;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
@ -21,11 +22,13 @@ builder.Services.AddDbContext<CompileDbContext>(options =>
|
||||||
options.UseMongoDB(connectionString, "Canon");
|
options.UseMongoDB(connectionString, "Canon");
|
||||||
});
|
});
|
||||||
builder.Services.AddGridFs(connectionString, "Canon");
|
builder.Services.AddGridFs(connectionString, "Canon");
|
||||||
|
builder.Services.AddSingleton<ICompilerLogger, CompilerLogger>();
|
||||||
builder.Services.AddTransient<ILexer, Lexer>();
|
builder.Services.AddTransient<ILexer, Lexer>();
|
||||||
builder.Services.AddSingleton<IGrammarParser>(
|
builder.Services.AddSingleton<IGrammarParser>(
|
||||||
_ => GeneratedGrammarParser.Instance);
|
_ => GeneratedGrammarParser.Instance);
|
||||||
builder.Services.AddSingleton<SyntaxTreePresentationService>();
|
builder.Services.AddSingleton<SyntaxTreePresentationService>();
|
||||||
builder.Services.AddSingleton<SyntaxTreeTraveller>();
|
builder.Services.AddSingleton<SyntaxTreeTraveller>();
|
||||||
|
builder.Services.AddTransient<CCodeGenerateVisitor>();
|
||||||
builder.Services.AddTransient<CompilerService>();
|
builder.Services.AddTransient<CompilerService>();
|
||||||
builder.Services.AddHostedService<DatabaseSetupService>();
|
builder.Services.AddHostedService<DatabaseSetupService>();
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,10 @@ using MongoDB.EntityFrameworkCore.Extensions;
|
||||||
|
|
||||||
namespace Canon.Server.Services;
|
namespace Canon.Server.Services;
|
||||||
|
|
||||||
public class CompileDbContext : DbContext
|
public class CompileDbContext(DbContextOptions<CompileDbContext> options) : DbContext(options)
|
||||||
{
|
{
|
||||||
public DbSet<CompileResult> CompileResults { get; init; }
|
public DbSet<CompileResult> CompileResults { get; init; }
|
||||||
|
|
||||||
public CompileDbContext(DbContextOptions<CompileDbContext> options) : base(options)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
|
@ -13,6 +13,8 @@ public class CompilerService(
|
||||||
ILexer lexer,
|
ILexer lexer,
|
||||||
IGrammarParser grammarParser,
|
IGrammarParser grammarParser,
|
||||||
SyntaxTreeTraveller traveller,
|
SyntaxTreeTraveller traveller,
|
||||||
|
CCodeGenerateVisitor visitor,
|
||||||
|
ICompilerLogger compilerLogger,
|
||||||
CompileDbContext dbContext,
|
CompileDbContext dbContext,
|
||||||
GridFsService gridFsService,
|
GridFsService gridFsService,
|
||||||
SyntaxTreePresentationService syntaxTreePresentationService,
|
SyntaxTreePresentationService syntaxTreePresentationService,
|
||||||
|
@ -39,7 +41,6 @@ public class CompilerService(
|
||||||
await using Stream imageStream = syntaxTreePresentationService.Present(root);
|
await using Stream imageStream = syntaxTreePresentationService.Present(root);
|
||||||
string filename = await gridFsService.UploadStream(imageStream, "image/png");
|
string filename = await gridFsService.UploadStream(imageStream, "image/png");
|
||||||
|
|
||||||
CCodeGenerateVisitor visitor = new();
|
|
||||||
traveller.Travel(root, visitor);
|
traveller.Travel(root, visitor);
|
||||||
|
|
||||||
CompileResult result = new()
|
CompileResult result = new()
|
||||||
|
@ -48,7 +49,8 @@ public class CompilerService(
|
||||||
CompileId = Guid.NewGuid().ToString(),
|
CompileId = Guid.NewGuid().ToString(),
|
||||||
CompiledCode = visitor.Builder.Build(),
|
CompiledCode = visitor.Builder.Build(),
|
||||||
SytaxTreeImageFilename = filename,
|
SytaxTreeImageFilename = filename,
|
||||||
CompileTime = DateTime.Now
|
CompileTime = DateTime.Now,
|
||||||
|
CompileInformation = compilerLogger.Build()
|
||||||
};
|
};
|
||||||
|
|
||||||
await dbContext.CompileResults.AddAsync(result);
|
await dbContext.CompileResults.AddAsync(result);
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
|
import * as openapi from '../openapi';
|
||||||
|
|
||||||
export interface OutputIntf {
|
export interface OutputIntf {
|
||||||
|
data : openapi.components["schemas"]["CompileResponse"]
|
||||||
compiledCode: string,
|
|
||||||
id: string,
|
|
||||||
imageAddress: string,
|
|
||||||
sourceCode: string,
|
|
||||||
compileTime: string
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,6 @@ import * as openapi from '../openapi';
|
||||||
import {enqueueSnackbar} from "notistack";
|
import {enqueueSnackbar} from "notistack";
|
||||||
import {useNavigate} from "react-router-dom";
|
import {useNavigate} from "react-router-dom";
|
||||||
import {HistoryPage} from "./HistoryPage.tsx";
|
import {HistoryPage} from "./HistoryPage.tsx";
|
||||||
import {OutputIntf} from "../Interfaces/OutputIntf.ts";
|
|
||||||
|
|
||||||
|
|
||||||
const client = createClient<openapi.paths>();
|
const client = createClient<openapi.paths>();
|
||||||
|
|
||||||
|
@ -16,12 +14,13 @@ const client = createClient<openapi.paths>();
|
||||||
export function Index() {
|
export function Index() {
|
||||||
|
|
||||||
const [inputValue, setInputValue] = useState('');
|
const [inputValue, setInputValue] = useState('');
|
||||||
const [outputValue, setOutputValue] = useState<OutputIntf>({
|
const [outputValue, setOutputValue] = useState<openapi.components["schemas"]["CompileResponse"]>({
|
||||||
compiledCode: "",
|
compiledCode: "",
|
||||||
sourceCode: "",
|
sourceCode: "",
|
||||||
id: "",
|
id: "",
|
||||||
imageAddress: "",
|
imageAddress: "",
|
||||||
compileTime: ""
|
compileTime: "",
|
||||||
|
compileInformation: ""
|
||||||
});
|
});
|
||||||
const [historyPageState,setHistoryPageState] = useState(false);
|
const [historyPageState,setHistoryPageState] = useState(false);
|
||||||
const navigate = useNavigate(); // 跳转hook
|
const navigate = useNavigate(); // 跳转hook
|
||||||
|
@ -36,7 +35,8 @@ export function Index() {
|
||||||
sourceCode: "",
|
sourceCode: "",
|
||||||
id: "",
|
id: "",
|
||||||
imageAddress: "pic/uncompiled.png",
|
imageAddress: "pic/uncompiled.png",
|
||||||
compileTime: ""
|
compileTime: "",
|
||||||
|
compileInformation: ""
|
||||||
})
|
})
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -52,13 +52,7 @@ export function Index() {
|
||||||
})
|
})
|
||||||
if (data !== undefined) {
|
if (data !== undefined) {
|
||||||
setInputValue(data.sourceCode);
|
setInputValue(data.sourceCode);
|
||||||
setOutputValue({
|
setOutputValue(data)
|
||||||
compiledCode: data.compiledCode,
|
|
||||||
sourceCode: data.sourceCode,
|
|
||||||
id: data.id,
|
|
||||||
imageAddress: data.imageAddress,
|
|
||||||
compileTime: data.compileTime
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getCompileInstance();
|
getCompileInstance();
|
||||||
|
@ -79,13 +73,7 @@ export function Index() {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (data !== undefined) {
|
if (data !== undefined) {
|
||||||
setOutputValue({
|
setOutputValue(data);
|
||||||
compiledCode: data.compiledCode,
|
|
||||||
sourceCode: data.sourceCode,
|
|
||||||
id: data.id,
|
|
||||||
imageAddress: data.imageAddress,
|
|
||||||
compileTime: data.compileTime
|
|
||||||
})
|
|
||||||
enqueueSnackbar("编译成功", {variant: "success", anchorOrigin: {vertical: 'bottom', horizontal: 'right'}});
|
enqueueSnackbar("编译成功", {variant: "success", anchorOrigin: {vertical: 'bottom', horizontal: 'right'}});
|
||||||
navigate(`/${data.id}`, {})
|
navigate(`/${data.id}`, {})
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,13 @@ import {CSSProperties, useState} from "react";
|
||||||
import { Box, ToggleButton, ToggleButtonGroup } from "@mui/material";
|
import { Box, ToggleButton, ToggleButtonGroup } from "@mui/material";
|
||||||
import { PhotoProvider, PhotoView } from "react-photo-view";
|
import { PhotoProvider, PhotoView } from "react-photo-view";
|
||||||
import MonacoEditor from "react-monaco-editor";
|
import MonacoEditor from "react-monaco-editor";
|
||||||
|
import { OutputIntf } from "../Interfaces/OutputIntf";
|
||||||
|
|
||||||
|
export function OutputField(props: OutputIntf) {
|
||||||
// @ts-expect-error ...
|
|
||||||
export function OutputField({data}) {
|
|
||||||
const [state, setState] = useState('tree')
|
const [state, setState] = useState('tree')
|
||||||
const {imageAddress, compiledCode} = data;
|
const { imageAddress, compiledCode, compileInformation } = props.data;
|
||||||
|
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div className={"output-field"} style={outputFieldClassCss}>
|
<div className={"output-field"} style={outputFieldClassCss}>
|
||||||
<ToggleButtonGroup
|
<ToggleButtonGroup
|
||||||
|
@ -37,13 +38,15 @@ export function OutputField({data}) {
|
||||||
size={"small"}>
|
size={"small"}>
|
||||||
Tree
|
Tree
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
|
<ToggleButton value="log" aria-label="log" size={"small"}>
|
||||||
|
Log
|
||||||
|
</ToggleButton>
|
||||||
</ToggleButtonGroup>
|
</ToggleButtonGroup>
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
height: "90%",
|
height: "90%",
|
||||||
}}>
|
}}>
|
||||||
{
|
{
|
||||||
|
state === 'tree' &&
|
||||||
state === 'tree' ?
|
|
||||||
<PhotoProvider>
|
<PhotoProvider>
|
||||||
<PhotoView key={1} src={imageAddress}>
|
<PhotoView key={1} src={imageAddress}>
|
||||||
{imageAddress == "pic/uncompiled.png" ?
|
{imageAddress == "pic/uncompiled.png" ?
|
||||||
|
@ -64,13 +67,22 @@ export function OutputField({data}) {
|
||||||
|
|
||||||
</PhotoView>
|
</PhotoView>
|
||||||
</PhotoProvider>
|
</PhotoProvider>
|
||||||
: <MonacoEditor
|
}
|
||||||
|
{
|
||||||
|
state == "code" && <MonacoEditor
|
||||||
language="javascript"
|
language="javascript"
|
||||||
theme="twilight"
|
theme="twilight"
|
||||||
value={compiledCode === "" ? "也就是说,还没编译啊还没编译" : compiledCode}
|
value={compiledCode === "" ? "也就是说,还没编译啊还没编译" : compiledCode}
|
||||||
options={{ readOnly: true }}
|
options={{ readOnly: true }}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
state == "log" && <MonacoEditor
|
||||||
|
theme={"twilight"}
|
||||||
|
value={compileInformation}
|
||||||
|
options={{readOnly: true}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
1
Canon.Server/client-app/src/openapi.d.ts
vendored
1
Canon.Server/client-app/src/openapi.d.ts
vendored
|
@ -119,6 +119,7 @@ export interface components {
|
||||||
compiledCode: string;
|
compiledCode: string;
|
||||||
imageAddress: string;
|
imageAddress: string;
|
||||||
compileTime: string;
|
compileTime: string;
|
||||||
|
compileInformation: string;
|
||||||
};
|
};
|
||||||
ProblemDetails: {
|
ProblemDetails: {
|
||||||
type?: string | null;
|
type?: string | null;
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace Canon.Tests.SemanticTests;
|
||||||
|
|
||||||
public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
public class TypeCheckVisitorTests(ITestOutputHelper testOutputHelper)
|
||||||
{
|
{
|
||||||
private readonly TestLogger<TypeCheckVisitor> _logger = new(testOutputHelper);
|
private readonly TestLogger _logger = new(testOutputHelper);
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ConstTypeTest()
|
public void ConstTypeTest()
|
||||||
|
|
|
@ -1,24 +1,16 @@
|
||||||
using Microsoft.Extensions.Logging;
|
using Canon.Core.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace Canon.Tests.Utils;
|
namespace Canon.Tests.Utils;
|
||||||
|
|
||||||
public class TestLogger<T>(ITestOutputHelper testOutputHelper) : ILogger<T>, IDisposable
|
public class TestLogger(ITestOutputHelper testOutputHelper) : ICompilerLogger
|
||||||
{
|
{
|
||||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception,
|
||||||
Func<TState, Exception?, string> formatter)
|
Func<TState, Exception?, string> formatter)
|
||||||
{
|
{
|
||||||
testOutputHelper.WriteLine("{0}: {1}", logLevel, formatter(state, exception));
|
testOutputHelper.WriteLine($"{logLevel}: {formatter(state, exception)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsEnabled(LogLevel logLevel) => false;
|
public string Build() => string.Empty;
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDisposable BeginScope<TState>(TState state) where TState : notnull
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user