diff --git a/src/Mamba/Code Analysis/Binding/Binder.cpp b/src/Mamba/Code Analysis/Binding/Binder.cpp index bf08fec..7233774 100644 --- a/src/Mamba/Code Analysis/Binding/Binder.cpp +++ b/src/Mamba/Code Analysis/Binding/Binder.cpp @@ -4,6 +4,7 @@ #include "BoundExpressionStatement.h" #include "MambaCore.h" #include "SyntaxFacts.h" +#include "TypeSymbol.h" #include using namespace Mamba; @@ -65,9 +66,9 @@ std::vector Binder::BindParameter( Parameters | std::views::transform([](auto&& Node) { return dynamic_cast(Node); }) | std::views::enumerate) { - const auto Name = Parameter->Identifier->Text(); - const auto Type = new TypeSymbol(Parameter->Type->Identifier->Text()); - const auto ParameterSymbol = new class ParameterSymbol(Name, Type, Index); + auto Name = Parameter->Identifier->Text(); + auto Type = new TypeSymbol(Parameter->Type->Identifier->Text()); + auto ParameterSymbol = new class ParameterSymbol(Name, Type, Index); Scope->Declare(ParameterSymbol); } #else @@ -77,9 +78,9 @@ std::vector Binder::BindParameter( { ++Index; - const auto Name = Parameter->Identifier->Text(); - const auto Type = new TypeSymbol(Parameter->Type->Identifier->Text()); - const auto ParameterSymbol = new class ParameterSymbol(Name, Type, Index); + auto Name = Parameter->Identifier->Text(); + auto Type = new TypeSymbol(Parameter->Type->Identifier->Text()); + auto ParameterSymbol = new class ParameterSymbol(Name, Type, Index); Scope->Declare(ParameterSymbol); } @@ -298,7 +299,7 @@ BoundStatement* Binder::BindContinueStatement(const ContinueStatementSyntax* Con BoundReturnStatement* Binder::BindReturnStatement(const ReturnStatementSyntax* ReturnStatement) noexcept { // TODO: Diagnostics - const auto Expression = BindExpression(ReturnStatement->Expression); + auto Expression = BindExpression(ReturnStatement->Expression); return new BoundReturnStatement(ReturnStatement, Expression); } @@ -354,12 +355,12 @@ BoundUnaryExpression* Binder::BindUnaryExpression(const UnaryExpressionSyntax* U BoundBinaryExpression* Binder::BindBinaryExpression(const BinaryExpressionSyntax* BinaryExpression) noexcept { - const auto BoundLeft = BindExpression(BinaryExpression->Left); - const auto BoundRight = BindExpression(BinaryExpression->Right); + auto BoundLeft = BindExpression(BinaryExpression->Left); + auto BoundRight = BindExpression(BinaryExpression->Right); // TODO: Check operand types - const auto BoundOperator = BoundBinaryOperator::Bind( + auto BoundOperator = BoundBinaryOperator::Bind( BinaryExpression->OperatorToken->Kind(), BoundLeft->Type(), BoundRight->Type() @@ -422,7 +423,7 @@ BoundCallExpression* Binder::BindCallExpression(const CallExpressionSyntax* Call for (auto&& Argument : CallExpression->Arguments.Nodes()) { // Argument is guaranteed to be a expression by the parser. - const auto BoundArgument = BindExpression(static_cast(Argument)); + auto BoundArgument = BindExpression(static_cast(Argument)); // TODO: Use hatcher to avoid copy BoundArguments.emplace_back(BoundArgument); @@ -431,7 +432,7 @@ BoundCallExpression* Binder::BindCallExpression(const CallExpressionSyntax* Call // TODO: Refinement Jvav standard // [basic.lookup]/? : If the declarations found by name lookup all denote functions, // the declarations are said to form an overload set. - const auto FunctionSet = Scope->LookupFunction(CallExpression->Identifier->Text()); + auto FunctionSet = Scope->LookupFunction(CallExpression->Identifier->Text()); if (FunctionSet.empty()) { // TODO: Diagnostics - undeclaraed function @@ -440,7 +441,7 @@ BoundCallExpression* Binder::BindCallExpression(const CallExpressionSyntax* Call } // TODO: Overload resolution. Before overload resolution is avaiable, function override is not permitted. - const auto Function = FunctionSet.front(); + auto Function = FunctionSet.front(); if (CallExpression->Arguments.Count() != Function->Parameters.size()) { @@ -461,10 +462,10 @@ NullablePointer Binder::BindTypeClause(NullablePointerLookupType(TypeClause->Identifier->Text()); + auto Types = Scope->LookupType(TypeClause->Identifier->Text()); if (Types.empty()) { - // TODO: Diagnostics - undeclaraed type + Diagnostics.ReportUndeclaredIdentifier(TypeClause->Identifier->Location(), TypeClause->Identifier->Text()); return {}; } @@ -480,7 +481,17 @@ void Binder::DeclareBuiltinFunctions() noexcept { } +void Binder::DeclareBuiltinTypes() noexcept +{ + Scope->Declare(&TypeSymbol::Int); + Scope->Declare(&TypeSymbol::Bool); + Scope->Declare(&TypeSymbol::String); + Scope->Declare(&TypeSymbol::Void); + Scope->Declare(&TypeSymbol::Double); +} + Binder::Binder(const class SyntaxTree* SyntaxTree) noexcept : Scope(new BoundScope(nullptr)), SyntaxTree(SyntaxTree) { + DeclareBuiltinTypes(); } diff --git a/src/Mamba/Code Analysis/Binding/Binder.h b/src/Mamba/Code Analysis/Binding/Binder.h index 19a808b..7ad1e19 100644 --- a/src/Mamba/Code Analysis/Binding/Binder.h +++ b/src/Mamba/Code Analysis/Binding/Binder.h @@ -89,7 +89,8 @@ namespace Mamba ScopeGuard EnterScope() noexcept; void DeclareBuiltinFunctions() noexcept; - void DeclareBuiltinFunction(); + void DeclareBuiltinFunction() noexcept; + void DeclareBuiltinTypes() noexcept; public: DiagnosticBag Diagnostics; diff --git a/src/Mamba/Code Analysis/Binding/BoundBinaryOperator.cpp b/src/Mamba/Code Analysis/Binding/BoundBinaryOperator.cpp index 69ca817..59fc347 100644 --- a/src/Mamba/Code Analysis/Binding/BoundBinaryOperator.cpp +++ b/src/Mamba/Code Analysis/Binding/BoundBinaryOperator.cpp @@ -4,18 +4,18 @@ using namespace Mamba; -BoundBinaryOperator::BoundBinaryOperator(SyntaxKind Kind, BoundBinaryOperatorKind BoundKind, const TypeSymbol* Type) noexcept : - BoundBinaryOperator(Kind, BoundKind, Type, Type, Type) +BoundBinaryOperator::BoundBinaryOperator(SyntaxKind Kind, BoundBinaryOperatorKind OperatorKind, const TypeSymbol* Type) noexcept : + BoundBinaryOperator(Kind, OperatorKind, Type, Type, Type) { } -BoundBinaryOperator::BoundBinaryOperator(SyntaxKind Kind, BoundBinaryOperatorKind BoundKind, const TypeSymbol* OperandType, const TypeSymbol* ResultType) noexcept : - BoundBinaryOperator(Kind, BoundKind, OperandType, OperandType, ResultType) +BoundBinaryOperator::BoundBinaryOperator(SyntaxKind Kind, BoundBinaryOperatorKind OperatorKind, const TypeSymbol* OperandType, const TypeSymbol* ResultType) noexcept : + BoundBinaryOperator(Kind, OperatorKind, OperandType, OperandType, ResultType) { } -BoundBinaryOperator::BoundBinaryOperator(SyntaxKind Kind, BoundBinaryOperatorKind BoundKind, const TypeSymbol* LeftType, const TypeSymbol* RightType, const TypeSymbol* ResultType) noexcept : - Kind(Kind), BoundKind(BoundKind), LeftType(LeftType), RightType(RightType), Type(ResultType) +BoundBinaryOperator::BoundBinaryOperator(SyntaxKind Kind, BoundBinaryOperatorKind OperatorKind, const TypeSymbol* LeftType, const TypeSymbol* RightType, const TypeSymbol* ResultType) noexcept : + Kind(Kind), OperatorKind(OperatorKind), LeftType(LeftType), RightType(RightType), Type(ResultType) { } diff --git a/src/Mamba/Code Analysis/Binding/BoundBinaryOperator.h b/src/Mamba/Code Analysis/Binding/BoundBinaryOperator.h index 673e51c..a7e4393 100644 --- a/src/Mamba/Code Analysis/Binding/BoundBinaryOperator.h +++ b/src/Mamba/Code Analysis/Binding/BoundBinaryOperator.h @@ -10,9 +10,9 @@ namespace Mamba { class BoundBinaryOperator { - [[nodiscard]] BoundBinaryOperator(SyntaxKind SyntaxKind, BoundBinaryOperatorKind Kind, const TypeSymbol* Type) noexcept; - [[nodiscard]] BoundBinaryOperator(SyntaxKind SyntaxKind, BoundBinaryOperatorKind Kind, const TypeSymbol* OperandType, const TypeSymbol* ResultType) noexcept; - [[nodiscard]] BoundBinaryOperator(SyntaxKind SyntaxKind, BoundBinaryOperatorKind Kind, const TypeSymbol* LeftType, const TypeSymbol* RightType, const TypeSymbol* ResultType) noexcept; + [[nodiscard]] BoundBinaryOperator(SyntaxKind Kind, BoundBinaryOperatorKind OperatorKind, const TypeSymbol* Type) noexcept; + [[nodiscard]] BoundBinaryOperator(SyntaxKind Kind, BoundBinaryOperatorKind OperatorKind, const TypeSymbol* OperandType, const TypeSymbol* ResultType) noexcept; + [[nodiscard]] BoundBinaryOperator(SyntaxKind Kind, BoundBinaryOperatorKind OperatorKind, const TypeSymbol* LeftType, const TypeSymbol* RightType, const TypeSymbol* ResultType) noexcept; BoundBinaryOperator(const BoundBinaryOperator&) = delete; BoundBinaryOperator(BoundBinaryOperator&&) = delete; @@ -21,8 +21,8 @@ namespace Mamba BoundBinaryOperator& operator=(BoundBinaryOperator&&) = delete; public: - enum SyntaxKind Kind; - BoundBinaryOperatorKind BoundKind; + SyntaxKind Kind; + BoundBinaryOperatorKind OperatorKind; const TypeSymbol* LeftType; const TypeSymbol* RightType; const TypeSymbol* Type; diff --git a/src/Mamba/Code Analysis/Binding/BoundLiteralExpression.cpp b/src/Mamba/Code Analysis/Binding/BoundLiteralExpression.cpp index 2429eba..2239da8 100644 --- a/src/Mamba/Code Analysis/Binding/BoundLiteralExpression.cpp +++ b/src/Mamba/Code Analysis/Binding/BoundLiteralExpression.cpp @@ -2,7 +2,9 @@ #include "MambaCore.h" #include "TypeSymbol.h" +#include #include +#include #include #include @@ -55,5 +57,18 @@ const TypeSymbol* BoundLiteralExpression::Type() const noexcept Constant BoundLiteralExpression::ConstantValue() const noexcept { - return std::visit([](auto Value) -> Constant { return Value; }, Value.Value); + return std::visit( + [](T&& Value) -> Constant { + if constexpr (std::is_same_v, LiteralType::Number>) + { + if (Value <= static_cast(std::numeric_limits::max())) + { + return static_cast(Value); + } + } + + return Value; + }, + Value.Value + ); } diff --git a/src/Mamba/Code Analysis/Binding/BoundScope.cpp b/src/Mamba/Code Analysis/Binding/BoundScope.cpp index a494a07..00ee821 100644 --- a/src/Mamba/Code Analysis/Binding/BoundScope.cpp +++ b/src/Mamba/Code Analysis/Binding/BoundScope.cpp @@ -1,4 +1,5 @@ #include "BoundScope.h" +#include "TypeSymbol.h" using namespace Mamba; @@ -7,6 +8,16 @@ BoundScope::BoundScope(NullablePointer Parent) noexcept : BoundScope::~BoundScope() noexcept { + for (auto Symbol : DeclaredSymbols()) + { + if (TypeSymbol::IsBuiltInType(static_cast(Symbol))) + { + continue; + } + + delete Symbol; + } + for (auto Child : Children) { delete Child; @@ -20,7 +31,7 @@ void BoundScope::Declare(const Symbol* Symbol) noexcept BoundScope* BoundScope::DeclareScope() noexcept { - const auto ChildScope = new BoundScope(this); + auto ChildScope = new BoundScope(this); Children.emplace_back(ChildScope); return ChildScope; } @@ -59,7 +70,7 @@ std::vector BoundScope::LookupParameter(StringView Name) std::vector BoundScope::Lookup(StringView Name) const noexcept { - const auto Result = Symbols.find(Name); + auto Result = Symbols.find(Name); if (Result != Symbols.end()) [[unlikely]] { return Result->second; diff --git a/src/Mamba/Code Analysis/Binding/ConstantFolding.cpp b/src/Mamba/Code Analysis/Binding/ConstantFolding.cpp index 8b6fdf9..1073fb6 100644 --- a/src/Mamba/Code Analysis/Binding/ConstantFolding.cpp +++ b/src/Mamba/Code Analysis/Binding/ConstantFolding.cpp @@ -33,13 +33,13 @@ Constant ConstantFolding::Fold( const BoundExpression* Right ) noexcept { - const auto LeftConstant = Left->ConstantValue(); - const auto RightConstant = Right->ConstantValue(); + auto LeftConstant = Left->ConstantValue(); + auto RightConstant = Right->ConstantValue(); // Special case && and || because there are cases where only one // side needs to be known. - if (Operator.BoundKind == BoundBinaryOperatorKind::LogicalAnd) + if (Operator.OperatorKind == BoundBinaryOperatorKind::LogicalAnd) { if ((LeftConstant.IsValid() && !LeftConstant.Get()) || (RightConstant.IsValid() && !RightConstant.Get())) @@ -48,7 +48,7 @@ Constant ConstantFolding::Fold( } } - if (Operator.BoundKind == BoundBinaryOperatorKind::LogicalOr) + if (Operator.OperatorKind == BoundBinaryOperatorKind::LogicalOr) { if ((LeftConstant.IsValid() && LeftConstant.Get()) || (RightConstant.IsValid() && RightConstant.Get())) @@ -62,7 +62,7 @@ Constant ConstantFolding::Fold( return {}; } - switch (Operator.BoundKind) + switch (Operator.OperatorKind) { case BoundBinaryOperatorKind::Addition: return LeftConstant + RightConstant; diff --git a/src/Mamba/Code Analysis/Compiler.cpp b/src/Mamba/Code Analysis/Compiler.cpp index 25e9939..5e52912 100644 --- a/src/Mamba/Code Analysis/Compiler.cpp +++ b/src/Mamba/Code Analysis/Compiler.cpp @@ -30,9 +30,9 @@ void Compiler::PrivateAddSourceFile(const std::string_view FileName) noexcept { try { - const auto FileLoader = fast_io::native_file_loader(FileName); + auto FileLoader = fast_io::native_file_loader(FileName); - const auto Info = SourceTextInfo{ + auto Info = SourceTextInfo{ .FileName = Concat(fast_io::mnp::code_cvt(FileName)), .Text = String(FileLoader.begin(), FileLoader.end()) }; @@ -107,10 +107,10 @@ void Compiler::Compile() noexcept PrintDiagnostics(Binder.Diagnostics); } + LLVMBackend::GenerateCode(BoundCompilationUnits, "Main"); + for (auto&& BoundCompilationUnit : BoundCompilationUnits) { delete BoundCompilationUnit; } - - LLVMBackend::GenerateCode(BoundCompilationUnits, "Main"); } \ No newline at end of file diff --git a/src/Mamba/Code Analysis/DiagnosticBag.cpp b/src/Mamba/Code Analysis/DiagnosticBag.cpp index 5e826c1..9bd86f2 100644 --- a/src/Mamba/Code Analysis/DiagnosticBag.cpp +++ b/src/Mamba/Code Analysis/DiagnosticBag.cpp @@ -3,7 +3,6 @@ #include "BreakStatementSyntax.h" #include "CallExpressionSyntax.h" #include "ContinueStatementSyntax.h" -#include "Diagnostic.h" #include "DoWhileStatementSyntax.h" #include "ExpressionStatementSyntax.h" #include "ForStatementSyntax.h" @@ -22,53 +21,37 @@ namespace Mamba { - void DiagnosticBag::AddRange(const std::vector& Diagnostics) noexcept - { -#if __cpp_lib_containers_ranges == 202202L - append_range(Diagnostics); -#else - for (auto&& Diagnostic : Diagnostics) - { - emplace_back(std::forward(Diagnostic)); - } -#endif - } - - void DiagnosticBag::ReportInvalidCharacter(const TextLocation Location, const Char Character) noexcept + void DiagnosticBag::ReportInvalidCharacter(TextLocation Location, Char Character) noexcept { ReportError(Location, TEXT("无效字符 '"), fast_io::mnp::chvw(Character), TEXT("'.")); } - void DiagnosticBag::ReportUnterminatedString(const TextLocation Location) noexcept + void DiagnosticBag::ReportUnterminatedString(TextLocation Location) noexcept { ReportError(Location, TEXT("未结束的字符串字面量")); } - void DiagnosticBag::ReportInvalidDecimal(const TextLocation Location, const StringView Literal) noexcept + void DiagnosticBag::ReportInvalidDecimal(TextLocation Location, StringView Literal) noexcept { ReportError(Location, Concat(TEXT("无效十进制字面量 '"), Literal, TEXT("'."))); } - void DiagnosticBag::ReportInvalidHexadecimal(const TextLocation Location, const StringView Literal) noexcept + void DiagnosticBag::ReportInvalidHexadecimal(TextLocation Location, StringView Literal) noexcept { ReportError(Location, Concat(TEXT("无效十六进制字面量 '"), Literal, TEXT("'."))); } - void DiagnosticBag::ReportInvalidBinary(const TextLocation Location, const StringView Literal) noexcept + void DiagnosticBag::ReportInvalidBinary(TextLocation Location, StringView Literal) noexcept { ReportError(Location, Concat(TEXT("无效二进制字面量 '"), Literal, TEXT("'."))); } - void DiagnosticBag::ReportInvalidOctal(const TextLocation Location, const StringView Literal) noexcept + void DiagnosticBag::ReportInvalidOctal(TextLocation Location, StringView Literal) noexcept { ReportError(Location, Concat(TEXT("无效八进制字面量 '"), Literal, TEXT("'."))); } - void DiagnosticBag::ReportUnexpectedToken( - const TextLocation Location, - const SyntaxKind Kind, - const SyntaxKind ExpectedKind - ) noexcept + void DiagnosticBag::ReportUnexpectedToken(TextLocation Location, SyntaxKind Kind, SyntaxKind ExpectedKind) noexcept { // Unexpected token 'Kind', Expected: 'ExpectedKind'. if (ExpectedKind == SyntaxKind::IdentifierToken) @@ -89,12 +72,12 @@ namespace Mamba } } - void DiagnosticBag::ReportDiscardExpressionValue(const TextLocation Location) noexcept + void DiagnosticBag::ReportDiscardExpressionValue(TextLocation Location) noexcept { ReportWarning(Location, TEXT("表达式的结果被忽略")); } - void DiagnosticBag::ReportVariableAlreadyDeclared(const TextLocation Location, StringView Name) noexcept + void DiagnosticBag::ReportVariableAlreadyDeclared(TextLocation Location, StringView Name) noexcept { // Variable 'Name' is already declared, previous declaration at FileName:StartLine:StartCharacter. ReportError( diff --git a/src/Mamba/Code Analysis/DiagnosticBag.h b/src/Mamba/Code Analysis/DiagnosticBag.h index 6fd90fa..0673df7 100644 --- a/src/Mamba/Code Analysis/DiagnosticBag.h +++ b/src/Mamba/Code Analysis/DiagnosticBag.h @@ -14,45 +14,39 @@ namespace Mamba public: using Super = std::vector; - void AddRange(const std::vector& Diagnostics) noexcept; - private: template - void ReportError(const TextLocation Location, T&&... Args) noexcept + void ReportError(TextLocation Location, T&&... Args) noexcept { emplace_back(DiagnosticSeverity::Error, Location, Concat(std::forward(Args)...)); } template - void ReportWarning(const TextLocation Location, T&&... Args) noexcept + void ReportWarning(TextLocation Location, T&&... Args) noexcept { emplace_back(DiagnosticSeverity::Warning, Location, Concat(std::forward(Args)...)); } template - void ReportInformation(const TextLocation Location, T&&... Args) noexcept + void ReportInformation(TextLocation Location, T&&... Args) noexcept { emplace_back(DiagnosticSeverity::Warning, Location, Concat(std::forward(Args)...)); } public: - void ReportInvalidCharacter(const TextLocation Location, const Char Character) noexcept; - void ReportUnterminatedString(const TextLocation Location) noexcept; - - void ReportInvalidDecimal(const TextLocation Location, const StringView Literal) noexcept; - void ReportInvalidHexadecimal(const TextLocation Location, const StringView Literal) noexcept; - void ReportInvalidBinary(const TextLocation Location, const StringView Literal) noexcept; - void ReportInvalidOctal(const TextLocation Location, const StringView Literal) noexcept; - - void ReportUnexpectedToken( - const TextLocation Location, - const SyntaxKind Kind, - const SyntaxKind ExpectedKind - ) noexcept; - - void ReportDiscardExpressionValue(const TextLocation Location) noexcept; - void ReportVariableAlreadyDeclared(const TextLocation Location, StringView Name) noexcept; - void ReportUnreachableCode(const TextLocation Location) noexcept; + void ReportInvalidCharacter(TextLocation Location, Char Character) noexcept; + void ReportUnterminatedString(TextLocation Location) noexcept; + + void ReportInvalidDecimal(TextLocation Location, StringView Literal) noexcept; + void ReportInvalidHexadecimal(TextLocation Location, StringView Literal) noexcept; + void ReportInvalidBinary(TextLocation Location, StringView Literal) noexcept; + void ReportInvalidOctal(TextLocation Location, StringView Literal) noexcept; + + void ReportUnexpectedToken(TextLocation Location, SyntaxKind Kind, SyntaxKind ExpectedKind) noexcept; + + void ReportDiscardExpressionValue(TextLocation Location) noexcept; + void ReportVariableAlreadyDeclared(TextLocation Location, StringView Name) noexcept; + void ReportUnreachableCode(TextLocation Location) noexcept; void ReportUnreachableCode(const SyntaxNode* Node) noexcept; void ReportUndeclaredIdentifier(TextLocation Location, StringView Name) noexcept; diff --git a/src/Mamba/Code Analysis/Symbol/Symbol.h b/src/Mamba/Code Analysis/Symbol/Symbol.h index c2c9cbe..8c515ff 100644 --- a/src/Mamba/Code Analysis/Symbol/Symbol.h +++ b/src/Mamba/Code Analysis/Symbol/Symbol.h @@ -12,9 +12,10 @@ namespace Mamba protected: [[nodiscard]] Symbol(StringView Name) noexcept; - virtual ~Symbol() = default; public: + virtual ~Symbol() = default; + [[nodiscard]] StringView Name() const noexcept; [[nodiscard]] virtual SymbolKind Kind() const noexcept = 0; [[nodiscard]] bool IsFunction() const noexcept; diff --git a/src/Mamba/Code Analysis/Symbol/TypeSymbol.cpp b/src/Mamba/Code Analysis/Symbol/TypeSymbol.cpp index 7cecf1b..2ba959e 100644 --- a/src/Mamba/Code Analysis/Symbol/TypeSymbol.cpp +++ b/src/Mamba/Code Analysis/Symbol/TypeSymbol.cpp @@ -15,7 +15,8 @@ bool TypeSymbol::IsBuiltInType(const TypeSymbol* Type) noexcept return Type == &TypeSymbol::Int || Type == &TypeSymbol::Bool || Type == &TypeSymbol::String || - Type == &TypeSymbol::Void; + Type == &TypeSymbol::Void || + Type == &TypeSymbol::Double; } const TypeSymbol TypeSymbol::Int = TypeSymbol(TEXT("int")); diff --git a/src/Mamba/Code Analysis/Syntax/Constant.h b/src/Mamba/Code Analysis/Syntax/Constant.h index dd68052..cca5bce 100644 --- a/src/Mamba/Code Analysis/Syntax/Constant.h +++ b/src/Mamba/Code Analysis/Syntax/Constant.h @@ -46,6 +46,11 @@ namespace Mamba return std::get(Value); } + [[nodiscard]] constexpr ValueType& GetValue() noexcept + { + return Value; + } + [[nodiscard]] constexpr bool IsValid() const noexcept { return !Value.valueless_by_exception(); diff --git a/src/Mamba/Code Analysis/Syntax/Lexer.cpp b/src/Mamba/Code Analysis/Syntax/Lexer.cpp index 0aca2cc..4ea5770 100644 --- a/src/Mamba/Code Analysis/Syntax/Lexer.cpp +++ b/src/Mamba/Code Analysis/Syntax/Lexer.cpp @@ -355,9 +355,9 @@ namespace Mamba // one or more binary digits (0, 1) // The current character is guaranteed to be a digit - if (Current() != TEXT('0')) + if (Current() == TEXT('0') && IsOctalDigit(Lookahead())) { - ReadDecimal(); + ReadOctal(); } else if (Lookahead() == TEXT('x') || Lookahead() == TEXT('X')) { @@ -367,8 +367,10 @@ namespace Mamba { ReadBinary(); } - - ReadOctal(); + else + { + ReadDecimal(); + } Kind = SyntaxKind::NumberToken; } @@ -413,7 +415,7 @@ namespace Mamba void Lexer::ReadOctal() noexcept { - while (IsHexadecimalDigit(Current())) + while (IsOctalDigit(Current())) { ++Position; } diff --git a/src/Mamba/Code Analysis/Syntax/Lexer.h b/src/Mamba/Code Analysis/Syntax/Lexer.h index 1b9508d..a9a2991 100644 --- a/src/Mamba/Code Analysis/Syntax/Lexer.h +++ b/src/Mamba/Code Analysis/Syntax/Lexer.h @@ -75,7 +75,7 @@ namespace Mamba void ReportInvalidNumber(StringView LiteralText) requires(Base == 2 || Base == 8 || Base == 10 || Base == 16) { - const auto Location = TextLocation(Text(), LiteralText); + auto Location = TextLocation(Text(), LiteralText); if constexpr (Base == 10) { Diagnostics.ReportInvalidDecimal(Location, LiteralText); diff --git a/src/Mamba/Code Analysis/Syntax/Parser.cpp b/src/Mamba/Code Analysis/Syntax/Parser.cpp index dba644b..dff0ac3 100644 --- a/src/Mamba/Code Analysis/Syntax/Parser.cpp +++ b/src/Mamba/Code Analysis/Syntax/Parser.cpp @@ -47,7 +47,7 @@ const SyntaxToken* Parser::Current() noexcept const SyntaxToken* Parser::NextToken() noexcept { - const auto Current = this->Current(); + auto Current = this->Current(); ++Position; return Current; } @@ -161,7 +161,7 @@ ParameterSyntax* Parser::ParseParameter() noexcept MemberSyntax* Parser::ParseGlobalStatement() noexcept { - const auto Statement = ParseStatement(); + auto Statement = ParseStatement(); return new GlobalStatementSyntax(SyntaxTree, Statement); } @@ -369,9 +369,9 @@ ExpressionSyntax* Parser::ParseAssignmentExpression() noexcept case SyntaxKind::HatEqualsToken: case SyntaxKind::EqualsToken: { - const auto IdentifierToken = NextToken(); - const auto OperatorToken = NextToken(); - const auto Right = ParseAssignmentExpression(); + auto IdentifierToken = NextToken(); + auto OperatorToken = NextToken(); + auto Right = ParseAssignmentExpression(); return new AssignmentExpressionSyntax(SyntaxTree, IdentifierToken, OperatorToken, Right); } default: @@ -516,6 +516,6 @@ SeperatedSyntaxList Parser::ParseArguments() noexcept NameExpressionSyntax* Parser::ParseNameExpression() noexcept { - const auto IdentifierToken = MatchToken(SyntaxKind::IdentifierToken); + auto IdentifierToken = MatchToken(SyntaxKind::IdentifierToken); return new NameExpressionSyntax(SyntaxTree, IdentifierToken); } \ No newline at end of file diff --git a/src/Mamba/Code Analysis/Syntax/SyntaxFacts.cpp b/src/Mamba/Code Analysis/Syntax/SyntaxFacts.cpp index 7e932fc..9b4739e 100644 --- a/src/Mamba/Code Analysis/Syntax/SyntaxFacts.cpp +++ b/src/Mamba/Code Analysis/Syntax/SyntaxFacts.cpp @@ -57,7 +57,7 @@ namespace Mamba SyntaxKind SyntaxFacts::GetKeywordKind(const StringView Text) noexcept { - static const auto KeywordsMap = std::unordered_map{ + static auto KeywordsMap = std::unordered_map{ std::make_pair(TEXT("if"), SyntaxKind::IfKeyword), std::make_pair(TEXT("else"), SyntaxKind::ElseKeyword), @@ -79,7 +79,7 @@ namespace Mamba std::make_pair(TEXT("return"), SyntaxKind::ReturnKeyword), }; - const auto Iterator = KeywordsMap.find(Text); + auto Iterator = KeywordsMap.find(Text); if (Iterator != KeywordsMap.end()) { return Iterator->second; @@ -405,7 +405,7 @@ namespace Mamba return SyntaxKind::HatToken; default: #ifdef DEBUG - const auto Message = + auto Message = Concat(TEXT("No binary operator for assignment operator: '"), GetText(Kind), TEXT("'")); fast_io::io::perrln(fast_io::mnp::code_cvt(Message)); #endif diff --git a/src/Mamba/Code Analysis/Syntax/SyntaxNode.cpp b/src/Mamba/Code Analysis/Syntax/SyntaxNode.cpp index 3ba2071..ef2bc54 100644 --- a/src/Mamba/Code Analysis/Syntax/SyntaxNode.cpp +++ b/src/Mamba/Code Analysis/Syntax/SyntaxNode.cpp @@ -22,8 +22,8 @@ const SyntaxTree* Mamba::SyntaxNode::Tree() const noexcept StringView SyntaxNode::Text() const noexcept { - const auto First = Children().front()->Text(); - const auto Last = Children().back()->Text(); + auto First = Children().front()->Text(); + auto Last = Children().back()->Text(); return { First.begin(), Last.end() }; } diff --git a/src/Mamba/Code Analysis/Syntax/SyntaxTree.cpp b/src/Mamba/Code Analysis/Syntax/SyntaxTree.cpp index b8b51d2..042c49e 100644 --- a/src/Mamba/Code Analysis/Syntax/SyntaxTree.cpp +++ b/src/Mamba/Code Analysis/Syntax/SyntaxTree.cpp @@ -22,7 +22,7 @@ SyntaxTree::~SyntaxTree() noexcept NullablePointer SyntaxTree::Parent(const SyntaxNode& Node) const noexcept { - const auto Iterator = ParentsMap.find(&Node); + auto Iterator = ParentsMap.find(&Node); if (Iterator == ParentsMap.end()) { return {}; diff --git a/src/Mamba/Code Analysis/Text/SourceText.cpp b/src/Mamba/Code Analysis/Text/SourceText.cpp index f8c3124..aa4453d 100644 --- a/src/Mamba/Code Analysis/Text/SourceText.cpp +++ b/src/Mamba/Code Analysis/Text/SourceText.cpp @@ -108,24 +108,22 @@ std::vector SourceText::SplitLines(const SourceTextInfo& Info) auto LineStart = std::size_t(); #endif - const auto& Text = Info.Text; + auto& Text = Info.Text; while (Position < Text.length()) { - auto LineBreakWidth = GetLineBreakWidth(Text, Position); + auto LineBreakWidth = GetLineBreakWidth(Text, Position++); if (LineBreakWidth == 0) { - ++Position; + continue; } - else - { - auto LineLength = Position - LineStart; - auto LineLengthIncludingLineBreak = LineLength + LineBreakWidth; - Lines.emplace_back(LineStart + 1, LineLength, LineLengthIncludingLineBreak); - Position += LineBreakWidth; - LineStart = Position; - } + auto LineLength = Position - LineStart; + auto LineLengthIncludingLineBreak = LineLength + LineBreakWidth; + Lines.emplace_back(LineStart, LineLength, LineLengthIncludingLineBreak); + + Position += LineBreakWidth; + LineStart = Position; } if (Position >= LineStart) diff --git a/src/Mamba/Code Analysis/Text/TextLocation.cpp b/src/Mamba/Code Analysis/Text/TextLocation.cpp index 2c7fd74..4f4fb94 100644 --- a/src/Mamba/Code Analysis/Text/TextLocation.cpp +++ b/src/Mamba/Code Analysis/Text/TextLocation.cpp @@ -25,6 +25,11 @@ std::size_t TextLocation::EndLine() const noexcept } std::size_t TextLocation::AbsoluteEndCharacter() const noexcept +{ + return Text.RelativeEnd(View); +} + +std::size_t TextLocation::RelativeEndCharacter() const noexcept { auto Line = Text.Lines()[EndLine()]; return AbsoluteEndCharacter() - Line.End(); diff --git a/src/Mamba/Code Analysis/Text/TextSpan.cpp b/src/Mamba/Code Analysis/Text/TextSpan.cpp index 4605bd2..dfe5235 100644 --- a/src/Mamba/Code Analysis/Text/TextSpan.cpp +++ b/src/Mamba/Code Analysis/Text/TextSpan.cpp @@ -9,7 +9,7 @@ std::size_t TextSpan::End() const noexcept TextSpan TextSpan::FromBounds(const std::size_t Start, const std::size_t End) noexcept { - const auto Length = End - Start; + auto Length = End - Start; return TextSpan(Start, Length); } diff --git a/src/Mamba/Code Generation/Emitter.h b/src/Mamba/Code Generation/Emitter.h deleted file mode 100644 index 699ca41..0000000 --- a/src/Mamba/Code Generation/Emitter.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "BoundProgram.h" -#include "Diagnostic.h" - -#ifndef __has_declspec_attribute - #define __has_declspec_attribute(x) 0 -#endif - -namespace Mamba -{ - class -#if defined(MSVC_VER) || __has_declspec_attribute(novtable) - // Emitter is a pure - #define __declspec(novtable) -#endif - Emitter - { - public: - virtual std::vector Emit(const BoundProgram& Program, StringView ModuleName) noexcept = 0; - }; -} // namespace Mamba \ No newline at end of file diff --git a/src/Mamba/Code Generation/LLVMBackend.cpp b/src/Mamba/Code Generation/LLVMBackend.cpp index 71c5a07..88db2c5 100644 --- a/src/Mamba/Code Generation/LLVMBackend.cpp +++ b/src/Mamba/Code Generation/LLVMBackend.cpp @@ -1,16 +1,272 @@ #include "LLVMBackend.h" +#include "BlockStatementSyntax.h" +#include "BoundBinaryExpression.h" +#include "BoundBinaryOperatorKind.h" +#include "BoundBlockStatement.h" +#include "BoundExpression.h" +#include "BoundFunctionDeclaration.h" +#include "BoundLiteralExpression.h" +#include "BoundNodeKind.h" +#include "BoundReturnStatement.h" +#include "BoundStatement.h" +#include "Constant.h" +#include "FunctionSymbol.h" +#include "MambaCore.h" +#include "MambaLogger.h" +#include "TypeSymbol.h" + +#include +#include +#include + +#include "BoundBlockStatement.h" +#include "fast_io.h" +#include "fast_io_core_impl/codecvt/general.h" + +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/TargetParser/Host.h" using namespace Mamba; using namespace llvm; +void InitializeLLVM() noexcept +{ + static bool Initialized = false; + if (Initialized) [[unlikely]] + { + return; + } + + Verbose("正在初始化LLVM"); + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmParsers(); + InitializeAllAsmPrinters(); +} + +Type* GetLLVMType(LLVMContext& Context, const TypeSymbol* Type) noexcept +{ + if (Type == &TypeSymbol::Void) + { + return Type::getVoidTy(Context); + } + else if (Type == &TypeSymbol::Int) + { + return Type::getInt32Ty(Context); + } + else if (Type == &TypeSymbol::Bool) + { + return Type::getInt1Ty(Context); + } + else if (Type == &TypeSymbol::Double) + { + return Type::getDoubleTy(Context); + } + + InternalCompilerError(std::source_location::current(), "无法识别的类型: ", fast_io::mnp::code_cvt(Type->Name())); +} + +std::vector GetFunctionArgumentTypes(LLVMContext& Context, const FunctionSymbol& FunctionDeclaration) noexcept +{ + return FunctionDeclaration.Parameters | + std::views::transform([&](const ParameterSymbol* Parameter) -> Type* { return GetLLVMType(Context, Parameter->Type); }) | + std::ranges::to(); +} + +void GenerateStatement(LLVMContext& Context, Module& Module, IRBuilder<>& Builder, const BoundStatement& Statement) noexcept; + +Value* GenerateExpression(LLVMContext& Context, Module& Module, IRBuilder<>& Builder, const BoundExpression& Statement) noexcept; + +void GenerateBlockStatement(LLVMContext& Context, Module& Module, IRBuilder<>& Builder, const BoundBlockStatement& BlockStatement) noexcept +{ + for (auto&& Statement : BlockStatement.Statements) + { + GenerateStatement(Context, Module, Builder, *Statement); + } +} + +Value* GenerateBinaryExpression(LLVMContext& Context, Module& Module, IRBuilder<>& Builder, const BoundBinaryExpression& BinaryExpression) noexcept +{ + auto Left = GenerateExpression(Context, Module, Builder, *BinaryExpression.Left); + auto Right = GenerateExpression(Context, Module, Builder, *BinaryExpression.Right); + + if (!Left && !Right) + { + InternalCompilerError(std::source_location::current(), "二元表达式左右表达式均为空"); + } + else if (!Left) + { + InternalCompilerError(std::source_location::current(), "二元表达式左表达式为空"); + } + else if (!Right) + { + InternalCompilerError(std::source_location::current(), "二元表达式右表达式为空"); + } + + if (BinaryExpression.Operator.OperatorKind == BoundBinaryOperatorKind::Addition) + { + return Builder.CreateAdd(Left, Right); + } + + return {}; +} + +Value* GenerateLiteralExpression(LLVMContext& Context, Module& Module [[maybe_unused]], IRBuilder<>& Builder [[maybe_unused]], const BoundLiteralExpression& Expression) noexcept +{ + return Expression.ConstantValue().GetValue().visit([&](T&& Value) -> ConstantData* { + if constexpr (std::is_same_v, ConstantType::Int>) + { + return ConstantInt::get(Type::getInt32Ty(Context), Value); + } + else if constexpr (std::is_same_v, ConstantType::ULong>) + { + return ConstantInt::get(Type::getInt64Ty(Context), Value); + } + + return nullptr; + }); +} + +Value* GenerateExpression(LLVMContext& Context, Module& Module, IRBuilder<>& Builder, const BoundExpression& Statement) noexcept +{ + switch (Statement.Kind()) + { + case BoundNodeKind::BinaryExpression: + return GenerateBinaryExpression(Context, Module, Builder, dynamic_cast(Statement)); + case BoundNodeKind::LiteralExpression: + return GenerateLiteralExpression(Context, Module, Builder, dynamic_cast(Statement)); + default: + break; + } + return {}; +} + +void GenerateReturnStatement(LLVMContext& Context, Module& Module, IRBuilder<>& Builder, const BoundReturnStatement& Statement) noexcept +{ + auto Value = GenerateExpression(Context, Module, Builder, *Statement.Expression); + Builder.CreateRet(Value); +} + +void GenerateStatement(LLVMContext& Context, Module& Module, IRBuilder<>& Builder, const BoundStatement& Statement) noexcept +{ + switch (Statement.Kind()) + { + case BoundNodeKind::BlockStatement: + GenerateBlockStatement(Context, Module, Builder, dynamic_cast(Statement)); + break; + case BoundNodeKind::ExpressionStatement: + GenerateExpression(Context, Module, Builder, dynamic_cast(Statement)); + break; + case BoundNodeKind::ReturnStatement: + GenerateReturnStatement(Context, Module, Builder, dynamic_cast(Statement)); + break; + default: + break; + } +} + +void GenerateFunctionBody(LLVMContext& Context, Module& Module, IRBuilder<>& Builder, const BoundFunctionDeclaration& FunctionDeclaration) noexcept +{ + GenerateStatement(Context, Module, Builder, *FunctionDeclaration.Body); +} + +void GenerateFunction(LLVMContext& Context, Module& Module, IRBuilder<>& Builder, const FunctionSymbol& FunctionDeclaration) noexcept +{ + auto ReturnType = GetLLVMType(Context, FunctionDeclaration.Type); + auto ParameterTypes = GetFunctionArgumentTypes(Context, FunctionDeclaration); + + auto FunctionType = FunctionType::get(ReturnType, ParameterTypes, false); + auto Function = Function::Create(FunctionType, GlobalValue::ExternalLinkage, fast_io::concat(fast_io::mnp::code_cvt(FunctionDeclaration.Name())), &Module); + + auto Index = std::size_t(); + for (auto&& Argument : Function->args()) + { + Argument.setName(fast_io::concat(fast_io::mnp::code_cvt(FunctionDeclaration.Parameters[Index++]->Name()))); + } + + auto Block = BasicBlock::Create(Context, "entry", Function); + Builder.SetInsertPoint(Block); + GenerateFunctionBody(Context, Module, Builder, *FunctionDeclaration.BoundDeclaration); +} + +void GenerateCompilationUnit(LLVMContext& Context, Module& Module, IRBuilder<>& Builder, BoundCompilationUnit& CompilationUnit) noexcept +{ + for (auto&& Function : CompilationUnit.GlobalScope->DeclaredFunctions()) + { + GenerateFunction(Context, Module, Builder, *Function); + } +} + void LLVMBackend::GenerateCode(std::span CompilationUnits, std::string_view ModuleName) noexcept { + InitializeLLVM(); + auto Context = LLVMContext(); auto LLVMModule = Module(ModuleName, Context); - auto Builder = IRBuilder<>(Context); + + for (auto&& CompilationUnit : CompilationUnits) + { + GenerateCompilationUnit(Context, LLVMModule, Builder, *CompilationUnit); + } + + auto TargetTriple = sys::getDefaultTargetTriple(); + auto ErrorString = std::string(); + auto Target = TargetRegistry::lookupTarget(TargetTriple, ErrorString); + if (!Target) + { + InternalCompilerError(std::source_location::current(), "无法找到请求的目标三元组: ", ErrorString); + } + + fast_io::io::println("编译到目标: ", TargetTriple); + + constexpr auto CPU = "generic"; + constexpr auto Features = ""; + + auto Options = TargetOptions(); + auto TargetMachine = Target->createTargetMachine(TargetTriple, CPU, Features, Options, Reloc::PIC_); + + LLVMModule.setDataLayout(TargetMachine->createDataLayout()); + LLVMModule.setTargetTriple(TargetTriple); + + // LLVMModule.print(errs(), nullptr); + + auto FileName = fast_io::concat(ModuleName, ".o"); + + auto error_code = std::error_code(); + raw_fd_ostream dest(FileName, error_code, sys::fs::OF_None); + if (error_code) + { + Error("无法打开输出文件: ", error_code.message()); + return; + } + + auto PassManager = legacy::PassManager(); + constexpr auto FileType = CodeGenFileType::ObjectFile; + + if (TargetMachine->addPassesToEmitFile(PassManager, dest, {}, FileType)) + { + InternalCompilerError(std::source_location::current(), "无法为目标生成代码"); + } + + PassManager.run(LLVMModule); + dest.flush(); + fast_io::io::println("编译成功: ", FileName); } \ No newline at end of file diff --git a/src/Mamba/Code Generation/LLVMBackend.h b/src/Mamba/Code Generation/LLVMBackend.h index 851c28f..9632355 100644 --- a/src/Mamba/Code Generation/LLVMBackend.h +++ b/src/Mamba/Code Generation/LLVMBackend.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "Backend.h" diff --git a/src/Mamba/Core/MambaLogger.h b/src/Mamba/Core/MambaLogger.h new file mode 100644 index 0000000..b0594aa --- /dev/null +++ b/src/Mamba/Core/MambaLogger.h @@ -0,0 +1,25 @@ +#pragma once + +#include "fast_io.h" + +namespace Mamba +{ + bool VerboseLoggingEnabled = true; + + auto MambaOut() noexcept + { + return fast_io::out(); + } + + template + void Verbose(T&&... Arguments) + { + if (!VerboseLoggingEnabled) + { + return; + } + + fast_io::io::println(MambaOut(), std::forward(Arguments)...); + } + +} // namespace Mamba \ No newline at end of file diff --git a/src/Mamba/MambaCore.h b/src/Mamba/MambaCore.h index d65db98..8e4828f 100644 --- a/src/Mamba/MambaCore.h +++ b/src/Mamba/MambaCore.h @@ -141,12 +141,21 @@ namespace Mamba ":", SourceLocation.column(), ": ", - Color("internal compiler error: ", Colors::BrightForegroundRed), + Color("内部编译器错误: ", Colors::BrightForegroundRed), std::forward(Args)... ); fast_io::fast_terminate(); } + template + [[noreturn]] void Error(T&&... Args) noexcept + { + fast_io::io::perrln( + Color("错误: ", Colors::BrightForegroundRed), + std::forward(Args)... + ); + } + // Hatcher stores a callable object, so that the result of the call can be emplace constructed into a container by // copy elision, the container must support adding new elements by forwarding arguments to the constructor // (emplace).