2024-04-19 14:59:45 +08:00
|
|
|
|
using Canon.Core.Abstractions;
|
2024-05-13 22:29:32 +08:00
|
|
|
|
using Canon.Core.Exceptions;
|
2024-04-19 14:59:45 +08:00
|
|
|
|
using Canon.Core.LexicalParser;
|
2024-04-26 10:18:49 +08:00
|
|
|
|
using Canon.Core.SemanticParser;
|
2024-04-19 14:59:45 +08:00
|
|
|
|
using Canon.Core.SyntaxNodes;
|
2024-04-22 21:26:34 +08:00
|
|
|
|
using Canon.Server.DataTransferObjects;
|
|
|
|
|
using Canon.Server.Entities;
|
2024-04-19 14:59:45 +08:00
|
|
|
|
using Canon.Server.Models;
|
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
2024-05-13 22:29:32 +08:00
|
|
|
|
using MongoDB.Bson;
|
2024-04-19 14:59:45 +08:00
|
|
|
|
|
|
|
|
|
namespace Canon.Server.Services;
|
|
|
|
|
|
|
|
|
|
public class CompilerService(
|
|
|
|
|
ILexer lexer,
|
|
|
|
|
IGrammarParser grammarParser,
|
2024-04-26 10:18:49 +08:00
|
|
|
|
SyntaxTreeTraveller traveller,
|
2024-04-19 14:59:45 +08:00
|
|
|
|
CompileDbContext dbContext,
|
|
|
|
|
GridFsService gridFsService,
|
|
|
|
|
SyntaxTreePresentationService syntaxTreePresentationService,
|
|
|
|
|
ILogger<CompilerService> logger)
|
|
|
|
|
{
|
|
|
|
|
public async Task<CompileResponse> Compile(SourceCode sourceCode)
|
|
|
|
|
{
|
|
|
|
|
logger.LogInformation("Try to compile: '{}'.", sourceCode.Code);
|
|
|
|
|
|
|
|
|
|
IQueryable<CompileResult> resultQuery = from item in dbContext.CompileResults
|
|
|
|
|
where item.SourceCode == sourceCode.Code
|
|
|
|
|
select item;
|
|
|
|
|
|
|
|
|
|
CompileResult? cachedResult = await resultQuery.FirstOrDefaultAsync();
|
|
|
|
|
if (cachedResult is not null)
|
|
|
|
|
{
|
|
|
|
|
return new CompileResponse(cachedResult);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CodeReader reader = new(sourceCode);
|
2024-05-13 22:29:32 +08:00
|
|
|
|
|
|
|
|
|
ProgramStruct root;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
IEnumerable<SemanticToken> 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);
|
|
|
|
|
}
|
2024-04-19 14:59:45 +08:00
|
|
|
|
|
|
|
|
|
await using Stream imageStream = syntaxTreePresentationService.Present(root);
|
|
|
|
|
string filename = await gridFsService.UploadStream(imageStream, "image/png");
|
|
|
|
|
|
2024-05-13 22:29:32 +08:00
|
|
|
|
ICompilerLogger compilerLogger = new CompilerLogger();
|
2024-05-12 22:36:17 +08:00
|
|
|
|
CodeGeneratorVisitor visitor = new(compilerLogger);
|
2024-04-26 10:18:49 +08:00
|
|
|
|
traveller.Travel(root, visitor);
|
2024-04-22 21:26:34 +08:00
|
|
|
|
|
2024-04-19 14:59:45 +08:00
|
|
|
|
CompileResult result = new()
|
|
|
|
|
{
|
2024-05-13 22:29:32 +08:00
|
|
|
|
Id = ObjectId.GenerateNewId(),
|
|
|
|
|
Error = visitor.IsError,
|
2024-04-19 14:59:45 +08:00
|
|
|
|
SourceCode = sourceCode.Code,
|
2024-04-26 10:18:49 +08:00
|
|
|
|
CompiledCode = visitor.Builder.Build(),
|
2024-04-22 21:26:34 +08:00
|
|
|
|
SytaxTreeImageFilename = filename,
|
2024-04-29 23:55:36 +08:00
|
|
|
|
CompileTime = DateTime.Now,
|
|
|
|
|
CompileInformation = compilerLogger.Build()
|
2024-04-19 14:59:45 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
await dbContext.CompileResults.AddAsync(result);
|
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
|
|
|
|
|
|
|
|
return new CompileResponse(result);
|
|
|
|
|
}
|
|
|
|
|
}
|