diff --git a/lib/parser/IParser.hpp b/lib/parser/IParser.hpp new file mode 100644 index 0000000..50bb764 --- /dev/null +++ b/lib/parser/IParser.hpp @@ -0,0 +1,20 @@ +#ifndef PARSER_IPARSER_HPP_ +#define PARSER_IPARSER_HPP_ + +#include + +#include "ast/nodes/decls/Module.hpp" +#include "diagnostics/IDiagnosticSink.hpp" +#include "tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class IParser { +public: + virtual ~IParser() = default; + virtual std::unique_ptr Parse(ITokenStream& ts, IDiagnosticSink& diags) = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IPARSER_HPP_ diff --git a/lib/parser/ParserFsm.cpp b/lib/parser/ParserFsm.cpp new file mode 100644 index 0000000..2989de7 --- /dev/null +++ b/lib/parser/ParserFsm.cpp @@ -0,0 +1,3 @@ +#include "ParserFsm.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/ParserFsm.hpp b/lib/parser/ParserFsm.hpp new file mode 100644 index 0000000..a4cba9a --- /dev/null +++ b/lib/parser/ParserFsm.hpp @@ -0,0 +1,31 @@ +#ifndef PARSER_PARSERFSM_HPP_ +#define PARSER_PARSERFSM_HPP_ + +#include + +#include "IParser.hpp" +#include "ast/IAstFactory.hpp" +#include "pratt/IExpressionParser.hpp" +#include "type_parser/ITypeParser.hpp" + +namespace ovum::compiler::parser { + +class ParserFsm : public IParser { +public: + ParserFsm(std::unique_ptr expr, + std::unique_ptr typep, + std::unique_ptr factory); + + ~ParserFsm() override = default; + + std::unique_ptr Parse(ITokenStream& ts, IDiagnosticSink& diags) override; + +private: + std::unique_ptr expr_parser_; + std::unique_ptr type_parser_; + std::unique_ptr factory_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_PARSERFSM_HPP_ diff --git a/lib/parser/ast/AstVisitor.hpp b/lib/parser/ast/AstVisitor.hpp new file mode 100644 index 0000000..a260ca1 --- /dev/null +++ b/lib/parser/ast/AstVisitor.hpp @@ -0,0 +1,98 @@ +#ifndef PARSER_ASTVISITOR_HPP_ +#define PARSER_ASTVISITOR_HPP_ + +#include "nodes/class_members/CallDecl.hpp" +#include "nodes/class_members/DestructorDecl.hpp" +#include "nodes/class_members/FieldDecl.hpp" +#include "nodes/class_members/MethodDecl.hpp" +#include "nodes/class_members/StaticFieldDecl.hpp" +#include "nodes/decls/ClassDecl.hpp" +#include "nodes/decls/FunctionDecl.hpp" +#include "nodes/decls/GlobalVarDecl.hpp" +#include "nodes/decls/InterfaceDecl.hpp" +#include "nodes/decls/Module.hpp" +#include "nodes/decls/TypeAliasDecl.hpp" +#include "nodes/exprs/Assign.hpp" +#include "nodes/exprs/Binary.hpp" +#include "nodes/exprs/Call.hpp" +#include "nodes/exprs/CastAs.hpp" +#include "nodes/exprs/Elvis.hpp" +#include "nodes/exprs/FieldAccess.hpp" +#include "nodes/exprs/IdentRef.hpp" +#include "nodes/exprs/IndexAccess.hpp" +#include "nodes/exprs/NamespaceRef.hpp" +#include "nodes/exprs/SafeCall.hpp" +#include "nodes/exprs/TypeTestIs.hpp" +#include "nodes/exprs/Unary.hpp" +#include "nodes/exprs/literals/BoolLit.hpp" +#include "nodes/exprs/literals/CharLit.hpp" +#include "nodes/exprs/literals/FloatLit.hpp" +#include "nodes/exprs/literals/IntLit.hpp" +#include "nodes/exprs/literals/NullLit.hpp" +#include "nodes/exprs/literals/StringLit.hpp" +#include "nodes/stmts/BreakStmt.hpp" +#include "nodes/stmts/ContinueStmt.hpp" +#include "nodes/stmts/ExprStmt.hpp" +#include "nodes/stmts/ForStmt.hpp" +#include "nodes/stmts/IfStmt.hpp" +#include "nodes/stmts/ReturnStmt.hpp" +#include "nodes/stmts/UnsafeBlock.hpp" +#include "nodes/stmts/VarDeclStmt.hpp" +#include "nodes/stmts/WhileStmt.hpp" + +namespace ovum::compiler::parser { + +class AstVisitor { +public: + virtual ~AstVisitor() = default; + + // Decls + virtual void Visit(Module&) = 0; + virtual void Visit(FunctionDecl&) = 0; + virtual void Visit(ClassDecl&) = 0; + virtual void Visit(InterfaceMethod&) = 0; + virtual void Visit(InterfaceDecl&) = 0; + virtual void Visit(TypeAliasDecl&) = 0; + virtual void Visit(GlobalVarDecl&) = 0; + virtual void Visit(FieldDecl&) = 0; + virtual void Visit(StaticFieldDecl&) = 0; + virtual void Visit(MethodDecl&) = 0; + virtual void Visit(CallDecl&) = 0; + virtual void Visit(DestructorDecl&) = 0; + + // Stmts + virtual void Visit(Block&) = 0; + virtual void Visit(VarDeclStmt&) = 0; + virtual void Visit(ExprStmt&) = 0; + virtual void Visit(ReturnStmt&) = 0; + virtual void Visit(BreakStmt&) = 0; + virtual void Visit(ContinueStmt&) = 0; + virtual void Visit(IfStmt&) = 0; + virtual void Visit(WhileStmt&) = 0; + virtual void Visit(ForStmt&) = 0; + virtual void Visit(UnsafeBlock&) = 0; + + // Exprs + virtual void Visit(Binary&) = 0; + virtual void Visit(Unary&) = 0; + virtual void Visit(Assign&) = 0; + virtual void Visit(Call&) = 0; + virtual void Visit(FieldAccess&) = 0; + virtual void Visit(IndexAccess&) = 0; + virtual void Visit(NamespaceRef&) = 0; + virtual void Visit(SafeCall&) = 0; + virtual void Visit(Elvis&) = 0; + virtual void Visit(CastAs&) = 0; + virtual void Visit(TypeTestIs&) = 0; + virtual void Visit(IdentRef&) = 0; + virtual void Visit(IntLit&) = 0; + virtual void Visit(FloatLit&) = 0; + virtual void Visit(StringLit&) = 0; + virtual void Visit(CharLit&) = 0; + virtual void Visit(BoolLit&) = 0; + virtual void Visit(NullLit&) = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_ASTVISITOR_HPP_ diff --git a/lib/parser/ast/IAstFactory.hpp b/lib/parser/ast/IAstFactory.hpp new file mode 100644 index 0000000..203cb6f --- /dev/null +++ b/lib/parser/ast/IAstFactory.hpp @@ -0,0 +1,96 @@ +#ifndef PARSER_IASTFACTORY_HPP_ +#define PARSER_IASTFACTORY_HPP_ + +#include + +#include "nodes/class_members/CallDecl.hpp" +#include "nodes/class_members/DestructorDecl.hpp" +#include "nodes/class_members/FieldDecl.hpp" +#include "nodes/class_members/MethodDecl.hpp" +#include "nodes/class_members/StaticFieldDecl.hpp" +#include "nodes/decls/ClassDecl.hpp" +#include "nodes/decls/FunctionDecl.hpp" +#include "nodes/decls/GlobalVarDecl.hpp" +#include "nodes/decls/InterfaceDecl.hpp" +#include "nodes/decls/TypeAliasDecl.hpp" +#include "nodes/exprs/Assign.hpp" +#include "nodes/exprs/Binary.hpp" +#include "nodes/exprs/Call.hpp" +#include "nodes/exprs/CastAs.hpp" +#include "nodes/exprs/Elvis.hpp" +#include "nodes/exprs/FieldAccess.hpp" +#include "nodes/exprs/IdentRef.hpp" +#include "nodes/exprs/IndexAccess.hpp" +#include "nodes/exprs/NamespaceRef.hpp" +#include "nodes/exprs/SafeCall.hpp" +#include "nodes/exprs/TypeTestIs.hpp" +#include "nodes/exprs/Unary.hpp" +#include "nodes/exprs/literals/BoolLit.hpp" +#include "nodes/exprs/literals/CharLit.hpp" +#include "nodes/exprs/literals/FloatLit.hpp" +#include "nodes/exprs/literals/IntLit.hpp" +#include "nodes/exprs/literals/NullLit.hpp" +#include "nodes/exprs/literals/StringLit.hpp" +#include "nodes/stmts/BreakStmt.hpp" +#include "nodes/stmts/ContinueStmt.hpp" +#include "nodes/stmts/ExprStmt.hpp" +#include "nodes/stmts/ForStmt.hpp" +#include "nodes/stmts/IfStmt.hpp" +#include "nodes/stmts/ReturnStmt.hpp" +#include "nodes/stmts/UnsafeBlock.hpp" +#include "nodes/stmts/VarDeclStmt.hpp" +#include "nodes/stmts/WhileStmt.hpp" + +namespace ovum::compiler::parser { + +class IAstFactory { +public: + virtual ~IAstFactory() = default; + + virtual std::unique_ptr MakeFunction() = 0; + virtual std::unique_ptr MakeClass() = 0; + virtual std::unique_ptr MakeInterface() = 0; + virtual std::unique_ptr MakeInterfaceMethod() = 0; + virtual std::unique_ptr MakeTypeAlias() = 0; + virtual std::unique_ptr MakeGlobalVar() = 0; + + virtual std::unique_ptr MakeField() = 0; + virtual std::unique_ptr MakeStaticField() = 0; + virtual std::unique_ptr MakeMethod() = 0; + virtual std::unique_ptr MakeCallDecl() = 0; + virtual std::unique_ptr MakeDestructor() = 0; + + virtual std::unique_ptr MakeBlock() = 0; + virtual std::unique_ptr MakeVarDeclStmt() = 0; + virtual std::unique_ptr MakeExprStmt() = 0; + virtual std::unique_ptr MakeReturnStmt() = 0; + virtual std::unique_ptr MakeBreakStmt() = 0; + virtual std::unique_ptr MakeContinueStmt() = 0; + virtual std::unique_ptr MakeIfStmt() = 0; + virtual std::unique_ptr MakeWhileStmt() = 0; + virtual std::unique_ptr MakeForStmt() = 0; + virtual std::unique_ptr MakeUnsafeBlock() = 0; + + virtual std::unique_ptr MakeBinary(const IBinaryOpTag& op) = 0; + virtual std::unique_ptr MakeUnary(const IUnaryOpTag& op) = 0; + virtual std::unique_ptr MakeAssign(const IAssignOpTag& op) = 0; + virtual std::unique_ptr MakeCall() = 0; + virtual std::unique_ptr MakeFieldAccess() = 0; + virtual std::unique_ptr MakeIndexAccess() = 0; + virtual std::unique_ptr MakeNamespaceRef() = 0; + virtual std::unique_ptr MakeSafeCall() = 0; + virtual std::unique_ptr MakeElvis() = 0; + virtual std::unique_ptr MakeCastAs() = 0; + virtual std::unique_ptr MakeTypeTestIs() = 0; + virtual std::unique_ptr MakeIdent(std::string name) = 0; + virtual std::unique_ptr MakeInt(long long v) = 0; + virtual std::unique_ptr MakeFloat(long double v) = 0; + virtual std::unique_ptr MakeString(std::u32string v) = 0; + virtual std::unique_ptr MakeChar(char32_t v) = 0; + virtual std::unique_ptr MakeBool(bool v) = 0; + virtual std::unique_ptr MakeNull() = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IASTFACTORY_HPP_ diff --git a/lib/parser/ast/nodes/base/AstNode.hpp b/lib/parser/ast/nodes/base/AstNode.hpp new file mode 100644 index 0000000..8e54691 --- /dev/null +++ b/lib/parser/ast/nodes/base/AstNode.hpp @@ -0,0 +1,19 @@ +#ifndef PARSER_ASTNODE_HPP_ +#define PARSER_ASTNODE_HPP_ + +namespace ovum::compiler::parser { + +class AstVisitor; // forward + +class AstNode { +public: + virtual ~AstNode() = default; + + // TODO: add positions...... + + virtual void Accept(AstVisitor& visitor) = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_ASTNODE_HPP_ diff --git a/lib/parser/ast/nodes/base/Decl.hpp b/lib/parser/ast/nodes/base/Decl.hpp new file mode 100644 index 0000000..26ac67e --- /dev/null +++ b/lib/parser/ast/nodes/base/Decl.hpp @@ -0,0 +1,12 @@ +#ifndef PARSER_DECL_HPP_ +#define PARSER_DECL_HPP_ + +#include "AstNode.hpp" + +namespace ovum::compiler::parser { + +class Decl : public AstNode {}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_DECL_HPP_ diff --git a/lib/parser/ast/nodes/base/Expr.hpp b/lib/parser/ast/nodes/base/Expr.hpp new file mode 100644 index 0000000..2d1917f --- /dev/null +++ b/lib/parser/ast/nodes/base/Expr.hpp @@ -0,0 +1,12 @@ +#ifndef PARSER_EXPR_HPP_ +#define PARSER_EXPR_HPP_ + +#include "AstNode.hpp" + +namespace ovum::compiler::parser { + +class Expr : public AstNode {}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_EXPR_HPP_ diff --git a/lib/parser/ast/nodes/base/Stmt.hpp b/lib/parser/ast/nodes/base/Stmt.hpp new file mode 100644 index 0000000..19a7b2d --- /dev/null +++ b/lib/parser/ast/nodes/base/Stmt.hpp @@ -0,0 +1,12 @@ +#ifndef PARSER_STMT_HPP_ +#define PARSER_STMT_HPP_ + +#include "AstNode.hpp" + +namespace ovum::compiler::parser { + +class Stmt : public AstNode {}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STMT_HPP_ diff --git a/lib/parser/ast/nodes/class_members/CallDecl.cpp b/lib/parser/ast/nodes/class_members/CallDecl.cpp new file mode 100644 index 0000000..a84e922 --- /dev/null +++ b/lib/parser/ast/nodes/class_members/CallDecl.cpp @@ -0,0 +1,65 @@ +#include "lib/parser/ast/nodes/class_members/CallDecl.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void CallDecl::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +bool CallDecl::IsPublic() const noexcept { + return is_public_; +} + +void CallDecl::SetPublic(bool v) noexcept { + is_public_ = v; +} + +const std::vector& CallDecl::Params() const noexcept { + return params_; +} + +std::vector& CallDecl::MutableParams() noexcept { + return params_; +} + +void CallDecl::AddParam(Param param) { + params_.emplace_back(std::move(param)); +} + +const TypeReference* CallDecl::ReturnType() const noexcept { + return ret_type_.get(); +} + +TypeReference* CallDecl::MutableReturnType() noexcept { + return ret_type_.get(); +} + +void CallDecl::SetReturnType(std::unique_ptr type) { + ret_type_ = std::move(type); +} + +std::unique_ptr CallDecl::ReleaseReturnType() { + return std::move(ret_type_); +} + +const Block* CallDecl::Body() const noexcept { + return body_.get(); +} + +Block* CallDecl::MutableBody() noexcept { + return body_.get(); +} + +void CallDecl::SetBody(std::unique_ptr block) { + body_ = std::move(block); +} + +std::unique_ptr CallDecl::ReleaseBody() { + return std::move(body_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/class_members/CallDecl.hpp b/lib/parser/ast/nodes/class_members/CallDecl.hpp new file mode 100644 index 0000000..6082620 --- /dev/null +++ b/lib/parser/ast/nodes/class_members/CallDecl.hpp @@ -0,0 +1,44 @@ +#ifndef PARSER_CALLDECL_HPP_ +#define PARSER_CALLDECL_HPP_ + +#include +#include + +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/ast/nodes/stmts/Block.hpp" +#include "lib/parser/types/Param.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class CallDecl : public Decl { +public: + void Accept(AstVisitor& visitor) override; + + bool IsPublic() const noexcept; + void SetPublic(bool v) noexcept; + + const std::vector& Params() const noexcept; + std::vector& MutableParams() noexcept; + void AddParam(Param param); + + const TypeReference* ReturnType() const noexcept; + TypeReference* MutableReturnType() noexcept; + void SetReturnType(std::unique_ptr type); + std::unique_ptr ReleaseReturnType(); + + const Block* Body() const noexcept; + Block* MutableBody() noexcept; + void SetBody(std::unique_ptr block); + std::unique_ptr ReleaseBody(); + +private: + bool is_public_ = true; + std::vector params_; + std::unique_ptr ret_type_; + std::unique_ptr body_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_CALLDECL_HPP_ diff --git a/lib/parser/ast/nodes/class_members/DestructorDecl.cpp b/lib/parser/ast/nodes/class_members/DestructorDecl.cpp new file mode 100644 index 0000000..f965f0a --- /dev/null +++ b/lib/parser/ast/nodes/class_members/DestructorDecl.cpp @@ -0,0 +1,37 @@ +#include "lib/parser/ast/nodes/class_members/DestructorDecl.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void DestructorDecl::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +bool DestructorDecl::IsPublic() const noexcept { + return is_public_; +} + +void DestructorDecl::SetPublic(bool value) noexcept { + is_public_ = value; +} + +const Block* DestructorDecl::Body() const noexcept { + return body_.get(); +} + +Block* DestructorDecl::MutableBody() noexcept { + return body_.get(); +} + +void DestructorDecl::SetBody(std::unique_ptr block) { + body_ = std::move(block); +} + +std::unique_ptr DestructorDecl::ReleaseBody() { + return std::move(body_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/class_members/DestructorDecl.hpp b/lib/parser/ast/nodes/class_members/DestructorDecl.hpp new file mode 100644 index 0000000..24f780a --- /dev/null +++ b/lib/parser/ast/nodes/class_members/DestructorDecl.hpp @@ -0,0 +1,30 @@ +#ifndef PARSER_DESTRUCTORDECL_HPP_ +#define PARSER_DESTRUCTORDECL_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/ast/nodes/stmts/Block.hpp" + +namespace ovum::compiler::parser { + +class DestructorDecl : public Decl { +public: + void Accept(AstVisitor& visitor) override; + + bool IsPublic() const noexcept; + void SetPublic(bool value) noexcept; + + const Block* Body() const noexcept; + Block* MutableBody() noexcept; + void SetBody(std::unique_ptr block); + std::unique_ptr ReleaseBody(); + +private: + bool is_public_ = true; + std::unique_ptr body_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_DESTRUCTORDECL_HPP_ diff --git a/lib/parser/ast/nodes/class_members/FieldDecl.cpp b/lib/parser/ast/nodes/class_members/FieldDecl.cpp new file mode 100644 index 0000000..e073caa --- /dev/null +++ b/lib/parser/ast/nodes/class_members/FieldDecl.cpp @@ -0,0 +1,65 @@ +#include "lib/parser/ast/nodes/class_members/FieldDecl.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void FieldDecl::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +bool FieldDecl::IsPublic() const noexcept { + return is_public_; +} + +void FieldDecl::SetPublic(bool value) noexcept { + is_public_ = value; +} + +bool FieldDecl::IsVar() const noexcept { + return is_var_; +} + +void FieldDecl::SetVar(bool var) noexcept { + is_var_ = var; +} + +const std::string& FieldDecl::Name() const noexcept { + return name_; +} + +void FieldDecl::SetName(std::string name) { + name_ = std::move(name); +} + +const TypeReference& FieldDecl::Type() const noexcept { + return type_; +} + +TypeReference& FieldDecl::MutableType() noexcept { + return type_; +} + +void FieldDecl::SetType(TypeReference type) { + type_ = std::move(type); +} + +const Expr* FieldDecl::Init() const noexcept { + return init_.get(); +} + +Expr* FieldDecl::MutableInit() noexcept { + return init_.get(); +} + +void FieldDecl::SetInit(std::unique_ptr expr) { + init_ = std::move(expr); +} + +std::unique_ptr FieldDecl::ReleaseInit() { + return std::move(init_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/class_members/FieldDecl.hpp b/lib/parser/ast/nodes/class_members/FieldDecl.hpp new file mode 100644 index 0000000..aa63002 --- /dev/null +++ b/lib/parser/ast/nodes/class_members/FieldDecl.hpp @@ -0,0 +1,45 @@ +#ifndef PARSER_FIELDDECL_HPP_ +#define PARSER_FIELDDECL_HPP_ + +#include +#include + +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class FieldDecl : public Decl { +public: + void Accept(AstVisitor& visitor) override; + + bool IsPublic() const noexcept; + void SetPublic(bool value) noexcept; + + bool IsVar() const noexcept; + void SetVar(bool var) noexcept; + + const std::string& Name() const noexcept; + void SetName(std::string name); + + const TypeReference& Type() const noexcept; + TypeReference& MutableType() noexcept; + void SetType(TypeReference type); + + const Expr* Init() const noexcept; + Expr* MutableInit() noexcept; + void SetInit(std::unique_ptr expr); + std::unique_ptr ReleaseInit(); + +private: + bool is_public_ = true; + bool is_var_ = false; + std::string name_; + TypeReference type_; + std::unique_ptr init_; // optional +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_FIELDDECL_HPP_ diff --git a/lib/parser/ast/nodes/class_members/MethodDecl.cpp b/lib/parser/ast/nodes/class_members/MethodDecl.cpp new file mode 100644 index 0000000..8689d25 --- /dev/null +++ b/lib/parser/ast/nodes/class_members/MethodDecl.cpp @@ -0,0 +1,96 @@ +#include "lib/parser/ast/AstVisitor.hpp" +#include "lib/parser/ast/nodes/class_members/MethodDecl.hpp" + +#include + +namespace ovum::compiler::parser { + +void MethodDecl::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +bool MethodDecl::IsPublic() const noexcept { + return is_public_; +} + +void MethodDecl::SetPublic(bool is_public) noexcept { + is_public_ = is_public; +} + +bool MethodDecl::IsOverride() const noexcept { + return is_override_; +} + +void MethodDecl::SetOverride(bool is_override) noexcept { + is_override_ = is_override; +} + +bool MethodDecl::IsStatic() const noexcept { + return is_static_; +} + +void MethodDecl::SetStatic(bool is_static) noexcept { + is_static_ = is_static; +} + +bool MethodDecl::IsPure() const noexcept { + return is_pure_; +} + +void MethodDecl::SetPure(bool is_pure) noexcept { + is_pure_ = is_pure; +} + +const std::string& MethodDecl::Name() const noexcept { + return name; +} + +void MethodDecl::SetName(std::string new_name) { + name = std::move(new_name); +} + +const std::vector& MethodDecl::Params() const noexcept { + return params; +} + +std::vector& MethodDecl::MutableParams() noexcept { + return params; +} + +void MethodDecl::AddParam(Param param) { + params.emplace_back(std::move(param)); +} + +const TypeReference* MethodDecl::ReturnType() const noexcept { + return ret_type.get(); +} + +TypeReference* MethodDecl::MutableReturnType() noexcept { + return ret_type.get(); +} + +void MethodDecl::SetReturnType(std::unique_ptr type) { + ret_type = std::move(type); +} + +std::unique_ptr MethodDecl::ReleaseReturnType() { + return std::move(ret_type); +} + +const Block* MethodDecl::Body() const noexcept { + return body.get(); +} + +Block* MethodDecl::MutableBody() noexcept { + return body.get(); +} + +void MethodDecl::SetBody(std::unique_ptr block) { + body = std::move(block); +} + +std::unique_ptr MethodDecl::ReleaseBody() { + return std::move(body); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/class_members/MethodDecl.hpp b/lib/parser/ast/nodes/class_members/MethodDecl.hpp new file mode 100644 index 0000000..7702c00 --- /dev/null +++ b/lib/parser/ast/nodes/class_members/MethodDecl.hpp @@ -0,0 +1,62 @@ +#ifndef PARSER_METHODDECL_HPP_ +#define PARSER_METHODDECL_HPP_ + +#include +#include +#include + +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/ast/nodes/stmts/Block.hpp" +#include "lib/parser/types/Param.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class MethodDecl : public Decl { +public: + void Accept(AstVisitor& visitor) override; + + bool IsPublic() const noexcept; + void SetPublic(bool is_public) noexcept; + + bool IsOverride() const noexcept; + void SetOverride(bool is_override) noexcept; + + bool IsStatic() const noexcept; + void SetStatic(bool is_static) noexcept; + + bool IsPure() const noexcept; + void SetPure(bool is_pure) noexcept; + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + + const std::vector& Params() const noexcept; + std::vector& MutableParams() noexcept; + void AddParam(Param param); + + const TypeReference* ReturnType() const noexcept; + TypeReference* MutableReturnType() noexcept; + void SetReturnType(std::unique_ptr type); + std::unique_ptr ReleaseReturnType(); + + const Block* Body() const noexcept; + Block* MutableBody() noexcept; + void SetBody(std::unique_ptr block); + std::unique_ptr ReleaseBody(); + +private: + bool is_public_ = true; + bool is_override_ = false; + bool is_static_ = false; + bool is_pure_ = false; + + std::string name; + std::vector params; + std::unique_ptr ret_type; + std::unique_ptr body; // optional +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_METHODDECL_HPP_ diff --git a/lib/parser/ast/nodes/class_members/StaticFieldDecl.cpp b/lib/parser/ast/nodes/class_members/StaticFieldDecl.cpp new file mode 100644 index 0000000..a2470b4 --- /dev/null +++ b/lib/parser/ast/nodes/class_members/StaticFieldDecl.cpp @@ -0,0 +1,65 @@ +#include "lib/parser/ast/nodes/class_members/StaticFieldDecl.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void StaticFieldDecl::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +bool StaticFieldDecl::IsPublic() const noexcept { + return is_public_; +} + +void StaticFieldDecl::SetPublic(bool is_public) noexcept { + is_public_ = is_public; +} + +bool StaticFieldDecl::IsVar() const noexcept { + return is_var_; +} + +void StaticFieldDecl::SetVar(bool is_var) noexcept { + is_var_ = is_var; +} + +const std::string& StaticFieldDecl::Name() const noexcept { + return name_; +} + +void StaticFieldDecl::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +const TypeReference& StaticFieldDecl::Type() const noexcept { + return type_; +} + +TypeReference& StaticFieldDecl::MutableType() noexcept { + return type_; +} + +void StaticFieldDecl::SetType(TypeReference type) { + type_ = std::move(type); +} + +const Expr* StaticFieldDecl::Init() const noexcept { + return init_.get(); +} + +Expr* StaticFieldDecl::MutableInit() noexcept { + return init_.get(); +} + +void StaticFieldDecl::SetInit(std::unique_ptr expr) { + init_ = std::move(expr); +} + +std::unique_ptr StaticFieldDecl::ReleaseInit() { + return std::move(init_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/class_members/StaticFieldDecl.hpp b/lib/parser/ast/nodes/class_members/StaticFieldDecl.hpp new file mode 100644 index 0000000..09b5cd7 --- /dev/null +++ b/lib/parser/ast/nodes/class_members/StaticFieldDecl.hpp @@ -0,0 +1,45 @@ +#ifndef PARSER_STATICFIELDDECL_HPP_ +#define PARSER_STATICFIELDDECL_HPP_ + +#include +#include + +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class StaticFieldDecl : public Decl { +public: + void Accept(AstVisitor& visitor) override; + + bool IsPublic() const noexcept; + void SetPublic(bool is_public) noexcept; + + bool IsVar() const noexcept; + void SetVar(bool is_var) noexcept; + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + + const TypeReference& Type() const noexcept; + TypeReference& MutableType() noexcept; + void SetType(TypeReference type); + + const Expr* Init() const noexcept; + Expr* MutableInit() noexcept; + void SetInit(std::unique_ptr expr); + std::unique_ptr ReleaseInit(); + +private: + bool is_public_ = true; + bool is_var_ = false; + std::string name_; + TypeReference type_; + std::unique_ptr init_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATICFIELDDECL_HPP_ diff --git a/lib/parser/ast/nodes/decls/ClassDecl.cpp b/lib/parser/ast/nodes/decls/ClassDecl.cpp new file mode 100644 index 0000000..5f1f049 --- /dev/null +++ b/lib/parser/ast/nodes/decls/ClassDecl.cpp @@ -0,0 +1,53 @@ +#include "ClassDecl.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void ClassDecl::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const std::string& ClassDecl::Name() const noexcept { + return name_; +} + +void ClassDecl::SetName(std::string name) { + name_ = std::move(name); +} + +const std::vector& ClassDecl::Implements() const noexcept { + return implements_; +} + +std::vector& ClassDecl::MutableImplements() noexcept { + return implements_; +} + +void ClassDecl::AddImplements(TypeReference type) { + implements_.emplace_back(std::move(type)); +} + +const std::vector>& ClassDecl::Members() const noexcept { + return members_; +} + +std::vector>& ClassDecl::MutableMembers() noexcept { + return members_; +} + +void ClassDecl::AddMember(std::unique_ptr decl) { + members_.emplace_back(std::move(decl)); +} + +std::unique_ptr ClassDecl::ReleaseMember(std::size_t index) { + if (index >= members_.size()) { + return nullptr; + } + + auto old = std::move(members_[index]); + members_.erase(members_.begin() + static_cast(index)); + return old; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/decls/ClassDecl.hpp b/lib/parser/ast/nodes/decls/ClassDecl.hpp new file mode 100644 index 0000000..6e93ebe --- /dev/null +++ b/lib/parser/ast/nodes/decls/ClassDecl.hpp @@ -0,0 +1,37 @@ +#ifndef PARSER_CLASSDECL_HPP_ +#define PARSER_CLASSDECL_HPP_ + +#include +#include +#include + +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class ClassDecl : public Decl { +public: + void Accept(AstVisitor& visitor) override; + + const std::string& Name() const noexcept; + void SetName(std::string name); + + const std::vector& Implements() const noexcept; + std::vector& MutableImplements() noexcept; + void AddImplements(TypeReference type); + + const std::vector>& Members() const noexcept; + std::vector>& MutableMembers() noexcept; + void AddMember(std::unique_ptr decl); + std::unique_ptr ReleaseMember(std::size_t index); + +private: + std::string name_; + std::vector implements_; + std::vector> members_; // Field/StaticField/Method/Call/Destructor +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_CLASSDECL_HPP_ diff --git a/lib/parser/ast/nodes/decls/FunctionDecl.cpp b/lib/parser/ast/nodes/decls/FunctionDecl.cpp new file mode 100644 index 0000000..12afb59 --- /dev/null +++ b/lib/parser/ast/nodes/decls/FunctionDecl.cpp @@ -0,0 +1,70 @@ +#include "FunctionDecl.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void FunctionDecl::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +bool FunctionDecl::IsPure() const noexcept { + return is_pure_; +} + +void FunctionDecl::SetPure(bool is_pure) noexcept { + is_pure_ = is_pure; +} + +const std::string& FunctionDecl::Name() const noexcept { + return name_; +} + +void FunctionDecl::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +const std::vector& FunctionDecl::Params() const noexcept { + return params_; +} + +std::vector& FunctionDecl::MutableParams() noexcept { + return params_; +} + +void FunctionDecl::AddParam(Param param) { + params_.emplace_back(std::move(param)); +} + +const TypeReference* FunctionDecl::ReturnType() const noexcept { + return return_type_.get(); +} +TypeReference* FunctionDecl::MutableReturnType() noexcept { + return return_type_.get(); +} + +void FunctionDecl::SetReturnType(std::unique_ptr type) { + return_type_ = std::move(type); +} + +std::unique_ptr FunctionDecl::ReleaseReturnType() { + return std::move(return_type_); +} + +const Block* FunctionDecl::Body() const noexcept { + return body_.get(); +} + +Block* FunctionDecl::MutableBody() noexcept { + return body_.get(); +} + +void FunctionDecl::SetBody(std::unique_ptr block) { + body_ = std::move(block); +} + +std::unique_ptr FunctionDecl::ReleaseBody() { + return std::move(body_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/decls/FunctionDecl.hpp b/lib/parser/ast/nodes/decls/FunctionDecl.hpp new file mode 100644 index 0000000..198e234 --- /dev/null +++ b/lib/parser/ast/nodes/decls/FunctionDecl.hpp @@ -0,0 +1,50 @@ +#ifndef PARSER_FUNCTIONDECL_HPP_ +#define PARSER_FUNCTIONDECL_HPP_ + +#include +#include +#include + +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/ast/nodes/stmts/Block.hpp" +#include "lib/parser/types/Param.hpp" + +namespace ovum::compiler::parser { + +class TypeReference; + +class FunctionDecl : public Decl { +public: + void Accept(AstVisitor& visitor) override; + + bool IsPure() const noexcept; + void SetPure(bool is_pure) noexcept; + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + + const std::vector& Params() const noexcept; + std::vector& MutableParams() noexcept; + void AddParam(Param param); + + const TypeReference* ReturnType() const noexcept; + TypeReference* MutableReturnType() noexcept; + void SetReturnType(std::unique_ptr type); + std::unique_ptr ReleaseReturnType(); + + const Block* Body() const noexcept; + Block* MutableBody() noexcept; + void SetBody(std::unique_ptr block); + std::unique_ptr ReleaseBody(); + +private: + bool is_pure_ = false; + std::string name_; + std::vector params_; + std::unique_ptr return_type_; // optional + std::unique_ptr body_; // optional +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_FUNCTIONDECL_HPP_ diff --git a/lib/parser/ast/nodes/decls/GlobalVarDecl.cpp b/lib/parser/ast/nodes/decls/GlobalVarDecl.cpp new file mode 100644 index 0000000..97964dd --- /dev/null +++ b/lib/parser/ast/nodes/decls/GlobalVarDecl.cpp @@ -0,0 +1,55 @@ +#include "GlobalVarDecl.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void GlobalVarDecl::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +bool GlobalVarDecl::IsVar() const noexcept { + return is_var_; +} + +void GlobalVarDecl::SetVar(bool is_var) noexcept { + is_var_ = is_var; +} + +const std::string& GlobalVarDecl::Name() const noexcept { + return name_; +} + +void GlobalVarDecl::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +const TypeReference& GlobalVarDecl::Type() const noexcept { + return type_; +} + +TypeReference& GlobalVarDecl::MutableType() noexcept { + return type_; +} + +void GlobalVarDecl::SetType(TypeReference type) { + type_ = std::move(type); +} + +const Expr* GlobalVarDecl::Init() const noexcept { + return init_.get(); +} + +Expr* GlobalVarDecl::MutableInit() noexcept { + return init_.get(); +} + +void GlobalVarDecl::SetInit(std::unique_ptr expr) { + init_ = std::move(expr); +} + +std::unique_ptr GlobalVarDecl::ReleaseInit() { + return std::move(init_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/decls/GlobalVarDecl.hpp b/lib/parser/ast/nodes/decls/GlobalVarDecl.hpp new file mode 100644 index 0000000..ebcba68 --- /dev/null +++ b/lib/parser/ast/nodes/decls/GlobalVarDecl.hpp @@ -0,0 +1,41 @@ +#ifndef PARSER_GLOBALVARDECL_HPP_ +#define PARSER_GLOBALVARDECL_HPP_ + +#include +#include + +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class GlobalVarDecl : public Decl { +public: + void Accept(AstVisitor& visitor) override; + + bool IsVar() const noexcept; + void SetVar(bool is_var) noexcept; + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + + const TypeReference& Type() const noexcept; + TypeReference& MutableType() noexcept; + void SetType(TypeReference type); + + const Expr* Init() const noexcept; + Expr* MutableInit() noexcept; + void SetInit(std::unique_ptr expr); + std::unique_ptr ReleaseInit(); + +private: + bool is_var_ = false; // var=true, val=false + std::string name_; + TypeReference type_; + std::unique_ptr init_; // optional +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_GLOBALVARDECL_HPP_ diff --git a/lib/parser/ast/nodes/decls/InterfaceDecl.cpp b/lib/parser/ast/nodes/decls/InterfaceDecl.cpp new file mode 100644 index 0000000..8a36942 --- /dev/null +++ b/lib/parser/ast/nodes/decls/InterfaceDecl.cpp @@ -0,0 +1,41 @@ +#include "InterfaceDecl.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void InterfaceDecl::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const std::string& InterfaceDecl::Name() const noexcept { + return name_; +} + +void InterfaceDecl::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +const std::vector>& InterfaceDecl::Members() const noexcept { + return methods_; +} + +std::vector>& InterfaceDecl::MutableMembers() noexcept { + return methods_; +} + +void InterfaceDecl::AddMember(std::unique_ptr method) { + methods_.emplace_back(std::move(method)); +} + +std::unique_ptr InterfaceDecl::ReleaseMember(std::size_t index) { + if (index >= methods_.size()) { + return nullptr; + } + + auto old = std::move(methods_[index]); + methods_.erase(methods_.begin() + static_cast(index)); + return old; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/decls/InterfaceDecl.hpp b/lib/parser/ast/nodes/decls/InterfaceDecl.hpp new file mode 100644 index 0000000..752810a --- /dev/null +++ b/lib/parser/ast/nodes/decls/InterfaceDecl.hpp @@ -0,0 +1,33 @@ +#ifndef PARSER_INTERFACEDECL_HPP_ +#define PARSER_INTERFACEDECL_HPP_ + +#include +#include +#include + +#include "InterfaceMethod.hpp" +#include "lib/parser/ast/nodes/base/Decl.hpp" + +namespace ovum::compiler::parser { + +class InterfaceDecl : public Decl { +public: + void Accept(AstVisitor& visitor) override; + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + + const std::vector>& Members() const noexcept; + std::vector>& MutableMembers() noexcept; + + void AddMember(std::unique_ptr method); + std::unique_ptr ReleaseMember(std::size_t index); + +private: + std::string name_; + std::vector> methods_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_INTERFACEDECL_HPP_ diff --git a/lib/parser/ast/nodes/decls/InterfaceMethod.cpp b/lib/parser/ast/nodes/decls/InterfaceMethod.cpp new file mode 100644 index 0000000..a5d49bc --- /dev/null +++ b/lib/parser/ast/nodes/decls/InterfaceMethod.cpp @@ -0,0 +1,37 @@ +#include "lib/parser/ast/nodes/decls/InterfaceMethod.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void InterfaceMethod::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const std::string& InterfaceMethod::Name() const noexcept { + return name_; +} + +void InterfaceMethod::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +const std::vector& InterfaceMethod::Params() const noexcept { + return params_; +} + +std::vector& InterfaceMethod::MutableParams() noexcept { + return params_; +} + +const TypeReference* InterfaceMethod::ReturnType() const noexcept { + return ret_type_.get(); +} + +void InterfaceMethod::SetReturnType(std::unique_ptr type) { + ret_type_ = std::move(type); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/decls/InterfaceMethod.hpp b/lib/parser/ast/nodes/decls/InterfaceMethod.hpp new file mode 100644 index 0000000..b94dfbc --- /dev/null +++ b/lib/parser/ast/nodes/decls/InterfaceMethod.hpp @@ -0,0 +1,39 @@ +#ifndef PARSER_INTERFACEMETHOD_HPP_ +#define PARSER_INTERFACEMETHOD_HPP_ + +#include +#include + +#include "lib/parser/ast/nodes/base/AstNode.hpp" +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class InterfaceMethod : public Decl { +public: + struct Param { + std::string name; + TypeReference type; + }; + + void Accept(AstVisitor& visitor) override; + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + + const std::vector& Params() const noexcept; + std::vector& MutableParams() noexcept; + + const TypeReference* ReturnType() const noexcept; + void SetReturnType(std::unique_ptr type); + +private: + std::string name_; + std::vector params_; + std::unique_ptr ret_type_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_INTERFACEMETHOD_HPP_ diff --git a/lib/parser/ast/nodes/decls/Module.cpp b/lib/parser/ast/nodes/decls/Module.cpp new file mode 100644 index 0000000..1cfbb33 --- /dev/null +++ b/lib/parser/ast/nodes/decls/Module.cpp @@ -0,0 +1,49 @@ +#include "Module.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void Module::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const std::string& Module::Name() const noexcept { + return name_; +} + +void Module::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +const SourceId& Module::Source() const noexcept { + return source_; +} + +void Module::SetSource(SourceId id) { + source_ = std::move(id); +} + +const std::vector>& Module::Decls() const noexcept { + return decls_; +} + +std::vector>& Module::MutableDecls() noexcept { + return decls_; +} + +void Module::AddDecl(std::unique_ptr decl) { + decls_.emplace_back(std::move(decl)); +} + +std::unique_ptr Module::ReleaseDecl(std::size_t index) { + if (index >= decls_.size()) { + return nullptr; + } + + auto old = std::move(decls_[index]); + decls_.erase(decls_.begin() + static_cast(index)); + return std::move(old); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/decls/Module.hpp b/lib/parser/ast/nodes/decls/Module.hpp new file mode 100644 index 0000000..341b246 --- /dev/null +++ b/lib/parser/ast/nodes/decls/Module.hpp @@ -0,0 +1,37 @@ +#ifndef PARSER_MODULE_HPP_ +#define PARSER_MODULE_HPP_ + +#include +#include +#include + +#include "lib/parser/ast/nodes/base/AstNode.hpp" +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/tokens/SourceId.hpp" + +namespace ovum::compiler::parser { + +class Module : public AstNode { +public: + void Accept(AstVisitor& visitor) override; + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + + const SourceId& Source() const noexcept; + void SetSource(SourceId id); + + const std::vector>& Decls() const noexcept; + std::vector>& MutableDecls() noexcept; + void AddDecl(std::unique_ptr decl); + std::unique_ptr ReleaseDecl(std::size_t index); + +private: + std::string name_; + SourceId source_; + std::vector> decls_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_MODULE_HPP_ diff --git a/lib/parser/ast/nodes/decls/TypeAliasDecl.cpp b/lib/parser/ast/nodes/decls/TypeAliasDecl.cpp new file mode 100644 index 0000000..7cdc767 --- /dev/null +++ b/lib/parser/ast/nodes/decls/TypeAliasDecl.cpp @@ -0,0 +1,33 @@ +#include "lib/parser/ast/nodes/decls/TypeAliasDecl.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void TypeAliasDecl::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const std::string& TypeAliasDecl::Name() const noexcept { + return name_; +} + +void TypeAliasDecl::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +const TypeReference& TypeAliasDecl::AliasedType() const noexcept { + return aliased_type_; +} + +TypeReference& TypeAliasDecl::MutableAliasedType() noexcept { + return aliased_type_; +} + +void TypeAliasDecl::SetAliasedType(TypeReference type) { + aliased_type_ = std::move(type); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/decls/TypeAliasDecl.hpp b/lib/parser/ast/nodes/decls/TypeAliasDecl.hpp new file mode 100644 index 0000000..352a355 --- /dev/null +++ b/lib/parser/ast/nodes/decls/TypeAliasDecl.hpp @@ -0,0 +1,29 @@ +#ifndef PARSER_TYPEALIASDECL_HPP_ +#define PARSER_TYPEALIASDECL_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Decl.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class TypeAliasDecl : public Decl { +public: + void Accept(AstVisitor& visitor) override; + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + + const TypeReference& AliasedType() const noexcept; + TypeReference& MutableAliasedType() noexcept; + void SetAliasedType(TypeReference type); + +private: + std::string name_; + TypeReference aliased_type_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_TYPEALIASDECL_HPP_ diff --git a/lib/parser/ast/nodes/exprs/Assign.cpp b/lib/parser/ast/nodes/exprs/Assign.cpp new file mode 100644 index 0000000..c38d05e --- /dev/null +++ b/lib/parser/ast/nodes/exprs/Assign.cpp @@ -0,0 +1,57 @@ +#include "lib/parser/ast/nodes/exprs/Assign.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void Assign::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const IAssignOpTag& Assign::Kind() const noexcept { + return *kind_; +} + +void Assign::SetKind(const IAssignOpTag& new_kind) noexcept { + kind_ = &new_kind; +} + +const Expr& Assign::Target() const noexcept { + return *target_; +} + +Expr& Assign::MutableTarget() noexcept { + return *target_; +} + +void Assign::SetTarget(std::unique_ptr new_target) { + target_ = std::move(new_target); +} + +std::unique_ptr Assign::ReplaceTarget(std::unique_ptr new_target) { + auto old_target = std::move(target_); + target_ = std::move(new_target); + return old_target; +} + +const Expr& Assign::Value() const noexcept { + return *value_; +} + +Expr& Assign::MutableValue() noexcept { + return *value_; +} + +void Assign::SetValue(std::unique_ptr new_value) { + value_ = std::move(new_value); +} + +std::unique_ptr Assign::ReplaceValue(std::unique_ptr new_value) { + auto old_value = std::move(value_); + value_ = std::move(new_value); + return old_value; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/Assign.hpp b/lib/parser/ast/nodes/exprs/Assign.hpp new file mode 100644 index 0000000..a49ae85 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/Assign.hpp @@ -0,0 +1,37 @@ +#ifndef PARSER_ASSIGN_HPP_ +#define PARSER_ASSIGN_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "tags/IAssignOpTag.hpp" +#include "tags/OpTags.hpp" + +namespace ovum::compiler::parser { + +class Assign : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const IAssignOpTag& Kind() const noexcept; + void SetKind(const IAssignOpTag& new_kind) noexcept; + + const Expr& Target() const noexcept; + Expr& MutableTarget() noexcept; + void SetTarget(std::unique_ptr new_target); + std::unique_ptr ReplaceTarget(std::unique_ptr new_target); + + const Expr& Value() const noexcept; + Expr& MutableValue() noexcept; + void SetValue(std::unique_ptr new_value); + std::unique_ptr ReplaceValue(std::unique_ptr new_value); + +private: + const IAssignOpTag* kind_ = &OpTags::RefAssign(); + std::unique_ptr target_; + std::unique_ptr value_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_ASSIGN_HPP_ diff --git a/lib/parser/ast/nodes/exprs/Binary.cpp b/lib/parser/ast/nodes/exprs/Binary.cpp new file mode 100644 index 0000000..c6e843e --- /dev/null +++ b/lib/parser/ast/nodes/exprs/Binary.cpp @@ -0,0 +1,57 @@ +#include "lib/parser/ast/nodes/exprs/Binary.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void Binary::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const IBinaryOpTag& Binary::Op() const noexcept { + return *op_; +} + +void Binary::SetOp(const IBinaryOpTag& new_op) noexcept { + op_ = &new_op; +} + +const Expr& Binary::Lhs() const noexcept { + return *lhs_; +} + +Expr& Binary::MutableLhs() noexcept { + return *lhs_; +} + +void Binary::SetLhs(std::unique_ptr new_lhs) { + lhs_ = std::move(new_lhs); +} + +std::unique_ptr Binary::ReplaceLhs(std::unique_ptr new_lhs) { + auto old_lhs = std::move(lhs_); + lhs_ = std::move(new_lhs); + return old_lhs; +} + +const Expr& Binary::Rhs() const noexcept { + return *rhs_; +} + +Expr& Binary::MutableRhs() noexcept { + return *rhs_; +} + +void Binary::SetRhs(std::unique_ptr new_rhs) { + rhs_ = std::move(new_rhs); +} + +std::unique_ptr Binary::ReplaceRhs(std::unique_ptr new_rhs) { + auto old_rhs = std::move(rhs_); + rhs_ = std::move(new_rhs); + return old_rhs; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/Binary.hpp b/lib/parser/ast/nodes/exprs/Binary.hpp new file mode 100644 index 0000000..ac2dcf6 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/Binary.hpp @@ -0,0 +1,37 @@ +#ifndef PARSER_BINARY_HPP_ +#define PARSER_BINARY_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "tags/IBinaryOpTag.hpp" +#include "tags/OpTags.hpp" + +namespace ovum::compiler::parser { + +class Binary : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const IBinaryOpTag& Op() const noexcept; + void SetOp(const IBinaryOpTag& new_op) noexcept; + + const Expr& Lhs() const noexcept; + Expr& MutableLhs() noexcept; + void SetLhs(std::unique_ptr new_lhs); + std::unique_ptr ReplaceLhs(std::unique_ptr new_lhs); + + const Expr& Rhs() const noexcept; + Expr& MutableRhs() noexcept; + void SetRhs(std::unique_ptr new_rhs); + std::unique_ptr ReplaceRhs(std::unique_ptr new_rhs); + +private: + const IBinaryOpTag* op_ = &OpTags::Add(); + std::unique_ptr lhs_; + std::unique_ptr rhs_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_BINARY_HPP_ diff --git a/lib/parser/ast/nodes/exprs/Call.cpp b/lib/parser/ast/nodes/exprs/Call.cpp new file mode 100644 index 0000000..12f4417 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/Call.cpp @@ -0,0 +1,46 @@ +#include "lib/parser/ast/AstVisitor.hpp" +#include "lib/parser/ast/nodes/exprs/Call.hpp" + +#include + +namespace ovum::compiler::parser { + +void Call::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Expr& Call::Callee() const noexcept { + return *callee_; +} + +Expr& Call::MutableCallee() noexcept { + return *callee_; +} + +void Call::SetCallee(std::unique_ptr new_callee) { + callee_ = std::move(new_callee); +} + +std::unique_ptr Call::ReplaceCallee(std::unique_ptr new_callee) { + auto old_callee = std::move(callee_); + callee_ = std::move(new_callee); + return old_callee; +} + +const std::vector>& Call::Args() const noexcept { + return args_; +} + +std::vector>& Call::MutableArgs() noexcept { + return args_; +} + +void Call::AddArg(std::unique_ptr new_arg) { + args_.emplace_back(std::move(new_arg)); +} + +void Call::ClearArgs() { + args_.clear(); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/Call.hpp b/lib/parser/ast/nodes/exprs/Call.hpp new file mode 100644 index 0000000..6217740 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/Call.hpp @@ -0,0 +1,32 @@ +#ifndef PARSER_CALL_HPP_ +#define PARSER_CALL_HPP_ + +#include +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class Call : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const Expr& Callee() const noexcept; + Expr& MutableCallee() noexcept; + void SetCallee(std::unique_ptr new_callee); + std::unique_ptr ReplaceCallee(std::unique_ptr new_callee); + + const std::vector>& Args() const noexcept; + std::vector>& MutableArgs() noexcept; + void AddArg(std::unique_ptr new_arg); + void ClearArgs(); + +private: + std::unique_ptr callee_; + std::vector> args_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_CALL_HPP_ diff --git a/lib/parser/ast/nodes/exprs/CastAs.cpp b/lib/parser/ast/nodes/exprs/CastAs.cpp new file mode 100644 index 0000000..9bf495f --- /dev/null +++ b/lib/parser/ast/nodes/exprs/CastAs.cpp @@ -0,0 +1,43 @@ +#include "lib/parser/ast/nodes/exprs/CastAs.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void CastAs::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Expr& CastAs::Expression() const noexcept { + return *expr_; +} + +Expr& CastAs::MutableExpression() noexcept { + return *expr_; +} + +void CastAs::SetExpression(std::unique_ptr new_expression) { + expr_ = std::move(new_expression); +} + +std::unique_ptr CastAs::ReplaceExpression(std::unique_ptr new_expression) { + auto old_expr = std::move(expr_); + expr_ = std::move(new_expression); + return old_expr; +} + +const TypeReference& CastAs::Type() const noexcept { + return type_; +} + +TypeReference& CastAs::MutableType() noexcept { + return type_; +} + +void CastAs::SetType(TypeReference new_type) { + type_ = std::move(new_type); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/CastAs.hpp b/lib/parser/ast/nodes/exprs/CastAs.hpp new file mode 100644 index 0000000..fc9c88a --- /dev/null +++ b/lib/parser/ast/nodes/exprs/CastAs.hpp @@ -0,0 +1,31 @@ +#ifndef PARSER_CASTAS_HPP_ +#define PARSER_CASTAS_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class CastAs : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const Expr& Expression() const noexcept; + Expr& MutableExpression() noexcept; + void SetExpression(std::unique_ptr new_expression); + std::unique_ptr ReplaceExpression(std::unique_ptr new_expression); + + const TypeReference& Type() const noexcept; + TypeReference& MutableType() noexcept; + void SetType(TypeReference new_type); + +private: + std::unique_ptr expr_; + TypeReference type_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_CASTAS_HPP_ diff --git a/lib/parser/ast/nodes/exprs/Elvis.cpp b/lib/parser/ast/nodes/exprs/Elvis.cpp new file mode 100644 index 0000000..c19b6d3 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/Elvis.cpp @@ -0,0 +1,49 @@ +#include "lib/parser/ast/nodes/exprs/Elvis.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void Elvis::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Expr& Elvis::Lhs() const noexcept { + return *lhs_; +} + +Expr& Elvis::MutableLhs() noexcept { + return *lhs_; +} + +void Elvis::SetLhs(std::unique_ptr new_lhs) { + lhs_ = std::move(new_lhs); +} + +std::unique_ptr Elvis::ReplaceLhs(std::unique_ptr new_lhs) { + auto old_lhs = std::move(lhs_); + lhs_ = std::move(new_lhs); + return old_lhs; +} + +const Expr& Elvis::Rhs() const noexcept { + return *rhs_; +} + +Expr& Elvis::MutableRhs() noexcept { + return *rhs_; +} + +void Elvis::SetRhs(std::unique_ptr new_rhs) { + rhs_ = std::move(new_rhs); +} + +std::unique_ptr Elvis::ReplaceRhs(std::unique_ptr new_rhs) { + auto old_rhs = std::move(rhs_); + rhs_ = std::move(new_rhs); + return old_rhs; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/Elvis.hpp b/lib/parser/ast/nodes/exprs/Elvis.hpp new file mode 100644 index 0000000..0511bb8 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/Elvis.hpp @@ -0,0 +1,31 @@ +#ifndef PARSER_ELVIS_HPP_ +#define PARSER_ELVIS_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class Elvis : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const Expr& Lhs() const noexcept; + Expr& MutableLhs() noexcept; + void SetLhs(std::unique_ptr new_lhs); + std::unique_ptr ReplaceLhs(std::unique_ptr new_lhs); + + const Expr& Rhs() const noexcept; + Expr& MutableRhs() noexcept; + void SetRhs(std::unique_ptr new_rhs); + std::unique_ptr ReplaceRhs(std::unique_ptr new_rhs); + +private: + std::unique_ptr lhs_; + std::unique_ptr rhs_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_ELVIS_HPP_ diff --git a/lib/parser/ast/nodes/exprs/FieldAccess.cpp b/lib/parser/ast/nodes/exprs/FieldAccess.cpp new file mode 100644 index 0000000..67395ae --- /dev/null +++ b/lib/parser/ast/nodes/exprs/FieldAccess.cpp @@ -0,0 +1,39 @@ +#include "lib/parser/ast/nodes/exprs/FieldAccess.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void FieldAccess::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Expr& FieldAccess::Object() const noexcept { + return *object_; +} + +Expr& FieldAccess::MutableObject() noexcept { + return *object_; +} + +void FieldAccess::SetObject(std::unique_ptr new_object) { + object_ = std::move(new_object); +} + +std::unique_ptr FieldAccess::ReplaceObject(std::unique_ptr new_object) { + auto old_object = std::move(object_); + object_ = std::move(new_object); + return old_object; +} + +const std::string& FieldAccess::Name() const noexcept { + return name_; +} + +void FieldAccess::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/FieldAccess.hpp b/lib/parser/ast/nodes/exprs/FieldAccess.hpp new file mode 100644 index 0000000..96cbed9 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/FieldAccess.hpp @@ -0,0 +1,30 @@ +#ifndef PARSER_FIELDACCESS_HPP_ +#define PARSER_FIELDACCESS_HPP_ + +#include +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class FieldAccess : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const Expr& Object() const noexcept; + Expr& MutableObject() noexcept; + void SetObject(std::unique_ptr new_object); + std::unique_ptr ReplaceObject(std::unique_ptr new_object); + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + +private: + std::unique_ptr object_; + std::string name_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_FIELDACCESS_HPP_ diff --git a/lib/parser/ast/nodes/exprs/IdentRef.cpp b/lib/parser/ast/nodes/exprs/IdentRef.cpp new file mode 100644 index 0000000..37cb13c --- /dev/null +++ b/lib/parser/ast/nodes/exprs/IdentRef.cpp @@ -0,0 +1,21 @@ +#include "lib/parser/ast/nodes/exprs/IdentRef.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void IdentRef::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const std::string& IdentRef::Name() const noexcept { + return name_; +} + +void IdentRef::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/IdentRef.hpp b/lib/parser/ast/nodes/exprs/IdentRef.hpp new file mode 100644 index 0000000..288aeb6 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/IdentRef.hpp @@ -0,0 +1,23 @@ +#ifndef PARSER_IDENTREF_HPP_ +#define PARSER_IDENTREF_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class IdentRef : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + +private: + std::string name_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IDENTREF_HPP_ diff --git a/lib/parser/ast/nodes/exprs/IndexAccess.cpp b/lib/parser/ast/nodes/exprs/IndexAccess.cpp new file mode 100644 index 0000000..2f59348 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/IndexAccess.cpp @@ -0,0 +1,49 @@ +#include "lib/parser/ast/nodes/exprs/IndexAccess.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void IndexAccess::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Expr& IndexAccess::Object() const noexcept { + return *object_; +} + +Expr& IndexAccess::MutableObject() noexcept { + return *object_; +} + +void IndexAccess::SetObject(std::unique_ptr new_object) { + object_ = std::move(new_object); +} + +std::unique_ptr IndexAccess::ReplaceObject(std::unique_ptr new_object) { + auto old_object = std::move(object_); + object_ = std::move(new_object); + return old_object; +} + +const Expr& IndexAccess::IndexExpr() const noexcept { + return *index_; +} + +Expr& IndexAccess::MutableIndexExpr() noexcept { + return *index_; +} + +void IndexAccess::SetIndexExpr(std::unique_ptr new_index) { + index_ = std::move(new_index); +} + +std::unique_ptr IndexAccess::ReplaceIndexExpr(std::unique_ptr new_index) { + auto old_index = std::move(index_); + index_ = std::move(new_index); + return old_index; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/IndexAccess.hpp b/lib/parser/ast/nodes/exprs/IndexAccess.hpp new file mode 100644 index 0000000..694c789 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/IndexAccess.hpp @@ -0,0 +1,31 @@ +#ifndef PARSER_INDEXACCESS_HPP_ +#define PARSER_INDEXACCESS_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class IndexAccess : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const Expr& Object() const noexcept; + Expr& MutableObject() noexcept; + void SetObject(std::unique_ptr new_object); + std::unique_ptr ReplaceObject(std::unique_ptr new_object); + + const Expr& IndexExpr() const noexcept; + Expr& MutableIndexExpr() noexcept; + void SetIndexExpr(std::unique_ptr new_index); + std::unique_ptr ReplaceIndexExpr(std::unique_ptr new_index); + +private: + std::unique_ptr object_; + std::unique_ptr index_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_INDEXACCESS_HPP_ diff --git a/lib/parser/ast/nodes/exprs/NamespaceRef.cpp b/lib/parser/ast/nodes/exprs/NamespaceRef.cpp new file mode 100644 index 0000000..7443147 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/NamespaceRef.cpp @@ -0,0 +1,39 @@ +#include "lib/parser/ast/nodes/exprs/NamespaceRef.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void NamespaceRef::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Expr& NamespaceRef::NamespaceExpr() const noexcept { + return *namespace_; +} + +Expr& NamespaceRef::MutableNamespaceExpr() noexcept { + return *namespace_; +} + +void NamespaceRef::SetNamespaceExpr(std::unique_ptr new_namespace_expr) { + namespace_ = std::move(new_namespace_expr); +} + +std::unique_ptr NamespaceRef::ReplaceNamespaceExpr(std::unique_ptr new_namespace_expr) { + auto old_ns = std::move(namespace_); + namespace_ = std::move(new_namespace_expr); + return old_ns; +} + +const std::string& NamespaceRef::Name() const noexcept { + return name_; +} + +void NamespaceRef::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/NamespaceRef.hpp b/lib/parser/ast/nodes/exprs/NamespaceRef.hpp new file mode 100644 index 0000000..0f0eb72 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/NamespaceRef.hpp @@ -0,0 +1,30 @@ +#ifndef PARSER_NAMESPACEREF_HPP_ +#define PARSER_NAMESPACEREF_HPP_ + +#include +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class NamespaceRef : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const Expr& NamespaceExpr() const noexcept; + Expr& MutableNamespaceExpr() noexcept; + void SetNamespaceExpr(std::unique_ptr new_namespace_expr); + std::unique_ptr ReplaceNamespaceExpr(std::unique_ptr new_namespace_expr); + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + +private: + std::unique_ptr namespace_; + std::string name_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_NAMESPACEREF_HPP_ diff --git a/lib/parser/ast/nodes/exprs/SafeCall.cpp b/lib/parser/ast/nodes/exprs/SafeCall.cpp new file mode 100644 index 0000000..a0a158a --- /dev/null +++ b/lib/parser/ast/nodes/exprs/SafeCall.cpp @@ -0,0 +1,67 @@ +#include "lib/parser/ast/nodes/exprs/SafeCall.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void SafeCall::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Expr& SafeCall::Object() const noexcept { + return *object_; +} + +Expr& SafeCall::MutableObject() noexcept { + return *object_; +} + +void SafeCall::SetObject(std::unique_ptr object_expr) { + object_ = std::move(object_expr); +} + +std::unique_ptr SafeCall::ReplaceObject(std::unique_ptr new_object) { + auto old_object = std::move(object_); + object_ = std::move(new_object); + return old_object; +} + +const std::string& SafeCall::Method() const noexcept { + return method_; +} + +void SafeCall::SetMethod(std::string method_name) { + method_ = std::move(method_name); +} + +const std::vector>& SafeCall::Args() const noexcept { + return args_; +} + +std::vector>& SafeCall::MutableArgs() noexcept { + return args_; +} + +void SafeCall::AddArg(std::unique_ptr argument_expr) { + args_.emplace_back(std::move(argument_expr)); +} + +void SafeCall::ClearArgs() { + args_.clear(); +} + +bool SafeCall::IsNullPropagating() const noexcept { + return true; +} + +void SafeCall::SetInferredType(TypeReference inferred) { + inferred_type_ = std::move(inferred); +} + +const std::optional& SafeCall::InferredType() const noexcept { + return inferred_type_; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/SafeCall.hpp b/lib/parser/ast/nodes/exprs/SafeCall.hpp new file mode 100644 index 0000000..1052a7d --- /dev/null +++ b/lib/parser/ast/nodes/exprs/SafeCall.hpp @@ -0,0 +1,47 @@ +#ifndef PARSER_SAFECALL_HPP_ +#define PARSER_SAFECALL_HPP_ + +#include +#include +#include +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class AstVisitor; + +class SafeCall : public Expr { +public: + void Accept(AstVisitor& v) override; + + const Expr& Object() const noexcept; + Expr& MutableObject() noexcept; + void SetObject(std::unique_ptr object_expr); + std::unique_ptr ReplaceObject(std::unique_ptr new_object); + + const std::string& Method() const noexcept; + void SetMethod(std::string method_name); + + const std::vector>& Args() const noexcept; + std::vector>& MutableArgs() noexcept; + void AddArg(std::unique_ptr argument_expr); + void ClearArgs(); + + bool IsNullPropagating() const noexcept; + + void SetInferredType(TypeReference inferred); + const std::optional& InferredType() const noexcept; + +private: + std::unique_ptr object_; + std::string method_; + std::vector> args_; + std::optional inferred_type_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_SAFECALL_HPP_ diff --git a/lib/parser/ast/nodes/exprs/TypeTestIs.cpp b/lib/parser/ast/nodes/exprs/TypeTestIs.cpp new file mode 100644 index 0000000..9b360d8 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/TypeTestIs.cpp @@ -0,0 +1,43 @@ +#include "lib/parser/ast/nodes/exprs/TypeTestIs.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void TypeTestIs::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Expr& TypeTestIs::Expression() const noexcept { + return *expr; +} + +Expr& TypeTestIs::MutableExpression() noexcept { + return *expr; +} + +void TypeTestIs::SetExpression(std::unique_ptr new_expression) { + expr = std::move(new_expression); +} + +std::unique_ptr TypeTestIs::ReplaceExpression(std::unique_ptr new_expression) { + auto old_expr = std::move(expr); + expr = std::move(new_expression); + return old_expr; +} + +const TypeReference& TypeTestIs::Type() const noexcept { + return type; +} + +TypeReference& TypeTestIs::MutableType() noexcept { + return type; +} + +void TypeTestIs::SetType(TypeReference new_type) { + type = std::move(new_type); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/TypeTestIs.hpp b/lib/parser/ast/nodes/exprs/TypeTestIs.hpp new file mode 100644 index 0000000..4cff1ce --- /dev/null +++ b/lib/parser/ast/nodes/exprs/TypeTestIs.hpp @@ -0,0 +1,31 @@ +#ifndef PARSER_TYPETESTIS_HPP_ +#define PARSER_TYPETESTIS_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class TypeTestIs : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const Expr& Expression() const noexcept; + Expr& MutableExpression() noexcept; + void SetExpression(std::unique_ptr new_expression); + std::unique_ptr ReplaceExpression(std::unique_ptr new_expression); + + const TypeReference& Type() const noexcept; + TypeReference& MutableType() noexcept; + void SetType(TypeReference new_type); + +private: + std::unique_ptr expr; + TypeReference type; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_TYPETESTIS_HPP_ diff --git a/lib/parser/ast/nodes/exprs/Unary.cpp b/lib/parser/ast/nodes/exprs/Unary.cpp new file mode 100644 index 0000000..e7f5edd --- /dev/null +++ b/lib/parser/ast/nodes/exprs/Unary.cpp @@ -0,0 +1,39 @@ +#include "lib/parser/ast/nodes/exprs/Unary.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void Unary::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const IUnaryOpTag& Unary::Op() const noexcept { + return *op_; +} + +void Unary::SetOp(const IUnaryOpTag& new_op) noexcept { + op_ = &new_op; +} + +const Expr& Unary::Operand() const noexcept { + return *operand_; +} + +Expr& Unary::MutableOperand() noexcept { + return *operand_; +} + +void Unary::SetOperand(std::unique_ptr new_operand) { + operand_ = std::move(new_operand); +} + +std::unique_ptr Unary::ReplaceOperand(std::unique_ptr new_operand) { + auto old_operand = std::move(operand_); + operand_ = std::move(new_operand); + return old_operand; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/Unary.hpp b/lib/parser/ast/nodes/exprs/Unary.hpp new file mode 100644 index 0000000..60319cc --- /dev/null +++ b/lib/parser/ast/nodes/exprs/Unary.hpp @@ -0,0 +1,31 @@ +#ifndef PARSER_UNARY_HPP_ +#define PARSER_UNARY_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "tags/IUnaryOpTag.hpp" +#include "tags/OpTags.hpp" + +namespace ovum::compiler::parser { + +class Unary : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const IUnaryOpTag& Op() const noexcept; + void SetOp(const IUnaryOpTag& new_op) noexcept; + + const Expr& Operand() const noexcept; + Expr& MutableOperand() noexcept; + void SetOperand(std::unique_ptr new_operand); + std::unique_ptr ReplaceOperand(std::unique_ptr new_operand); + +private: + const IUnaryOpTag* op_ = &OpTags::Neg(); + std::unique_ptr operand_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_UNARY_HPP_ diff --git a/lib/parser/ast/nodes/exprs/literals/BoolLit.cpp b/lib/parser/ast/nodes/exprs/literals/BoolLit.cpp new file mode 100644 index 0000000..51a7488 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/BoolLit.cpp @@ -0,0 +1,19 @@ +#include "lib/parser/ast/nodes/exprs/literals/BoolLit.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void BoolLit::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +bool BoolLit::Value() const noexcept { + return value; +} + +void BoolLit::SetValue(bool new_value) noexcept { + value = new_value; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/literals/BoolLit.hpp b/lib/parser/ast/nodes/exprs/literals/BoolLit.hpp new file mode 100644 index 0000000..399b701 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/BoolLit.hpp @@ -0,0 +1,21 @@ +#ifndef PARSER_BOOLLIT_HPP_ +#define PARSER_BOOLLIT_HPP_ + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class BoolLit : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + bool Value() const noexcept; + void SetValue(bool new_value) noexcept; + +private: + bool value = false; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_BOOLLIT_HPP_ diff --git a/lib/parser/ast/nodes/exprs/literals/CharLit.cpp b/lib/parser/ast/nodes/exprs/literals/CharLit.cpp new file mode 100644 index 0000000..4c45367 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/CharLit.cpp @@ -0,0 +1,19 @@ +#include "lib/parser/ast/nodes/exprs/literals/CharLit.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void CharLit::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +char CharLit::Value() const noexcept { + return value_; +} + +void CharLit::SetValue(char new_value) noexcept { + value_ = new_value; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/literals/CharLit.hpp b/lib/parser/ast/nodes/exprs/literals/CharLit.hpp new file mode 100644 index 0000000..6393dd8 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/CharLit.hpp @@ -0,0 +1,21 @@ +#ifndef PARSER_CHARLIT_HPP_ +#define PARSER_CHARLIT_HPP_ + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class CharLit : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + char Value() const noexcept; + void SetValue(char new_value) noexcept; + +private: + char value_ = '\0'; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_CHARLIT_HPP_ diff --git a/lib/parser/ast/nodes/exprs/literals/FloatLit.cpp b/lib/parser/ast/nodes/exprs/literals/FloatLit.cpp new file mode 100644 index 0000000..99631d6 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/FloatLit.cpp @@ -0,0 +1,19 @@ +#include "lib/parser/ast/nodes/exprs/literals/FloatLit.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void FloatLit::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +double FloatLit::Value() const noexcept { + return value; +} + +void FloatLit::SetValue(double new_value) noexcept { + value = new_value; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/literals/FloatLit.hpp b/lib/parser/ast/nodes/exprs/literals/FloatLit.hpp new file mode 100644 index 0000000..4dba68a --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/FloatLit.hpp @@ -0,0 +1,21 @@ +#ifndef PARSER_FLOATLIT_HPP_ +#define PARSER_FLOATLIT_HPP_ + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class FloatLit : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + double Value() const noexcept; + void SetValue(double new_value) noexcept; + +private: + double value = 0.0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_FLOATLIT_HPP_ diff --git a/lib/parser/ast/nodes/exprs/literals/IntLit.cpp b/lib/parser/ast/nodes/exprs/literals/IntLit.cpp new file mode 100644 index 0000000..8c9d681 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/IntLit.cpp @@ -0,0 +1,19 @@ +#include "lib/parser/ast/nodes/exprs/literals/IntLit.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void IntLit::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +int64_t IntLit::Value() const noexcept { + return value; +} + +void IntLit::SetValue(int64_t new_value) noexcept { + value = new_value; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/literals/IntLit.hpp b/lib/parser/ast/nodes/exprs/literals/IntLit.hpp new file mode 100644 index 0000000..3ec55e5 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/IntLit.hpp @@ -0,0 +1,22 @@ +#ifndef PARSER_INTLIT_HPP_ +#define PARSER_INTLIT_HPP_ + +#include +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class IntLit : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + int64_t Value() const noexcept; + void SetValue(int64_t new_value) noexcept; + +private: + int64_t value = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_INTLIT_HPP_ diff --git a/lib/parser/ast/nodes/exprs/literals/NullLit.cpp b/lib/parser/ast/nodes/exprs/literals/NullLit.cpp new file mode 100644 index 0000000..1af96fd --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/NullLit.cpp @@ -0,0 +1,11 @@ +#include "lib/parser/ast/nodes/exprs/literals/NullLit.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void NullLit::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/literals/NullLit.hpp b/lib/parser/ast/nodes/exprs/literals/NullLit.hpp new file mode 100644 index 0000000..21ac8a4 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/NullLit.hpp @@ -0,0 +1,15 @@ +#ifndef PARSER_NULLLIT_HPP_ +#define PARSER_NULLLIT_HPP_ + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class NullLit : public Expr { +public: + void Accept(AstVisitor& visitor) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_NULLLIT_HPP_ diff --git a/lib/parser/ast/nodes/exprs/literals/StringLit.cpp b/lib/parser/ast/nodes/exprs/literals/StringLit.cpp new file mode 100644 index 0000000..db667f2 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/StringLit.cpp @@ -0,0 +1,21 @@ +#include "lib/parser/ast/nodes/exprs/literals/StringLit.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void StringLit::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const std::string& StringLit::Value() const noexcept { + return value_; +} + +void StringLit::SetValue(std::string new_value) { + value_ = std::move(new_value); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/literals/StringLit.hpp b/lib/parser/ast/nodes/exprs/literals/StringLit.hpp new file mode 100644 index 0000000..e6a1ed5 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/literals/StringLit.hpp @@ -0,0 +1,23 @@ +#ifndef PARSER_STRINGLIT_HPP_ +#define PARSER_STRINGLIT_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class StringLit : public Expr { +public: + void Accept(AstVisitor& visitor) override; + + const std::string& Value() const noexcept; + void SetValue(std::string new_value); + +private: + std::string value_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STRINGLIT_HPP_ diff --git a/lib/parser/ast/nodes/exprs/tags/IAssignOpTag.hpp b/lib/parser/ast/nodes/exprs/tags/IAssignOpTag.hpp new file mode 100644 index 0000000..a7f6116 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/tags/IAssignOpTag.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_IASSIGNOPTAG_HPP_ +#define PARSER_IASSIGNOPTAG_HPP_ + +#include + +namespace ovum::compiler::parser { + +class IAssignOpTag { +public: + virtual ~IAssignOpTag() = default; + + virtual std::string_view Name() const = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IASSIGNOPTAG_HPP_ diff --git a/lib/parser/ast/nodes/exprs/tags/IBinaryOpTag.hpp b/lib/parser/ast/nodes/exprs/tags/IBinaryOpTag.hpp new file mode 100644 index 0000000..0032c50 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/tags/IBinaryOpTag.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_IBINARYOPTAG_HPP_ +#define PARSER_IBINARYOPTAG_HPP_ + +#include + +namespace ovum::compiler::parser { + +class IBinaryOpTag { +public: + virtual ~IBinaryOpTag() = default; + + virtual std::string_view Name() const = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IBINARYOPTAG_HPP_ diff --git a/lib/parser/ast/nodes/exprs/tags/IUnaryOpTag.hpp b/lib/parser/ast/nodes/exprs/tags/IUnaryOpTag.hpp new file mode 100644 index 0000000..d5d42ee --- /dev/null +++ b/lib/parser/ast/nodes/exprs/tags/IUnaryOpTag.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_IUNARYOPTAG_HPP_ +#define PARSER_IUNARYOPTAG_HPP_ + +#include + +namespace ovum::compiler::parser { + +class IUnaryOpTag { +public: + virtual ~IUnaryOpTag() = default; + + virtual std::string_view Name() const = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IUNARYOPTAG_HPP_ diff --git a/lib/parser/ast/nodes/exprs/tags/OpTags.cpp b/lib/parser/ast/nodes/exprs/tags/OpTags.cpp new file mode 100644 index 0000000..53c8c87 --- /dev/null +++ b/lib/parser/ast/nodes/exprs/tags/OpTags.cpp @@ -0,0 +1,224 @@ +#include "OpTags.hpp" + +#include + +namespace ovum::compiler::parser { + +namespace { + +struct BinaryAdd : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "add"; + } +}; + +struct BinarySub : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "sub"; + } +}; + +struct BinaryMul : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "mul"; + } +}; + +struct BinaryDiv : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "div"; + } +}; + +struct BinaryMod : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "mod"; + } +}; + +struct BinaryLt : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "lt"; + } +}; + +struct BinaryLe : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "le"; + } +}; + +struct BinaryGt : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "gt"; + } +}; + +struct BinaryGe : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "ge"; + } +}; + +struct BinaryEq : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "eq"; + } +}; + +struct BinaryNe : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "ne"; + } +}; + +struct BinaryAnd : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "and"; + } +}; + +struct BinaryOr : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "or"; + } +}; + +struct BinaryXor : IBinaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "xor"; + } +}; + +struct UnaryNeg : IUnaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "neg"; + } +}; + +struct UnaryPlus : IUnaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "plus"; + } +}; + +struct UnaryNot : IUnaryOpTag { + [[nodiscard]] std::string_view Name() const override { + return "not"; + } +}; + +struct AssignRef : IAssignOpTag { + [[nodiscard]] std::string_view Name() const override { + return "="; + } +}; + +struct AssignCopy : IAssignOpTag { + [[nodiscard]] std::string_view Name() const override { + return ":="; + } +}; + +} // namespace + +namespace OpTags { + +const IBinaryOpTag& Add() { + static BinaryAdd t; + return t; +} + +const IBinaryOpTag& Sub() { + static BinarySub t; + return t; +} + +const IBinaryOpTag& Mul() { + static BinaryMul t; + return t; +} + +const IBinaryOpTag& Div() { + static BinaryDiv t; + return t; +} + +const IBinaryOpTag& Mod() { + static BinaryMod t; + return t; +} + +const IBinaryOpTag& Lt() { + static BinaryLt t; + return t; +} + +const IBinaryOpTag& Le() { + static BinaryLe t; + return t; +} + +const IBinaryOpTag& Gt() { + static BinaryGt t; + return t; +} + +const IBinaryOpTag& Ge() { + static BinaryGe t; + return t; +} + +const IBinaryOpTag& Eq() { + static BinaryEq t; + return t; +} + +const IBinaryOpTag& Ne() { + static BinaryNe t; + return t; +} + +const IBinaryOpTag& And() { + static BinaryAnd t; + return t; +} + +const IBinaryOpTag& Or() { + static BinaryOr t; + return t; +} + +const IBinaryOpTag& Xor() { + static BinaryXor t; + return t; +} + +const IUnaryOpTag& Neg() { + static UnaryNeg t; + return t; +} + +const IUnaryOpTag& Plus() { + static UnaryPlus t; + return t; +} + +const IUnaryOpTag& Not() { + static UnaryNot t; + return t; +} + +const IAssignOpTag& RefAssign() { + static AssignRef t; + return t; +} + +const IAssignOpTag& CopyAssign() { + static AssignCopy t; + return t; +} + +} // namespace OpTags + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/exprs/tags/OpTags.hpp b/lib/parser/ast/nodes/exprs/tags/OpTags.hpp new file mode 100644 index 0000000..7879e2e --- /dev/null +++ b/lib/parser/ast/nodes/exprs/tags/OpTags.hpp @@ -0,0 +1,39 @@ +#ifndef PARSER_OPTAGS_HPP_ +#define PARSER_OPTAGS_HPP_ + +#include "IAssignOpTag.hpp" +#include "IBinaryOpTag.hpp" +#include "IUnaryOpTag.hpp" + +namespace ovum::compiler::parser { + +namespace OpTags { +// binary +const IBinaryOpTag& Add(); +const IBinaryOpTag& Sub(); +const IBinaryOpTag& Mul(); +const IBinaryOpTag& Div(); +const IBinaryOpTag& Mod(); +const IBinaryOpTag& Lt(); +const IBinaryOpTag& Le(); +const IBinaryOpTag& Gt(); +const IBinaryOpTag& Ge(); +const IBinaryOpTag& Eq(); +const IBinaryOpTag& Ne(); +const IBinaryOpTag& And(); +const IBinaryOpTag& Or(); +const IBinaryOpTag& Xor(); + +// unary +const IUnaryOpTag& Neg(); +const IUnaryOpTag& Plus(); +const IUnaryOpTag& Not(); + +// assign +const IAssignOpTag& RefAssign(); // = +const IAssignOpTag& CopyAssign(); // := +} // namespace OpTags + +} // namespace ovum::compiler::parser + +#endif // PARSER_OPTAGS_HPP_ diff --git a/lib/parser/ast/nodes/stmts/Block.cpp b/lib/parser/ast/nodes/stmts/Block.cpp new file mode 100644 index 0000000..e572b0a --- /dev/null +++ b/lib/parser/ast/nodes/stmts/Block.cpp @@ -0,0 +1,51 @@ +#include "lib/parser/ast/nodes/stmts/Block.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void Block::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +std::vector>& Block::GetStatements() { + return stmts_; +} + +const std::vector>& Block::GetStatements() const { + return stmts_; +} + +void Block::Append(std::unique_ptr statement) { + stmts_.emplace_back(std::move(statement)); +} + +void Block::Insert(std::size_t index, std::unique_ptr statement) { + if (index >= stmts_.size()) { + stmts_.emplace_back(std::move(statement)); + } else { + stmts_.insert(stmts_.begin() + static_cast(index), std::move(statement)); + } +} + +std::unique_ptr Block::ReleaseAt(std::size_t index) { + if (index >= stmts_.size()) { + return nullptr; + } + + auto old_stmt = std::move(stmts_[index]); + stmts_.erase(stmts_.begin() + static_cast(index)); + return old_stmt; +} + +void Block::Clear() noexcept { + stmts_.clear(); +} + +std::size_t Block::Size() const noexcept { + return stmts_.size(); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/Block.hpp b/lib/parser/ast/nodes/stmts/Block.hpp new file mode 100644 index 0000000..046ba3e --- /dev/null +++ b/lib/parser/ast/nodes/stmts/Block.hpp @@ -0,0 +1,32 @@ +#ifndef PARSER_BLOCK_HPP_ +#define PARSER_BLOCK_HPP_ + +#include +#include +#include + +#include "lib/parser/ast/nodes/base/AstNode.hpp" +#include "lib/parser/ast/nodes/base/Stmt.hpp" + +namespace ovum::compiler::parser { + +class Block : public Stmt { +public: + void Accept(AstVisitor& visitor) override; + + std::vector>& GetStatements(); + const std::vector>& GetStatements() const; + void Append(std::unique_ptr statement); + + void Insert(std::size_t index, std::unique_ptr statement); + std::unique_ptr ReleaseAt(std::size_t index); + void Clear() noexcept; + std::size_t Size() const noexcept; + +private: + std::vector> stmts_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_BLOCK_HPP_ diff --git a/lib/parser/ast/nodes/stmts/Branch.cpp b/lib/parser/ast/nodes/stmts/Branch.cpp new file mode 100644 index 0000000..8dbdecf --- /dev/null +++ b/lib/parser/ast/nodes/stmts/Branch.cpp @@ -0,0 +1,43 @@ +#include "lib/parser/ast/nodes/stmts/Branch.hpp" + +#include + +namespace ovum::compiler::parser { + +Branch::Branch(std::unique_ptr condition, std::unique_ptr then_block) : + condition_(std::move(condition)), then_block_(std::move(then_block)) { +} + +const Expr* Branch::Condition() const noexcept { + return condition_.get(); +} + +Expr* Branch::MutableCondition() noexcept { + return condition_.get(); +} + +void Branch::SetCondition(std::unique_ptr expression) { + condition_ = std::move(expression); +} + +std::unique_ptr Branch::ReleaseCondition() { + return std::move(condition_); +} + +const Block* Branch::Then() const noexcept { + return then_block_.get(); +} + +Block* Branch::MutableThen() noexcept { + return then_block_.get(); +} + +void Branch::SetThen(std::unique_ptr then_body) { + then_block_ = std::move(then_body); +} + +std::unique_ptr Branch::ReleaseThen() { + return std::move(then_block_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/Branch.hpp b/lib/parser/ast/nodes/stmts/Branch.hpp new file mode 100644 index 0000000..cc679ff --- /dev/null +++ b/lib/parser/ast/nodes/stmts/Branch.hpp @@ -0,0 +1,37 @@ +#ifndef PARSER_BRANCH_HPP_ +#define PARSER_BRANCH_HPP_ + +#include + +#include "Block.hpp" +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class Branch { +public: + Branch(std::unique_ptr condition, std::unique_ptr then_block); + Branch(const Branch&) = delete; + Branch& operator=(const Branch&) = delete; + Branch(Branch&&) noexcept = default; + Branch& operator=(Branch&&) noexcept = default; + ~Branch() = default; + + const Expr* Condition() const noexcept; + Expr* MutableCondition() noexcept; + void SetCondition(std::unique_ptr expression); + std::unique_ptr ReleaseCondition(); + + const Block* Then() const noexcept; + Block* MutableThen() noexcept; + void SetThen(std::unique_ptr then_body); + std::unique_ptr ReleaseThen(); + +private: + std::unique_ptr condition_; + std::unique_ptr then_block_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_BRANCH_HPP_ diff --git a/lib/parser/ast/nodes/stmts/BreakStmt.cpp b/lib/parser/ast/nodes/stmts/BreakStmt.cpp new file mode 100644 index 0000000..1685231 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/BreakStmt.cpp @@ -0,0 +1,11 @@ +#include "lib/parser/ast/nodes/stmts/BreakStmt.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void BreakStmt::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/BreakStmt.hpp b/lib/parser/ast/nodes/stmts/BreakStmt.hpp new file mode 100644 index 0000000..bf3fbf5 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/BreakStmt.hpp @@ -0,0 +1,15 @@ +#ifndef PARSER_BREAKSTMT_HPP_ +#define PARSER_BREAKSTMT_HPP_ + +#include "lib/parser/ast/nodes/base/Stmt.hpp" + +namespace ovum::compiler::parser { + +class BreakStmt : public Stmt { +public: + void Accept(AstVisitor& visitor) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_BREAKSTMT_HPP_ diff --git a/lib/parser/ast/nodes/stmts/ContinueStmt.cpp b/lib/parser/ast/nodes/stmts/ContinueStmt.cpp new file mode 100644 index 0000000..aa19fc7 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/ContinueStmt.cpp @@ -0,0 +1,11 @@ +#include "lib/parser/ast/nodes/stmts/ContinueStmt.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +void ContinueStmt::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/ContinueStmt.hpp b/lib/parser/ast/nodes/stmts/ContinueStmt.hpp new file mode 100644 index 0000000..11ce141 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/ContinueStmt.hpp @@ -0,0 +1,15 @@ +#ifndef PARSER_CONTINUESTMT_HPP_ +#define PARSER_CONTINUESTMT_HPP_ + +#include "lib/parser/ast/nodes/base/Stmt.hpp" + +namespace ovum::compiler::parser { + +class ContinueStmt : public Stmt { +public: + void Accept(AstVisitor& visitor) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_CONTINUESTMT_HPP_ diff --git a/lib/parser/ast/nodes/stmts/ExprStmt.cpp b/lib/parser/ast/nodes/stmts/ExprStmt.cpp new file mode 100644 index 0000000..80424ef --- /dev/null +++ b/lib/parser/ast/nodes/stmts/ExprStmt.cpp @@ -0,0 +1,29 @@ +#include "lib/parser/ast/nodes/stmts/ExprStmt.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void ExprStmt::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Expr* ExprStmt::Expression() const noexcept { + return expr_.get(); +} + +Expr* ExprStmt::MutableExpression() noexcept { + return expr_.get(); +} + +void ExprStmt::SetExpression(std::unique_ptr expression) { + expr_ = std::move(expression); +} + +std::unique_ptr ExprStmt::ReleaseExpression() { + return std::move(expr_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/ExprStmt.hpp b/lib/parser/ast/nodes/stmts/ExprStmt.hpp new file mode 100644 index 0000000..420b611 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/ExprStmt.hpp @@ -0,0 +1,26 @@ +#ifndef PARSER_EXPRSTMT_HPP_ +#define PARSER_EXPRSTMT_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/ast/nodes/base/Stmt.hpp" + +namespace ovum::compiler::parser { + +class ExprStmt : public Stmt { +public: + void Accept(AstVisitor& visitor) override; + + const Expr* Expression() const noexcept; + Expr* MutableExpression() noexcept; + void SetExpression(std::unique_ptr expression); + std::unique_ptr ReleaseExpression(); + +private: + std::unique_ptr expr_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_EXPRSTMT_HPP_ diff --git a/lib/parser/ast/nodes/stmts/ForStmt.cpp b/lib/parser/ast/nodes/stmts/ForStmt.cpp new file mode 100644 index 0000000..3767dbc --- /dev/null +++ b/lib/parser/ast/nodes/stmts/ForStmt.cpp @@ -0,0 +1,53 @@ +#include "lib/parser/ast/nodes/stmts/ForStmt.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void ForStmt::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const std::string& ForStmt::IteratorName() const noexcept { + return iter_name_; +} + +void ForStmt::SetIteratorName(std::string new_name) { + iter_name_ = std::move(new_name); +} + +const Expr* ForStmt::IteratorExpr() const noexcept { + return iter_expr_.get(); +} + +Expr* ForStmt::MutableIteratorExpr() noexcept { + return iter_expr_.get(); +} + +void ForStmt::SetIteratorExpr(std::unique_ptr expression) { + iter_expr_ = std::move(expression); +} + +std::unique_ptr ForStmt::ReleaseIteratorExpr() { + return std::move(iter_expr_); +} + +const Block* ForStmt::Body() const noexcept { + return body_.get(); +} + +Block* ForStmt::MutableBody() noexcept { + return body_.get(); +} + +void ForStmt::SetBody(std::unique_ptr body_block) { + body_ = std::move(body_block); +} + +std::unique_ptr ForStmt::ReleaseBody() { + return std::move(body_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/ForStmt.hpp b/lib/parser/ast/nodes/stmts/ForStmt.hpp new file mode 100644 index 0000000..954f0e4 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/ForStmt.hpp @@ -0,0 +1,37 @@ +#ifndef PARSER_FORSTMT_HPP_ +#define PARSER_FORSTMT_HPP_ + +#include +#include + +#include "Block.hpp" +#include "lib/parser/ast/nodes/base/Expr.hpp" + +namespace ovum::compiler::parser { + +class ForStmt : public Stmt { +public: + void Accept(AstVisitor& visitor) override; + + const std::string& IteratorName() const noexcept; + void SetIteratorName(std::string new_name); + + const Expr* IteratorExpr() const noexcept; + Expr* MutableIteratorExpr() noexcept; + void SetIteratorExpr(std::unique_ptr expression); + std::unique_ptr ReleaseIteratorExpr(); + + const Block* Body() const noexcept; + Block* MutableBody() noexcept; + void SetBody(std::unique_ptr body_block); + std::unique_ptr ReleaseBody(); + +private: + std::string iter_name_; + std::unique_ptr iter_expr_; + std::unique_ptr body_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_FORSTMT_HPP_ diff --git a/lib/parser/ast/nodes/stmts/IfStmt.cpp b/lib/parser/ast/nodes/stmts/IfStmt.cpp new file mode 100644 index 0000000..dd768dd --- /dev/null +++ b/lib/parser/ast/nodes/stmts/IfStmt.cpp @@ -0,0 +1,53 @@ +#include "lib/parser/ast/nodes/stmts/IfStmt.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void IfStmt::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const std::vector& IfStmt::Branches() const noexcept { + return branches_; +} + +std::vector& IfStmt::MutableBranches() noexcept { + return branches_; +} + +void IfStmt::AddBranch(Branch branch_value) { + branches_.emplace_back(std::move(branch_value)); +} + +void IfStmt::EmplaceBranch(std::unique_ptr cond, std::unique_ptr then_blk) { + branches_.emplace_back(std::move(cond), std::move(then_blk)); +} + +const Block* IfStmt::ElseBlock() const noexcept { + return else_block_.get(); +} + +Block* IfStmt::MutableElseBlock() noexcept { + return else_block_.get(); +} + +void IfStmt::SetElseBlock(std::unique_ptr else_body) { + else_block_ = std::move(else_body); +} + +std::unique_ptr IfStmt::ReleaseElseBlock() { + return std::move(else_block_); +} + +bool IfStmt::HasElse() const noexcept { + return static_cast(else_block_); +} + +bool IfStmt::Empty() const noexcept { + return branches_.empty() && !else_block_; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/IfStmt.hpp b/lib/parser/ast/nodes/stmts/IfStmt.hpp new file mode 100644 index 0000000..e272bc3 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/IfStmt.hpp @@ -0,0 +1,38 @@ +#ifndef PARSER_IFSTMT_HPP_ +#define PARSER_IFSTMT_HPP_ + +#include +#include + +#include "Block.hpp" +#include "Branch.hpp" +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/ast/nodes/base/Stmt.hpp" + +namespace ovum::compiler::parser { + +class IfStmt : public Stmt { +public: + void Accept(AstVisitor& visitor) override; + + const std::vector& Branches() const noexcept; + std::vector& MutableBranches() noexcept; + void AddBranch(Branch branch_value); + void EmplaceBranch(std::unique_ptr cond, std::unique_ptr then_blk); + + const Block* ElseBlock() const noexcept; + Block* MutableElseBlock() noexcept; + void SetElseBlock(std::unique_ptr else_body); + std::unique_ptr ReleaseElseBlock(); + + bool HasElse() const noexcept; + bool Empty() const noexcept; + +private: + std::vector branches_; + std::unique_ptr else_block_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IFSTMT_HPP_ diff --git a/lib/parser/ast/nodes/stmts/ReturnStmt.cpp b/lib/parser/ast/nodes/stmts/ReturnStmt.cpp new file mode 100644 index 0000000..0ad75a8 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/ReturnStmt.cpp @@ -0,0 +1,43 @@ +#include "lib/parser/ast/nodes/stmts/ReturnStmt.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void ReturnStmt::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +bool ReturnStmt::HasValue() const noexcept { + return value_.has_value() && static_cast(value_.value()); +} + +const Expr* ReturnStmt::Value() const noexcept { + return value_.has_value() ? value_.value().get() : nullptr; +} + +Expr* ReturnStmt::MutableValue() noexcept { + return value_.has_value() ? value_.value().get() : nullptr; +} + +void ReturnStmt::SetValue(std::unique_ptr new_value) { + value_.emplace(std::move(new_value)); +} + +void ReturnStmt::ResetValue() { + value_.reset(); +} + +std::unique_ptr ReturnStmt::ReleaseValue() { + if (!value_.has_value()) { + return nullptr; + } + + auto out = std::move(value_.value()); + value_.reset(); + return out; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/ReturnStmt.hpp b/lib/parser/ast/nodes/stmts/ReturnStmt.hpp new file mode 100644 index 0000000..3437e5a --- /dev/null +++ b/lib/parser/ast/nodes/stmts/ReturnStmt.hpp @@ -0,0 +1,29 @@ +#ifndef PARSER_RETURNSTMT_HPP_ +#define PARSER_RETURNSTMT_HPP_ + +#include +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/ast/nodes/base/Stmt.hpp" + +namespace ovum::compiler::parser { + +class ReturnStmt : public Stmt { +public: + void Accept(AstVisitor& visitor) override; + + bool HasValue() const noexcept; + const Expr* Value() const noexcept; + Expr* MutableValue() noexcept; + void SetValue(std::unique_ptr new_value); + void ResetValue(); + std::unique_ptr ReleaseValue(); + +private: + std::optional> value_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_RETURNSTMT_HPP_ diff --git a/lib/parser/ast/nodes/stmts/UnsafeBlock.cpp b/lib/parser/ast/nodes/stmts/UnsafeBlock.cpp new file mode 100644 index 0000000..e15365d --- /dev/null +++ b/lib/parser/ast/nodes/stmts/UnsafeBlock.cpp @@ -0,0 +1,29 @@ +#include "lib/parser/ast/nodes/stmts/UnsafeBlock.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void UnsafeBlock::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Block* UnsafeBlock::Body() const noexcept { + return body_.get(); +} + +Block* UnsafeBlock::MutableBody() noexcept { + return body_.get(); +} + +void UnsafeBlock::SetBody(std::unique_ptr body_block) { + body_ = std::move(body_block); +} + +std::unique_ptr UnsafeBlock::ReleaseBody() { + return std::move(body_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/UnsafeBlock.hpp b/lib/parser/ast/nodes/stmts/UnsafeBlock.hpp new file mode 100644 index 0000000..76a8d92 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/UnsafeBlock.hpp @@ -0,0 +1,26 @@ +#ifndef PARSER_UNSAFEBLOCK_HPP_ +#define PARSER_UNSAFEBLOCK_HPP_ + +#include + +#include "Block.hpp" +#include "lib/parser/ast/nodes/base/Stmt.hpp" + +namespace ovum::compiler::parser { + +class UnsafeBlock : public Stmt { +public: + void Accept(AstVisitor& visitor) override; + + const Block* Body() const noexcept; + Block* MutableBody() noexcept; + void SetBody(std::unique_ptr body_block); + std::unique_ptr ReleaseBody(); + +private: + std::unique_ptr body_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_UNSAFEBLOCK_HPP_ diff --git a/lib/parser/ast/nodes/stmts/VarDeclStmt.cpp b/lib/parser/ast/nodes/stmts/VarDeclStmt.cpp new file mode 100644 index 0000000..2d3e9a1 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/VarDeclStmt.cpp @@ -0,0 +1,57 @@ +#include "lib/parser/ast/nodes/stmts/VarDeclStmt.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void VarDeclStmt::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +bool VarDeclStmt::IsVar() const noexcept { + return is_var_; +} + +void VarDeclStmt::SetVar(bool is_var) noexcept { + is_var_ = is_var; +} + +const std::string& VarDeclStmt::Name() const noexcept { + return name_; +} + +void VarDeclStmt::SetName(std::string new_name) { + name_ = std::move(new_name); +} + +const TypeReference& VarDeclStmt::Type() const noexcept { + return type_; +} + +TypeReference& VarDeclStmt::MutableType() noexcept { + return type_; +} + +void VarDeclStmt::SetType(TypeReference new_type) { + type_ = std::move(new_type); +} + +const Expr* VarDeclStmt::Init() const noexcept { + return init_.get(); +} + +Expr* VarDeclStmt::MutableInit() noexcept { + return init_.get(); +} + +void VarDeclStmt::SetInit(std::unique_ptr init_expr) { + init_ = std::move(init_expr); +} + +std::unique_ptr VarDeclStmt::ReleaseInit() { + return std::move(init_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/VarDeclStmt.hpp b/lib/parser/ast/nodes/stmts/VarDeclStmt.hpp new file mode 100644 index 0000000..6c86680 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/VarDeclStmt.hpp @@ -0,0 +1,41 @@ +#ifndef PARSER_VARDECLSTMT_HPP_ +#define PARSER_VARDECLSTMT_HPP_ + +#include +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/ast/nodes/base/Stmt.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class VarDeclStmt : public Stmt { +public: + void Accept(AstVisitor& visitor) override; + + bool IsVar() const noexcept; + void SetVar(bool is_var) noexcept; + + const std::string& Name() const noexcept; + void SetName(std::string new_name); + + const TypeReference& Type() const noexcept; + TypeReference& MutableType() noexcept; + void SetType(TypeReference new_type); + + const Expr* Init() const noexcept; + Expr* MutableInit() noexcept; + void SetInit(std::unique_ptr init_expr); + std::unique_ptr ReleaseInit(); + +private: + bool is_var_ = false; + std::string name_; + TypeReference type_; + std::unique_ptr init_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_VARDECLSTMT_HPP_ diff --git a/lib/parser/ast/nodes/stmts/WhileStmt.cpp b/lib/parser/ast/nodes/stmts/WhileStmt.cpp new file mode 100644 index 0000000..952b0f8 --- /dev/null +++ b/lib/parser/ast/nodes/stmts/WhileStmt.cpp @@ -0,0 +1,45 @@ +#include "lib/parser/ast/nodes/stmts/WhileStmt.hpp" + +#include "lib/parser/ast/AstVisitor.hpp" + +#include + +namespace ovum::compiler::parser { + +void WhileStmt::Accept(AstVisitor& visitor) { + visitor.Visit(*this); +} + +const Expr* WhileStmt::Condition() const noexcept { + return cond_.get(); +} + +Expr* WhileStmt::MutableCondition() noexcept { + return cond_.get(); +} + +void WhileStmt::SetCondition(std::unique_ptr condition_expr) { + cond_ = std::move(condition_expr); +} + +std::unique_ptr WhileStmt::ReleaseCondition() { + return std::move(cond_); +} + +const Block* WhileStmt::Body() const noexcept { + return body_.get(); +} + +Block* WhileStmt::MutableBody() noexcept { + return body_.get(); +} + +void WhileStmt::SetBody(std::unique_ptr body_block) { + body_ = std::move(body_block); +} + +std::unique_ptr WhileStmt::ReleaseBody() { + return std::move(body_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/nodes/stmts/WhileStmt.hpp b/lib/parser/ast/nodes/stmts/WhileStmt.hpp new file mode 100644 index 0000000..8a4c65b --- /dev/null +++ b/lib/parser/ast/nodes/stmts/WhileStmt.hpp @@ -0,0 +1,33 @@ +#ifndef PARSER_WHILESTMT_HPP_ +#define PARSER_WHILESTMT_HPP_ + +#include + +#include "Block.hpp" +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/ast/nodes/base/Stmt.hpp" + +namespace ovum::compiler::parser { + +class WhileStmt : public Stmt { +public: + void Accept(AstVisitor& visitor) override; + + const Expr* Condition() const noexcept; + Expr* MutableCondition() noexcept; + void SetCondition(std::unique_ptr condition_expr); + std::unique_ptr ReleaseCondition(); + + const Block* Body() const noexcept; + Block* MutableBody() noexcept; + void SetBody(std::unique_ptr body_block); + std::unique_ptr ReleaseBody(); + +private: + std::unique_ptr cond_; + std::unique_ptr body_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_WHILESTMT_HPP_ diff --git a/lib/parser/ast/visitors/ConstWalkVisitor.cpp b/lib/parser/ast/visitors/ConstWalkVisitor.cpp new file mode 100644 index 0000000..37f244e --- /dev/null +++ b/lib/parser/ast/visitors/ConstWalkVisitor.cpp @@ -0,0 +1,274 @@ +#include "ConstWalkVisitor.hpp" + +#include "lib/parser/ast/nodes/decls/ClassDecl.hpp" +#include "lib/parser/ast/nodes/decls/FunctionDecl.hpp" +#include "lib/parser/ast/nodes/decls/GlobalVarDecl.hpp" +#include "lib/parser/ast/nodes/decls/InterfaceDecl.hpp" +#include "lib/parser/ast/nodes/decls/InterfaceMethod.hpp" +#include "lib/parser/ast/nodes/decls/Module.hpp" +#include "lib/parser/ast/nodes/decls/TypeAliasDecl.hpp" + +#include "lib/parser/ast/nodes/class_members/CallDecl.hpp" +#include "lib/parser/ast/nodes/class_members/DestructorDecl.hpp" +#include "lib/parser/ast/nodes/class_members/FieldDecl.hpp" +#include "lib/parser/ast/nodes/class_members/MethodDecl.hpp" +#include "lib/parser/ast/nodes/class_members/StaticFieldDecl.hpp" + +#include "lib/parser/ast/nodes/exprs/Assign.hpp" +#include "lib/parser/ast/nodes/exprs/Binary.hpp" +#include "lib/parser/ast/nodes/exprs/Call.hpp" +#include "lib/parser/ast/nodes/exprs/CastAs.hpp" +#include "lib/parser/ast/nodes/exprs/Elvis.hpp" +#include "lib/parser/ast/nodes/exprs/FieldAccess.hpp" +#include "lib/parser/ast/nodes/exprs/IdentRef.hpp" +#include "lib/parser/ast/nodes/exprs/IndexAccess.hpp" +#include "lib/parser/ast/nodes/exprs/NamespaceRef.hpp" +#include "lib/parser/ast/nodes/exprs/SafeCall.hpp" +#include "lib/parser/ast/nodes/exprs/TypeTestIs.hpp" +#include "lib/parser/ast/nodes/exprs/Unary.hpp" + +#include "lib/parser/ast/nodes/exprs/literals/BoolLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/CharLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/FloatLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/IntLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/NullLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/StringLit.hpp" + +#include "lib/parser/ast/nodes/stmts/Block.hpp" +#include "lib/parser/ast/nodes/stmts/BreakStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ContinueStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ExprStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ForStmt.hpp" +#include "lib/parser/ast/nodes/stmts/IfStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ReturnStmt.hpp" +#include "lib/parser/ast/nodes/stmts/UnsafeBlock.hpp" +#include "lib/parser/ast/nodes/stmts/VarDeclStmt.hpp" +#include "lib/parser/ast/nodes/stmts/WhileStmt.hpp" + +namespace ovum::compiler::parser { + +void ConstWalkVisitor::Visit(Module& node) { + for (auto& decl_ptr : node.MutableDecls()) { + decl_ptr->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(FunctionDecl& node) { + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(ClassDecl& node) { + for (auto& member : node.MutableMembers()) { + member->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(InterfaceMethod& node) { + (void) node; +} + +void ConstWalkVisitor::Visit(InterfaceDecl& node) { + for (auto& m : node.MutableMembers()) { + m->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(TypeAliasDecl& node) { + (void) node; +} + +void ConstWalkVisitor::Visit(GlobalVarDecl& node) { + if (auto* init = node.MutableInit()) { + init->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(FieldDecl& node) { + if (auto* init = node.MutableInit()) { + init->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(StaticFieldDecl& node) { + if (auto* init = node.MutableInit()) { + init->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(MethodDecl& node) { + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(CallDecl& node) { + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(DestructorDecl& node) { + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(Block& node) { + for (auto& stmt : node.GetStatements()) { + stmt->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(VarDeclStmt& node) { + if (auto* init = node.MutableInit()) { + init->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(ExprStmt& node) { + if (auto* e = node.MutableExpression()) { + e->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(ReturnStmt& node) { + if (auto* v = node.MutableValue()) { + v->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(BreakStmt& node) { + (void) node; +} + +void ConstWalkVisitor::Visit(ContinueStmt& node) { + (void) node; +} + +void ConstWalkVisitor::Visit(IfStmt& node) { + for (auto& br : node.MutableBranches()) { + if (auto* c = br.MutableCondition()) { + c->Accept(*this); + } + + if (auto* t = br.MutableThen()) { + t->Accept(*this); + } + } + + if (auto* eb = node.MutableElseBlock()) { + eb->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(WhileStmt& node) { + if (auto* c = node.MutableCondition()) { + c->Accept(*this); + } + + if (auto* b = node.MutableBody()) { + b->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(ForStmt& node) { + if (auto* it = node.MutableIteratorExpr()) { + it->Accept(*this); + } + + if (auto* b = node.MutableBody()) { + b->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(UnsafeBlock& node) { + if (auto* b = node.MutableBody()) { + b->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(Binary& node) { + node.MutableLhs().Accept(*this); + node.MutableRhs().Accept(*this); +} + +void ConstWalkVisitor::Visit(Unary& node) { + node.MutableOperand().Accept(*this); +} + +void ConstWalkVisitor::Visit(Assign& node) { + node.MutableTarget().Accept(*this); + node.MutableValue().Accept(*this); +} + +void ConstWalkVisitor::Visit(Call& node) { + node.MutableCallee().Accept(*this); + for (auto& a : node.MutableArgs()) { + a->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(FieldAccess& node) { + node.MutableObject().Accept(*this); +} + +void ConstWalkVisitor::Visit(IndexAccess& node) { + node.MutableObject().Accept(*this); + node.MutableIndexExpr().Accept(*this); +} + +void ConstWalkVisitor::Visit(NamespaceRef& node) { + node.MutableNamespaceExpr().Accept(*this); +} + +void ConstWalkVisitor::Visit(SafeCall& node) { + node.MutableObject().Accept(*this); + for (auto& a : node.MutableArgs()) { + a->Accept(*this); + } +} + +void ConstWalkVisitor::Visit(Elvis& node) { + node.MutableLhs().Accept(*this); + node.MutableRhs().Accept(*this); +} + +void ConstWalkVisitor::Visit(CastAs& node) { + node.MutableExpression().Accept(*this); +} + +void ConstWalkVisitor::Visit(TypeTestIs& node) { + node.MutableExpression().Accept(*this); +} + +void ConstWalkVisitor::Visit(IdentRef& node) { + (void) node; +} + +void ConstWalkVisitor::Visit(IntLit& node) { + (void) node; +} + +void ConstWalkVisitor::Visit(FloatLit& node) { + (void) node; +} + +void ConstWalkVisitor::Visit(StringLit& node) { + (void) node; +} + +void ConstWalkVisitor::Visit(CharLit& node) { + (void) node; +} + +void ConstWalkVisitor::Visit(BoolLit& node) { + (void) node; +} + +void ConstWalkVisitor::Visit(NullLit& node) { + (void) node; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/visitors/ConstWalkVisitor.hpp b/lib/parser/ast/visitors/ConstWalkVisitor.hpp new file mode 100644 index 0000000..c1b3f6d --- /dev/null +++ b/lib/parser/ast/visitors/ConstWalkVisitor.hpp @@ -0,0 +1,58 @@ +#ifndef PARSER_CONSTWALKVISITOR_HPP_ +#define PARSER_CONSTWALKVISITOR_HPP_ + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +class ConstWalkVisitor : public AstVisitor { +public: + ~ConstWalkVisitor() override = default; + + void Visit(Module& node) override; + void Visit(FunctionDecl& node) override; + void Visit(ClassDecl& node) override; + void Visit(InterfaceMethod& node) override; + void Visit(InterfaceDecl& node) override; + void Visit(TypeAliasDecl& node) override; + void Visit(GlobalVarDecl& node) override; + void Visit(FieldDecl& node) override; + void Visit(StaticFieldDecl& node) override; + void Visit(MethodDecl& node) override; + void Visit(CallDecl& node) override; + void Visit(DestructorDecl& node) override; + + void Visit(Block& node) override; + void Visit(VarDeclStmt& node) override; + void Visit(ExprStmt& node) override; + void Visit(ReturnStmt& node) override; + void Visit(BreakStmt& node) override; + void Visit(ContinueStmt& node) override; + void Visit(IfStmt& node) override; + void Visit(WhileStmt& node) override; + void Visit(ForStmt& node) override; + void Visit(UnsafeBlock& node) override; + + void Visit(Binary& node) override; + void Visit(Unary& node) override; + void Visit(Assign& node) override; + void Visit(Call& node) override; + void Visit(FieldAccess& node) override; + void Visit(IndexAccess& node) override; + void Visit(NamespaceRef& node) override; + void Visit(SafeCall& node) override; + void Visit(Elvis& node) override; + void Visit(CastAs& node) override; + void Visit(TypeTestIs& node) override; + void Visit(IdentRef& node) override; + void Visit(IntLit& node) override; + void Visit(FloatLit& node) override; + void Visit(StringLit& node) override; + void Visit(CharLit& node) override; + void Visit(BoolLit& node) override; + void Visit(NullLit& node) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_CONSTWALKVISITOR_HPP_ diff --git a/lib/parser/ast/visitors/LintVisitor.cpp b/lib/parser/ast/visitors/LintVisitor.cpp new file mode 100644 index 0000000..f7f5d82 --- /dev/null +++ b/lib/parser/ast/visitors/LintVisitor.cpp @@ -0,0 +1,327 @@ +#include "LintVisitor.hpp" + +#include + +#include "lib/parser/diagnostics/severity/Severity.hpp" + +#include "lib/parser/ast/nodes/class_members/CallDecl.hpp" +#include "lib/parser/ast/nodes/class_members/DestructorDecl.hpp" +#include "lib/parser/ast/nodes/class_members/FieldDecl.hpp" +#include "lib/parser/ast/nodes/class_members/MethodDecl.hpp" +#include "lib/parser/ast/nodes/class_members/StaticFieldDecl.hpp" + +#include "lib/parser/ast/nodes/decls/ClassDecl.hpp" +#include "lib/parser/ast/nodes/decls/FunctionDecl.hpp" +#include "lib/parser/ast/nodes/decls/GlobalVarDecl.hpp" +#include "lib/parser/ast/nodes/decls/Module.hpp" + +#include "lib/parser/ast/nodes/exprs/Assign.hpp" +#include "lib/parser/ast/nodes/exprs/Call.hpp" +#include "lib/parser/ast/nodes/exprs/SafeCall.hpp" + +#include "lib/parser/ast/nodes/exprs/literals/BoolLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/StringLit.hpp" + +#include "lib/parser/ast/nodes/stmts/Block.hpp" +#include "lib/parser/ast/nodes/stmts/BreakStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ContinueStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ExprStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ForStmt.hpp" +#include "lib/parser/ast/nodes/stmts/IfStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ReturnStmt.hpp" +#include "lib/parser/ast/nodes/stmts/UnsafeBlock.hpp" +#include "lib/parser/ast/nodes/stmts/WhileStmt.hpp" + +namespace ovum::compiler::parser { + +void LintVisitor::EnterBody() { + ++nesting_depth_; +} + +void LintVisitor::LeaveBody() { + if (nesting_depth_ > 0) { + --nesting_depth_; + } +} + +void LintVisitor::EnterLoop() { + ++loop_depth_; +} + +void LintVisitor::LeaveLoop() { + if (loop_depth_ > 0) { + --loop_depth_; + } +} + +void LintVisitor::CheckNestingDepth(const SourceSpan&) const { + if (opts_.warn_deep_nesting && nesting_depth_ > opts_.max_nesting) { + sink_.Warn("W0201", "deep nesting"); + } +} + +bool LintVisitor::IsPureExpr(Expr& expression) const { + if (dynamic_cast(&expression)) { + return false; + } + + if (dynamic_cast(&expression)) { + return false; + } + + if (dynamic_cast(&expression)) { + return false; + } + + return true; +} + +void LintVisitor::Visit(Module& node) { + if (opts_.warn_module_without_decls && node.MutableDecls().empty()) { + sink_.Warn("W0001", "module has no declarations"); + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(ClassDecl& node) { + if (opts_.warn_large_class && node.MutableMembers().size() > opts_.max_class_members) { + sink_.Warn("W0101", "class has too many members"); + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(FunctionDecl& node) { + if (opts_.warn_empty_bodies) { + if (auto* b = node.MutableBody()) { + if (b->Size() == 0) { + sink_.Warn("W0102", "function body is empty"); + } + } + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(MethodDecl& node) { + if (opts_.warn_empty_bodies) { + if (!node.IsPure()) { + if (auto* b = node.MutableBody()) { + if (b->Size() == 0) { + sink_.Warn("W0103", "method body is empty"); + } + } + } + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(CallDecl& node) { + if (opts_.warn_empty_bodies) { + if (auto* b = node.MutableBody()) { + if (b->Size() == 0) { + sink_.Warn("W0104", "call body is empty"); + } + } + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(DestructorDecl& node) { + if (opts_.warn_empty_bodies) { + if (auto* b = node.MutableBody()) { + if (b->Size() == 0) { + sink_.Warn("W0105", "destructor body is empty"); + } + } + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(Block& node) { + EnterBody(); + + if (opts_.warn_empty_blocks && node.GetStatements().empty()) { + sink_.Warn("W0202", "empty block"); + } + + CheckNestingDepth(); + + bool terminated = false; + if (opts_.warn_unreachable) { + for (const auto& stmt : node.GetStatements()) { + if (terminated) { + sink_.Warn("W0301", "unreachable statement"); + continue; + } + + if (dynamic_cast(stmt.get()) || dynamic_cast(stmt.get()) || + dynamic_cast(stmt.get())) { + terminated = true; + } + } + } + + if (opts_.max_block_len > 0 && node.GetStatements().size() > opts_.max_block_len) { + sink_.Warn("W0203", "block is too long"); + } + + for (auto& stmt : node.GetStatements()) { + stmt->Accept(*this); + } + + LeaveBody(); +} + +void LintVisitor::Visit(ExprStmt& node) { + if (opts_.warn_pure_expr_stmt) { + if (auto* e = node.MutableExpression()) { + if (IsPureExpr(*e)) { + sink_.Warn("W0401", "expression statement has no effect"); + } + } + } + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(ReturnStmt& node) { + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(BreakStmt& node) { + if (opts_.warn_break_continue_outside_loop && loop_depth_ == 0) { + sink_.Error("E0301", "break outside of loop"); + } + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(ContinueStmt& node) { + if (opts_.warn_break_continue_outside_loop && loop_depth_ == 0) { + sink_.Error("E0302", "continue outside of loop"); + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(IfStmt& node) { + EnterBody(); + + if (opts_.warn_if_without_branches && node.MutableBranches().empty() && !node.HasElse()) { + sink_.Warn("W0501", "if statement has no branches"); + } + + for (auto& br : node.MutableBranches()) { + if (auto* then_blk = br.MutableThen()) { + if (opts_.warn_empty_blocks && then_blk->GetStatements().empty()) { + sink_.Warn("W0502", "then-branch is empty"); + } + } + } + + if (opts_.warn_empty_else && node.HasElse()) { + if (auto* eb = node.MutableElseBlock()) { + if (eb->GetStatements().empty()) { + sink_.Warn("W0503", "else-branch is empty"); + } + } + } + + WalkVisitor::Visit(node); + + LeaveBody(); +} + +void LintVisitor::Visit(WhileStmt& node) { + EnterBody(); + + if (opts_.warn_missing_loop_cond_or_iterable && node.MutableCondition() == nullptr) { + sink_.Error("E0401", "while loop without condition"); + } + + if (opts_.warn_while_true) { + if (auto* cond = node.MutableCondition()) { + if (auto* bl = dynamic_cast(cond)) { + if (bl->Value()) { + sink_.Warn("W0601", "while(true) loop"); + } + } + } + } + + EnterLoop(); + WalkVisitor::Visit(node); + LeaveLoop(); + + LeaveBody(); +} + +void LintVisitor::Visit(ForStmt& node) { + EnterBody(); + + if (opts_.warn_missing_loop_cond_or_iterable && node.MutableIteratorExpr() == nullptr) { + sink_.Error("E0402", "for loop without iterable expression"); + } + + EnterLoop(); + WalkVisitor::Visit(node); + LeaveLoop(); + + LeaveBody(); +} + +void LintVisitor::Visit(UnsafeBlock& node) { + EnterBody(); + if (opts_.warn_empty_blocks) { + if (auto* b = node.MutableBody()) { + if (b->GetStatements().empty()) { + sink_.Warn("W0701", "empty unsafe block"); + } + } + } + + WalkVisitor::Visit(node); + LeaveBody(); +} + +void LintVisitor::Visit(GlobalVarDecl& node) { + if (opts_.warn_mutable_globals && node.IsVar()) { + sink_.Warn("W0801", "mutable global variable"); + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(FieldDecl& node) { + if (opts_.warn_public_fields && node.IsPublic()) { + sink_.Warn("W0802", "public field"); + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(StaticFieldDecl& node) { + if (opts_.warn_static_mutable_fields && node.IsVar()) { + sink_.Warn("W0803", "static mutable field"); + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(StringLit& node) { + if (opts_.warn_empty_string_literal && node.Value().empty()) { + sink_.Warn("W0901", "empty string literal"); + } + + WalkVisitor::Visit(node); +} + +void LintVisitor::Visit(BoolLit& node) { + (void) node; + WalkVisitor::Visit(node); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/visitors/LintVisitor.hpp b/lib/parser/ast/visitors/LintVisitor.hpp new file mode 100644 index 0000000..22cd71c --- /dev/null +++ b/lib/parser/ast/visitors/LintVisitor.hpp @@ -0,0 +1,80 @@ +#ifndef PARSER_LINTVISITOR_HPP_ +#define PARSER_LINTVISITOR_HPP_ + +#include +#include + +#include "WalkVisitor.hpp" + +#include "lib/parser/diagnostics/IDiagnosticSink.hpp" + +namespace ovum::compiler::parser { + +struct LintOptions { + std::size_t max_block_len = 200; + std::size_t max_nesting = 4; + std::size_t max_class_members = 64; + bool warn_empty_blocks = true; + bool warn_public_fields = true; + bool warn_mutable_globals = true; + bool warn_static_mutable_fields = true; + bool warn_unreachable = true; + bool warn_pure_expr_stmt = true; + bool warn_break_continue_outside_loop = true; + bool warn_empty_bodies = true; + bool warn_empty_else = true; + bool warn_missing_loop_cond_or_iterable = true; + bool warn_module_without_decls = true; + bool warn_empty_string_literal = true; + bool warn_deep_nesting = true; + bool warn_large_class = true; + bool warn_if_without_branches = true; + bool warn_while_true = true; +}; + +class LintVisitor : public WalkVisitor { +public: + explicit LintVisitor(IDiagnosticSink& sink, LintOptions options = {}) : sink_(sink), opts_(options) { + } + + void Visit(Module& node) override; + void Visit(ClassDecl& node) override; + void Visit(FunctionDecl& node) override; + void Visit(MethodDecl& node) override; + void Visit(CallDecl& node) override; + void Visit(DestructorDecl& node) override; + + void Visit(Block& node) override; + void Visit(ExprStmt& node) override; + void Visit(ReturnStmt& node) override; + void Visit(BreakStmt& node) override; + void Visit(ContinueStmt& node) override; + void Visit(IfStmt& node) override; + void Visit(WhileStmt& node) override; + void Visit(ForStmt& node) override; + void Visit(UnsafeBlock& node) override; + + void Visit(GlobalVarDecl& node) override; + void Visit(FieldDecl& node) override; + void Visit(StaticFieldDecl& node) override; + + void Visit(StringLit& node) override; + void Visit(BoolLit& node) override; + +private: + bool IsPureExpr(Expr& expression) const; + void EnterBody(); + void LeaveBody(); + void EnterLoop(); + void LeaveLoop(); + void CheckNestingDepth(const SourceSpan& where_hint = {}) const; + + IDiagnosticSink& sink_; + LintOptions opts_; + std::size_t loop_depth_ = 0; + std::size_t nesting_depth_ = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_LINTVISITOR_HPP_ diff --git a/lib/parser/ast/visitors/PrintVisitor.cpp b/lib/parser/ast/visitors/PrintVisitor.cpp new file mode 100644 index 0000000..9f47964 --- /dev/null +++ b/lib/parser/ast/visitors/PrintVisitor.cpp @@ -0,0 +1,421 @@ +#include "PrintVisitor.hpp" + +#include "lib/parser/ast/nodes/class_members/CallDecl.hpp" +#include "lib/parser/ast/nodes/class_members/DestructorDecl.hpp" +#include "lib/parser/ast/nodes/class_members/FieldDecl.hpp" +#include "lib/parser/ast/nodes/class_members/MethodDecl.hpp" +#include "lib/parser/ast/nodes/class_members/StaticFieldDecl.hpp" + +#include "lib/parser/ast/nodes/decls/ClassDecl.hpp" +#include "lib/parser/ast/nodes/decls/FunctionDecl.hpp" +#include "lib/parser/ast/nodes/decls/GlobalVarDecl.hpp" +#include "lib/parser/ast/nodes/decls/InterfaceDecl.hpp" +#include "lib/parser/ast/nodes/decls/InterfaceMethod.hpp" +#include "lib/parser/ast/nodes/decls/Module.hpp" +#include "lib/parser/ast/nodes/decls/TypeAliasDecl.hpp" + +#include "lib/parser/ast/nodes/stmts/Block.hpp" + +namespace ovum::compiler::parser { + +PrintVisitor::PrintVisitor(std::ostream& output) : out_(&output) { +} + +PrintVisitor::PrintVisitor() : out_(&buffer_), use_buffer_(true) { +} + +std::string PrintVisitor::Str() const { + return buffer_.str(); +} + +void PrintVisitor::WriteIndent() { + for (int i = 0; i < indent_; ++i) { + *out_ << " "; + } +} + +void PrintVisitor::WriteLine(const std::string& text) { + WriteIndent(); + *out_ << text << '\n'; +} + +void PrintVisitor::Open(const std::string& header) { + WriteLine(header + " {"); + ++indent_; +} + +void PrintVisitor::Close() { + --indent_; + WriteLine("}"); +} + +void PrintVisitor::Visit(Module& node) { + Open("Module name=\"" + node.Name() + "\""); + for (auto& declaration : node.MutableDecls()) { + declaration->Accept(*this); + } + Close(); +} + +void PrintVisitor::Visit(FunctionDecl& node) { + Open(std::string("FunctionDecl name=\"") + node.Name() + "\"" + (node.IsPure() ? " pure" : "")); + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } + Close(); +} + +void PrintVisitor::Visit(ClassDecl& node) { + Open(std::string("ClassDecl name=\"") + node.Name() + "\""); + for (auto& member : node.MutableMembers()) { + member->Accept(*this); + } + Close(); +} + +void PrintVisitor::Visit(InterfaceMethod& node) { + WriteLine(std::string("InterfaceMethod name=\"") + node.Name() + "\""); +} + +void PrintVisitor::Visit(InterfaceDecl& node) { + Open(std::string("InterfaceDecl name=\"") + node.Name() + "\""); + for (auto& method_ptr : node.MutableMembers()) { + method_ptr->Accept(*this); + } + Close(); +} + +void PrintVisitor::Visit(TypeAliasDecl& node) { + WriteLine(std::string("TypeAliasDecl name=\"") + node.Name() + "\""); +} + +void PrintVisitor::Visit(GlobalVarDecl& node) { + Open(std::string("GlobalVarDecl ") + (node.IsVar() ? "var" : "val") + " name=\"" + node.Name() + "\""); + if (auto* init_expr = node.MutableInit()) { + init_expr->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(FieldDecl& node) { + Open(std::string("FieldDecl ") + (node.IsVar() ? "var" : "val") + " name=\"" + node.Name() + "\"" + + (node.IsPublic() ? " public" : "")); + if (auto* init_expr = node.MutableInit()) { + init_expr->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(StaticFieldDecl& node) { + Open(std::string("StaticFieldDecl ") + (node.IsVar() ? "var" : "val") + " name=\"" + node.Name() + "\"" + + (node.IsPublic() ? " public" : "")); + if (auto* init_expr = node.MutableInit()) { + init_expr->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(MethodDecl& node) { + std::string flags; + if (node.IsPublic()) { + flags += " public"; + } + + if (node.IsStatic()) { + flags += " static"; + } + + if (node.IsOverride()) { + flags += " override"; + } + + if (node.IsPure()) { + flags += " pure"; + } + + Open("MethodDecl name=\"" + node.Name() + "\"" + flags); + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(CallDecl& node) { + Open(std::string("CallDecl") + (node.IsPublic() ? " public" : "")); + + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(DestructorDecl& node) { + Open(std::string("DestructorDecl") + (node.IsPublic() ? " public" : "")); + + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(Block& node) { + Open("Block"); + + for (auto& statement : node.GetStatements()) { + statement->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(VarDeclStmt& node) { + Open(std::string("VarDeclStmt ") + (node.IsVar() ? "var" : "val") + " name=\"" + node.Name() + "\""); + + if (auto* init_expr = node.MutableInit()) { + init_expr->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(ExprStmt& node) { + Open("ExprStmt"); + + if (auto* expression = node.MutableExpression()) { + expression->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(ReturnStmt& node) { + if (!node.HasValue()) { + WriteLine("ReturnStmt"); + return; + } + + Open("ReturnStmt"); + if (auto* value_expr = node.MutableValue()) { + value_expr->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(BreakStmt& node) { + WriteLine("BreakStmt"); + (void) node; +} + +void PrintVisitor::Visit(ContinueStmt& node) { + WriteLine("ContinueStmt"); + (void) node; +} + +void PrintVisitor::Visit(IfStmt& node) { + Open("IfStmt"); + for (auto& branch_value : node.MutableBranches()) { + Open("Branch"); + + if (auto* cond_expr = branch_value.MutableCondition()) { + Open("Condition"); + cond_expr->Accept(*this); + Close(); + } + + if (auto* then_block = branch_value.MutableThen()) { + Open("Then"); + then_block->Accept(*this); + Close(); + } + + Close(); + } + + if (auto* else_block = node.MutableElseBlock()) { + Open("Else"); + else_block->Accept(*this); + Close(); + } + + Close(); +} + +void PrintVisitor::Visit(WhileStmt& node) { + Open("WhileStmt"); + + if (auto* cond_expr = node.MutableCondition()) { + Open("Condition"); + cond_expr->Accept(*this); + Close(); + } + + if (auto* body_block = node.MutableBody()) { + Open("Body"); + body_block->Accept(*this); + Close(); + } + + Close(); +} + +void PrintVisitor::Visit(ForStmt& node) { + Open(std::string("ForStmt iterator=\"") + node.IteratorName() + "\""); + + if (auto* iter_expr = node.MutableIteratorExpr()) { + Open("Iterable"); + iter_expr->Accept(*this); + Close(); + } + + if (auto* body_block = node.MutableBody()) { + Open("Body"); + body_block->Accept(*this); + Close(); + } + + Close(); +} + +void PrintVisitor::Visit(UnsafeBlock& node) { + Open("UnsafeBlock"); + + if (auto* body_block = node.MutableBody()) { + body_block->Accept(*this); + } + + Close(); +} + +void PrintVisitor::Visit(Binary& node) { + Open(std::string("Binary op=\"") + std::string(node.Op().Name()) + "\""); + node.MutableLhs().Accept(*this); + node.MutableRhs().Accept(*this); + Close(); +} + +void PrintVisitor::Visit(Unary& node) { + Open(std::string("Unary op=\"") + std::string(node.Op().Name()) + "\""); + node.MutableOperand().Accept(*this); + Close(); +} + +void PrintVisitor::Visit(Assign& node) { + Open(std::string("Assign kind=\"") + std::string(node.Kind().Name()) + "\""); + Open("Target"); + node.MutableTarget().Accept(*this); + Close(); + Open("Value"); + node.MutableValue().Accept(*this); + Close(); + Close(); +} + +void PrintVisitor::Visit(Call& node) { + Open("Call"); + Open("Callee"); + node.MutableCallee().Accept(*this); + Close(); + Open("Args"); + + for (auto& argument : node.MutableArgs()) { + argument->Accept(*this); + } + + Close(); + Close(); +} + +void PrintVisitor::Visit(FieldAccess& node) { + Open(std::string("FieldAccess name=\"") + node.Name() + "\""); + node.MutableObject().Accept(*this); + Close(); +} + +void PrintVisitor::Visit(IndexAccess& node) { + Open("IndexAccess"); + Open("Object"); + node.MutableObject().Accept(*this); + Close(); + Open("Index"); + node.MutableIndexExpr().Accept(*this); + Close(); + Close(); +} + +void PrintVisitor::Visit(NamespaceRef& node) { + Open(std::string("NamespaceRef name=\"") + node.Name() + "\""); + node.MutableNamespaceExpr().Accept(*this); + Close(); +} + +void PrintVisitor::Visit(SafeCall& node) { + Open(std::string("SafeCall method=\"") + node.Method() + "\""); + Open("Object"); + node.MutableObject().Accept(*this); + Close(); + Open("Args"); + + for (auto& argument : node.MutableArgs()) { + argument->Accept(*this); + } + + Close(); + Close(); +} + +void PrintVisitor::Visit(Elvis& node) { + Open("Elvis"); + node.MutableLhs().Accept(*this); + node.MutableRhs().Accept(*this); + Close(); +} + +void PrintVisitor::Visit(CastAs& node) { + Open("CastAs"); + node.MutableExpression().Accept(*this); + Close(); +} + +void PrintVisitor::Visit(TypeTestIs& node) { + Open("TypeTestIs"); + node.MutableExpression().Accept(*this); + Close(); +} + +void PrintVisitor::Visit(IdentRef& node) { + WriteLine(std::string("IdentRef name=\"") + node.Name() + "\""); +} + +void PrintVisitor::Visit(IntLit& node) { + WriteLine("IntLit value=" + std::to_string(node.Value())); +} + +void PrintVisitor::Visit(FloatLit& node) { + WriteLine("FloatLit value=" + std::to_string(node.Value())); +} + +void PrintVisitor::Visit(StringLit& node) { + WriteLine(std::string("StringLit value=\"") + node.Value() + "\""); +} + +void PrintVisitor::Visit(CharLit& node) { + std::string printable(1, node.Value()); + WriteLine(std::string("CharLit value='") + printable + "'"); +} + +void PrintVisitor::Visit(BoolLit& node) { + WriteLine(std::string("BoolLit value=") + (node.Value() ? "true" : "false")); +} + +void PrintVisitor::Visit(NullLit& node) { + WriteLine("NullLit"); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/visitors/PrintVisitor.hpp b/lib/parser/ast/visitors/PrintVisitor.hpp new file mode 100644 index 0000000..fef2fce --- /dev/null +++ b/lib/parser/ast/visitors/PrintVisitor.hpp @@ -0,0 +1,78 @@ +#ifndef PARSER_PRINTVISITOR_HPP_ +#define PARSER_PRINTVISITOR_HPP_ + +#include +#include +#include + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +class PrintVisitor : public AstVisitor { +public: + explicit PrintVisitor(std::ostream& output); + PrintVisitor(); + + ~PrintVisitor() override = default; + + std::string Str() const; + + void Visit(Module& node) override; + void Visit(FunctionDecl& node) override; + void Visit(ClassDecl& node) override; + void Visit(InterfaceMethod& node) override; + void Visit(InterfaceDecl& node) override; + void Visit(TypeAliasDecl& node) override; + void Visit(GlobalVarDecl& node) override; + void Visit(FieldDecl& node) override; + void Visit(StaticFieldDecl& node) override; + void Visit(MethodDecl& node) override; + void Visit(CallDecl& node) override; + void Visit(DestructorDecl& node) override; + + void Visit(Block& node) override; + void Visit(VarDeclStmt& node) override; + void Visit(ExprStmt& node) override; + void Visit(ReturnStmt& node) override; + void Visit(BreakStmt& node) override; + void Visit(ContinueStmt& node) override; + void Visit(IfStmt& node) override; + void Visit(WhileStmt& node) override; + void Visit(ForStmt& node) override; + void Visit(UnsafeBlock& node) override; + + void Visit(Binary& node) override; + void Visit(Unary& node) override; + void Visit(Assign& node) override; + void Visit(Call& node) override; + void Visit(FieldAccess& node) override; + void Visit(IndexAccess& node) override; + void Visit(NamespaceRef& node) override; + void Visit(SafeCall& node) override; + void Visit(Elvis& node) override; + void Visit(CastAs& node) override; + void Visit(TypeTestIs& node) override; + void Visit(IdentRef& node) override; + void Visit(IntLit& node) override; + void Visit(FloatLit& node) override; + void Visit(StringLit& node) override; + void Visit(CharLit& node) override; + void Visit(BoolLit& node) override; + void Visit(NullLit& node) override; + +private: + void WriteIndent(); + void WriteLine(const std::string& text); + void Open(const std::string& header); + void Close(); + + std::ostream* out_ = nullptr; + std::ostringstream buffer_; + int indent_ = 0; + bool use_buffer_ = false; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_PRINTVISITOR_HPP_ diff --git a/lib/parser/ast/visitors/StructuralValidator.cpp b/lib/parser/ast/visitors/StructuralValidator.cpp new file mode 100644 index 0000000..0a9b5b4 --- /dev/null +++ b/lib/parser/ast/visitors/StructuralValidator.cpp @@ -0,0 +1,118 @@ +#include "StructuralValidator.hpp" + +#include "lib/parser/diagnostics/severity/Severity.hpp" + +#include "lib/parser/ast/nodes/class_members/CallDecl.hpp" +#include "lib/parser/ast/nodes/class_members/DestructorDecl.hpp" +#include "lib/parser/ast/nodes/class_members/MethodDecl.hpp" + +#include "lib/parser/ast/nodes/decls/ClassDecl.hpp" +#include "lib/parser/ast/nodes/decls/FunctionDecl.hpp" +#include "lib/parser/ast/nodes/decls/Module.hpp" + +#include "lib/parser/ast/nodes/exprs/Binary.hpp" +#include "lib/parser/ast/nodes/exprs/Call.hpp" +#include "lib/parser/ast/nodes/exprs/FieldAccess.hpp" +#include "lib/parser/ast/nodes/exprs/IndexAccess.hpp" +#include "lib/parser/ast/nodes/exprs/NamespaceRef.hpp" +#include "lib/parser/ast/nodes/exprs/SafeCall.hpp" +#include "lib/parser/ast/nodes/exprs/Unary.hpp" + +namespace ovum::compiler::parser { + +void StructuralValidator::Visit(Module& node) { + if (node.Name().empty()) { + sink_.Error("E0001", "module name must not be empty"); + } + + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(FunctionDecl& node) { + if (!node.IsPure() && node.MutableBody() == nullptr) { + sink_.Error("E1001", "function must have a body"); + } + + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(ClassDecl& node) { + if (node.Name().empty()) { + sink_.Error("E1002", "class name must not be empty"); + } + + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(CallDecl& node) { + if (node.MutableBody() == nullptr) { + sink_.Error("E1101", "call declaration must have a body"); + } + + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(MethodDecl& node) { + if (!node.IsPure() && node.MutableBody() == nullptr) { + sink_.Error("E1201", "method must have a body"); + } + + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(DestructorDecl& node) { + if (node.MutableBody() == nullptr) { + sink_.Error("E1301", "destructor must have a body"); + } + + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(Call& node) { + if (&node.MutableCallee() == nullptr) { + sink_.Error("E2001", "call must have callee"); + } + + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(Binary& node) { + (void) node.MutableLhs(); + (void) node.MutableRhs(); + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(Unary& node) { + (void) node.MutableOperand(); + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(FieldAccess& node) { + (void) node.MutableObject(); + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(IndexAccess& node) { + (void) node.MutableObject(); + (void) node.MutableIndexExpr(); + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(NamespaceRef& node) { + if (node.Name().empty()) { + sink_.Error("E2101", "namespace reference must have name"); + } + + WalkVisitor::Visit(node); +} + +void StructuralValidator::Visit(SafeCall& node) { + if (node.Method().empty()) { + sink_.Error("E2201", "safecall must have method name"); + } + + (void) node.MutableObject(); + WalkVisitor::Visit(node); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/visitors/StructuralValidator.hpp b/lib/parser/ast/visitors/StructuralValidator.hpp new file mode 100644 index 0000000..7079927 --- /dev/null +++ b/lib/parser/ast/visitors/StructuralValidator.hpp @@ -0,0 +1,35 @@ +#ifndef PARSER_STRUCTURALVALIDATOR_HPP_ +#define PARSER_STRUCTURALVALIDATOR_HPP_ + +#include "WalkVisitor.hpp" +#include "lib/parser/diagnostics/IDiagnosticSink.hpp" + +namespace ovum::compiler::parser { + +class StructuralValidator : public WalkVisitor { +public: + explicit StructuralValidator(IDiagnosticSink& sink) : sink_(sink) { + } + + void Visit(Module& node) override; + void Visit(FunctionDecl& node) override; + void Visit(ClassDecl& node) override; + void Visit(CallDecl& node) override; + void Visit(MethodDecl& node) override; + void Visit(DestructorDecl& node) override; + + void Visit(Call& node) override; + void Visit(Binary& node) override; + void Visit(Unary& node) override; + void Visit(FieldAccess& node) override; + void Visit(IndexAccess& node) override; + void Visit(NamespaceRef& node) override; + void Visit(SafeCall& node) override; + +private: + IDiagnosticSink& sink_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STRUCTURALVALIDATOR_HPP_ diff --git a/lib/parser/ast/visitors/WalkVisitor.cpp b/lib/parser/ast/visitors/WalkVisitor.cpp new file mode 100644 index 0000000..f9d4216 --- /dev/null +++ b/lib/parser/ast/visitors/WalkVisitor.cpp @@ -0,0 +1,274 @@ +#include "WalkVisitor.hpp" + +#include "lib/parser/ast/nodes/decls/ClassDecl.hpp" +#include "lib/parser/ast/nodes/decls/FunctionDecl.hpp" +#include "lib/parser/ast/nodes/decls/GlobalVarDecl.hpp" +#include "lib/parser/ast/nodes/decls/InterfaceDecl.hpp" +#include "lib/parser/ast/nodes/decls/InterfaceMethod.hpp" +#include "lib/parser/ast/nodes/decls/Module.hpp" +#include "lib/parser/ast/nodes/decls/TypeAliasDecl.hpp" + +#include "lib/parser/ast/nodes/class_members/CallDecl.hpp" +#include "lib/parser/ast/nodes/class_members/DestructorDecl.hpp" +#include "lib/parser/ast/nodes/class_members/FieldDecl.hpp" +#include "lib/parser/ast/nodes/class_members/MethodDecl.hpp" +#include "lib/parser/ast/nodes/class_members/StaticFieldDecl.hpp" + +#include "lib/parser/ast/nodes/exprs/Assign.hpp" +#include "lib/parser/ast/nodes/exprs/Binary.hpp" +#include "lib/parser/ast/nodes/exprs/Call.hpp" +#include "lib/parser/ast/nodes/exprs/CastAs.hpp" +#include "lib/parser/ast/nodes/exprs/Elvis.hpp" +#include "lib/parser/ast/nodes/exprs/FieldAccess.hpp" +#include "lib/parser/ast/nodes/exprs/IdentRef.hpp" +#include "lib/parser/ast/nodes/exprs/IndexAccess.hpp" +#include "lib/parser/ast/nodes/exprs/NamespaceRef.hpp" +#include "lib/parser/ast/nodes/exprs/SafeCall.hpp" +#include "lib/parser/ast/nodes/exprs/TypeTestIs.hpp" +#include "lib/parser/ast/nodes/exprs/Unary.hpp" + +#include "lib/parser/ast/nodes/exprs/literals/BoolLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/CharLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/FloatLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/IntLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/NullLit.hpp" +#include "lib/parser/ast/nodes/exprs/literals/StringLit.hpp" + +#include "lib/parser/ast/nodes/stmts/Block.hpp" +#include "lib/parser/ast/nodes/stmts/BreakStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ContinueStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ExprStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ForStmt.hpp" +#include "lib/parser/ast/nodes/stmts/IfStmt.hpp" +#include "lib/parser/ast/nodes/stmts/ReturnStmt.hpp" +#include "lib/parser/ast/nodes/stmts/UnsafeBlock.hpp" +#include "lib/parser/ast/nodes/stmts/VarDeclStmt.hpp" +#include "lib/parser/ast/nodes/stmts/WhileStmt.hpp" + +namespace ovum::compiler::parser { + +void WalkVisitor::Visit(Module& node) { + for (auto& decl_ptr : node.MutableDecls()) { + decl_ptr->Accept(*this); + } +} + +void WalkVisitor::Visit(FunctionDecl& node) { + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } +} + +void WalkVisitor::Visit(ClassDecl& node) { + for (auto& member : node.MutableMembers()) { + member->Accept(*this); + } +} + +void WalkVisitor::Visit(InterfaceMethod& node) { + (void) node; +} + +void WalkVisitor::Visit(InterfaceDecl& node) { + for (auto& m : node.MutableMembers()) { + m->Accept(*this); + } +} + +void WalkVisitor::Visit(TypeAliasDecl& node) { + (void) node; +} + +void WalkVisitor::Visit(GlobalVarDecl& node) { + if (auto* init = node.MutableInit()) { + init->Accept(*this); + } +} + +void WalkVisitor::Visit(FieldDecl& node) { + if (auto* init = node.MutableInit()) { + init->Accept(*this); + } +} + +void WalkVisitor::Visit(StaticFieldDecl& node) { + if (auto* init = node.MutableInit()) { + init->Accept(*this); + } +} + +void WalkVisitor::Visit(MethodDecl& node) { + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } +} + +void WalkVisitor::Visit(CallDecl& node) { + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } +} + +void WalkVisitor::Visit(DestructorDecl& node) { + if (auto* body = node.MutableBody()) { + body->Accept(*this); + } +} + +void WalkVisitor::Visit(Block& node) { + for (auto& stmt : node.GetStatements()) { + stmt->Accept(*this); + } +} + +void WalkVisitor::Visit(VarDeclStmt& node) { + if (auto* init = node.MutableInit()) { + init->Accept(*this); + } +} + +void WalkVisitor::Visit(ExprStmt& node) { + if (auto* e = node.MutableExpression()) { + e->Accept(*this); + } +} + +void WalkVisitor::Visit(ReturnStmt& node) { + if (auto* v = node.MutableValue()) { + v->Accept(*this); + } +} + +void WalkVisitor::Visit(BreakStmt& node) { + (void) node; +} + +void WalkVisitor::Visit(ContinueStmt& node) { + (void) node; +} + +void WalkVisitor::Visit(IfStmt& node) { + for (auto& br : node.MutableBranches()) { + if (auto* c = br.MutableCondition()) { + c->Accept(*this); + } + + if (auto* t = br.MutableThen()) { + t->Accept(*this); + } + } + + if (auto* eb = node.MutableElseBlock()) { + eb->Accept(*this); + } +} + +void WalkVisitor::Visit(WhileStmt& node) { + if (auto* c = node.MutableCondition()) { + c->Accept(*this); + } + + if (auto* b = node.MutableBody()) { + b->Accept(*this); + } +} + +void WalkVisitor::Visit(ForStmt& node) { + if (auto* it = node.MutableIteratorExpr()) { + it->Accept(*this); + } + + if (auto* b = node.MutableBody()) { + b->Accept(*this); + } +} + +void WalkVisitor::Visit(UnsafeBlock& node) { + if (auto* b = node.MutableBody()) { + b->Accept(*this); + } +} + +void WalkVisitor::Visit(Binary& node) { + node.MutableLhs().Accept(*this); + node.MutableRhs().Accept(*this); +} + +void WalkVisitor::Visit(Unary& node) { + node.MutableOperand().Accept(*this); +} + +void WalkVisitor::Visit(Assign& node) { + node.MutableTarget().Accept(*this); + node.MutableValue().Accept(*this); +} + +void WalkVisitor::Visit(Call& node) { + node.MutableCallee().Accept(*this); + for (auto& a : node.MutableArgs()) { + a->Accept(*this); + } +} + +void WalkVisitor::Visit(FieldAccess& node) { + node.MutableObject().Accept(*this); +} + +void WalkVisitor::Visit(IndexAccess& node) { + node.MutableObject().Accept(*this); + node.MutableIndexExpr().Accept(*this); +} + +void WalkVisitor::Visit(NamespaceRef& node) { + node.MutableNamespaceExpr().Accept(*this); +} + +void WalkVisitor::Visit(SafeCall& node) { + node.MutableObject().Accept(*this); + for (auto& a : node.MutableArgs()) { + a->Accept(*this); + } +} + +void WalkVisitor::Visit(Elvis& node) { + node.MutableLhs().Accept(*this); + node.MutableRhs().Accept(*this); +} + +void WalkVisitor::Visit(CastAs& node) { + node.MutableExpression().Accept(*this); +} + +void WalkVisitor::Visit(TypeTestIs& node) { + node.MutableExpression().Accept(*this); +} + +void WalkVisitor::Visit(IdentRef& node) { + (void) node; +} + +void WalkVisitor::Visit(IntLit& node) { + (void) node; +} + +void WalkVisitor::Visit(FloatLit& node) { + (void) node; +} + +void WalkVisitor::Visit(StringLit& node) { + (void) node; +} + +void WalkVisitor::Visit(CharLit& node) { + (void) node; +} + +void WalkVisitor::Visit(BoolLit& node) { + (void) node; +} + +void WalkVisitor::Visit(NullLit& node) { + (void) node; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/ast/visitors/WalkVisitor.hpp b/lib/parser/ast/visitors/WalkVisitor.hpp new file mode 100644 index 0000000..448217a --- /dev/null +++ b/lib/parser/ast/visitors/WalkVisitor.hpp @@ -0,0 +1,58 @@ +#ifndef PARSER_WALKVISITOR_HPP_ +#define PARSER_WALKVISITOR_HPP_ + +#include "lib/parser/ast/AstVisitor.hpp" + +namespace ovum::compiler::parser { + +class WalkVisitor : public AstVisitor { +public: + ~WalkVisitor() override = default; + + void Visit(Module& node) override; + void Visit(FunctionDecl& node) override; + void Visit(ClassDecl& node) override; + void Visit(InterfaceMethod& node) override; + void Visit(InterfaceDecl& node) override; + void Visit(TypeAliasDecl& node) override; + void Visit(GlobalVarDecl& node) override; + void Visit(FieldDecl& node) override; + void Visit(StaticFieldDecl& node) override; + void Visit(MethodDecl& node) override; + void Visit(CallDecl& node) override; + void Visit(DestructorDecl& node) override; + + void Visit(Block& node) override; + void Visit(VarDeclStmt& node) override; + void Visit(ExprStmt& node) override; + void Visit(ReturnStmt& node) override; + void Visit(BreakStmt& node) override; + void Visit(ContinueStmt& node) override; + void Visit(IfStmt& node) override; + void Visit(WhileStmt& node) override; + void Visit(ForStmt& node) override; + void Visit(UnsafeBlock& node) override; + + void Visit(Binary& node) override; + void Visit(Unary& node) override; + void Visit(Assign& node) override; + void Visit(Call& node) override; + void Visit(FieldAccess& node) override; + void Visit(IndexAccess& node) override; + void Visit(NamespaceRef& node) override; + void Visit(SafeCall& node) override; + void Visit(Elvis& node) override; + void Visit(CastAs& node) override; + void Visit(TypeTestIs& node) override; + void Visit(IdentRef& node) override; + void Visit(IntLit& node) override; + void Visit(FloatLit& node) override; + void Visit(StringLit& node) override; + void Visit(CharLit& node) override; + void Visit(BoolLit& node) override; + void Visit(NullLit& node) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_WALKVISITOR_HPP_ diff --git a/lib/parser/context/ContextParser.cpp b/lib/parser/context/ContextParser.cpp new file mode 100644 index 0000000..b4f763f --- /dev/null +++ b/lib/parser/context/ContextParser.cpp @@ -0,0 +1,87 @@ +#include "ContextParser.hpp" + +#include + +namespace ovum::compiler::parser { + +std::vector& ContextParser::StateStack() { + return state_stack_; +} + +std::vector& ContextParser::NodeStack() { + return node_stack_; +} + +void ContextParser::SetDiagnostics(IDiagnosticSink* diagnostics) { + diags_ = diagnostics; +} + +IDiagnosticSink* ContextParser::Diags() const { + return diags_; +} + +void ContextParser::SetExpr(IExpressionParser* parser) { + expr_ = parser; +} + +IExpressionParser* ContextParser::Expr() const { + return expr_; +} + +void ContextParser::SetTypeParser(ITypeParser* parser) { + typep_ = parser; +} + +ITypeParser* ContextParser::TypeParser() const { + return typep_; +} + +void ContextParser::PushState(const IState& state) { + state_stack_.push_back(&state); +} + +void ContextParser::PopState() { + if (!state_stack_.empty()) { + state_stack_.pop_back(); + } +} + +const IState* ContextParser::CurrentState() const { + if (state_stack_.empty()) { + return nullptr; + } + + return state_stack_.back(); +} + +void ContextParser::PushNode(std::unique_ptr node) { + node_stack_.emplace_back(std::move(node)); +} + +std::unique_ptr ContextParser::PopNode() { + if (node_stack_.empty()) { + return nullptr; + } + + auto out = node_stack_.back().ReleaseNode(); + node_stack_.pop_back(); + return out; +} + +bool ContextParser::HasStates() const noexcept { + return !state_stack_.empty(); +} + +bool ContextParser::HasNodes() const noexcept { + return !node_stack_.empty(); +} + +void ContextParser::Clear() { + state_stack_.clear(); + node_stack_.clear(); + diags_ = nullptr; + expr_ = nullptr; + typep_ = nullptr; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/context/ContextParser.hpp b/lib/parser/context/ContextParser.hpp new file mode 100644 index 0000000..43458ac --- /dev/null +++ b/lib/parser/context/ContextParser.hpp @@ -0,0 +1,65 @@ +#ifndef PARSER_CONTEXTPARSER_HPP_ +#define PARSER_CONTEXTPARSER_HPP_ + +#include +#include +#include + +#include "NodeEntry.hpp" +#include "lib/parser/diagnostics/IDiagnosticSink.hpp" +#include "lib/parser/states/base/IState.hpp" + +namespace ovum::compiler::parser { + +class AstNode; +class IExpressionParser; +class ITypeParser; + +template +concept AstNodeDerived = std::is_base_of_v; + +class ContextParser { +public: + std::vector& StateStack(); + std::vector& NodeStack(); + + void SetDiagnostics(IDiagnosticSink* diagnostics); + IDiagnosticSink* Diags() const; + + void SetExpr(IExpressionParser* parser); + IExpressionParser* Expr() const; + + void SetTypeParser(ITypeParser* parser); + ITypeParser* TypeParser() const; + + void PushState(const IState& state); + void PopState(); + const IState* CurrentState() const; + + template + T* TopNodeAs() { + if (node_stack_.empty()) { + return nullptr; + } + + return dynamic_cast(node_stack_.back().MutableNode()); + } + + void PushNode(std::unique_ptr node); + std::unique_ptr PopNode(); + + bool HasStates() const noexcept; + bool HasNodes() const noexcept; + void Clear(); + +private: + std::vector state_stack_; + std::vector node_stack_; + IDiagnosticSink* diags_ = nullptr; + IExpressionParser* expr_ = nullptr; + ITypeParser* typep_ = nullptr; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_CONTEXTPARSER_HPP_ diff --git a/lib/parser/context/NodeEntry.cpp b/lib/parser/context/NodeEntry.cpp new file mode 100644 index 0000000..659e4d7 --- /dev/null +++ b/lib/parser/context/NodeEntry.cpp @@ -0,0 +1,26 @@ +#include "NodeEntry.hpp" + +#include + +namespace ovum::compiler::parser { + +NodeEntry::NodeEntry(std::unique_ptr node) : node_(std::move(node)) { +} + +const AstNode* NodeEntry::GetNode() const noexcept { + return node_.get(); +} + +AstNode* NodeEntry::MutableNode() noexcept { + return node_.get(); +} + +void NodeEntry::SetNode(std::unique_ptr node) { + node_ = std::move(node); +} + +std::unique_ptr NodeEntry::ReleaseNode() { + return std::move(node_); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/context/NodeEntry.hpp b/lib/parser/context/NodeEntry.hpp new file mode 100644 index 0000000..0261c30 --- /dev/null +++ b/lib/parser/context/NodeEntry.hpp @@ -0,0 +1,26 @@ +#ifndef PARSER_NODEENTRY_HPP_ +#define PARSER_NODEENTRY_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/AstNode.hpp" + +namespace ovum::compiler::parser { + +class NodeEntry { +public: + NodeEntry() = default; + explicit NodeEntry(std::unique_ptr node); + + const AstNode* GetNode() const noexcept; + AstNode* MutableNode() noexcept; + void SetNode(std::unique_ptr node); + std::unique_ptr ReleaseNode(); + +private: + std::unique_ptr node_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_NODEENTRY_HPP_ diff --git a/lib/parser/diagnostics/Diagnostic.cpp b/lib/parser/diagnostics/Diagnostic.cpp new file mode 100644 index 0000000..21bdf3f --- /dev/null +++ b/lib/parser/diagnostics/Diagnostic.cpp @@ -0,0 +1,129 @@ +#include "Diagnostic.hpp" + +#include + +namespace ovum::compiler::parser { + +Diagnostic::Diagnostic() = default; + +Diagnostic::Diagnostic(std::shared_ptr sev, std::string code, std::string message) : + severity_(std::move(sev)), code_(std::move(code)), message_(std::move(message)) { +} + +Diagnostic::Diagnostic(const Diagnostic& other) = default; + +Diagnostic::Diagnostic(Diagnostic&& other) noexcept : + severity_(std::move(other.severity_)), code_(std::move(other.code_)), message_(std::move(other.message_)), + category_(std::move(other.category_)), where_(std::move(other.where_)), notes_(std::move(other.notes_)), + fixes_(std::move(other.fixes_)), is_fatal_(other.is_fatal_), is_suppressed_(other.is_suppressed_) { +} + +Diagnostic& Diagnostic::operator=(const Diagnostic& other) { + if (this == &other) { + return *this; + } + + severity_ = other.severity_; + code_ = other.code_; + message_ = other.message_; + category_ = other.category_; + where_ = other.where_; + notes_ = other.notes_; + fixes_ = other.fixes_; + is_fatal_ = other.is_fatal_; + is_suppressed_ = other.is_suppressed_; + return *this; +} + +Diagnostic& Diagnostic::operator=(Diagnostic&& other) noexcept { + if (this == &other) { + return *this; + } + + severity_ = std::move(other.severity_); + code_ = std::move(other.code_); + message_ = std::move(other.message_); + category_ = std::move(other.category_); + where_ = std::move(other.where_); + notes_ = std::move(other.notes_); + fixes_ = std::move(other.fixes_); + is_fatal_ = other.is_fatal_; + is_suppressed_ = other.is_suppressed_; + return *this; +} + +Diagnostic::~Diagnostic() = default; + +void Diagnostic::SetSeverity(std::shared_ptr sev) { + severity_ = std::move(sev); +} +const std::shared_ptr& Diagnostic::GetSeverity() const noexcept { + return severity_; +} + +void Diagnostic::SetCode(std::string c) { + code_ = std::move(c); +} +const std::string& Diagnostic::GetCode() const noexcept { + return code_; +} + +void Diagnostic::SetMessage(std::string m) { + message_ = std::move(m); +} +const std::string& Diagnostic::GetMessage() const noexcept { + return message_; +} + +void Diagnostic::SetCategory(std::string cat) { + category_ = std::move(cat); +} +const std::string& Diagnostic::GetCategory() const noexcept { + return category_; +} + +void Diagnostic::SetWhere(SourceSpan sp) { + where_ = std::move(sp); +} +void Diagnostic::ResetWhere() { + where_.reset(); +} +const std::optional& Diagnostic::GetWhere() const noexcept { + return where_; +} + +void Diagnostic::AddNote(RelatedInfo note) { + notes_.emplace_back(std::move(note)); +} +void Diagnostic::ClearNotes() { + notes_.clear(); +} +const std::vector& Diagnostic::GetNotes() const noexcept { + return notes_; +} + +void Diagnostic::AddFix(FixIt fix) { + fixes_.emplace_back(std::move(fix)); +} +void Diagnostic::ClearFixes() { + fixes_.clear(); +} +const std::vector& Diagnostic::GetFixes() const noexcept { + return fixes_; +} + +void Diagnostic::SetFatal(bool on) { + is_fatal_ = on; +} +bool Diagnostic::IsFatal() const noexcept { + return is_fatal_; +} + +void Diagnostic::SetSuppressed(bool on) { + is_suppressed_ = on; +} +bool Diagnostic::IsSuppressed() const noexcept { + return is_suppressed_; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/diagnostics/Diagnostic.hpp b/lib/parser/diagnostics/Diagnostic.hpp new file mode 100644 index 0000000..d4b766d --- /dev/null +++ b/lib/parser/diagnostics/Diagnostic.hpp @@ -0,0 +1,70 @@ +#ifndef PARSER_DIAGNOSTIC_HPP_ +#define PARSER_DIAGNOSTIC_HPP_ + +#include +#include +#include +#include + +#include "FixIt.hpp" +#include "RelatedInfo.hpp" +#include "lib/parser/tokens/SourceSpan.hpp" +#include "severity/ISeverity.hpp" + +namespace ovum::compiler::parser { + +class Diagnostic { +public: + Diagnostic(); + Diagnostic(std::shared_ptr sev, std::string code, std::string message); + Diagnostic(const Diagnostic& other); + Diagnostic(Diagnostic&& other) noexcept; + Diagnostic& operator=(const Diagnostic& other); + Diagnostic& operator=(Diagnostic&& other) noexcept; + ~Diagnostic(); + + void SetSeverity(std::shared_ptr sev); + [[nodiscard]] const std::shared_ptr& GetSeverity() const noexcept; + + void SetCode(std::string c); + [[nodiscard]] const std::string& GetCode() const noexcept; + + void SetMessage(std::string m); + [[nodiscard]] const std::string& GetMessage() const noexcept; + + void SetCategory(std::string cat); + [[nodiscard]] const std::string& GetCategory() const noexcept; + + void SetWhere(SourceSpan sp); + void ResetWhere(); + [[nodiscard]] const std::optional& GetWhere() const noexcept; + + void AddNote(RelatedInfo note); + void ClearNotes(); + [[nodiscard]] const std::vector& GetNotes() const noexcept; + + void AddFix(FixIt fix); + void ClearFixes(); + [[nodiscard]] const std::vector& GetFixes() const noexcept; + + void SetFatal(bool on); + [[nodiscard]] bool IsFatal() const noexcept; + + void SetSuppressed(bool on); + [[nodiscard]] bool IsSuppressed() const noexcept; + +private: + std::shared_ptr severity_; + std::string code_; + std::string message_; + std::string category_; + std::optional where_; + std::vector notes_; + std::vector fixes_; + bool is_fatal_ = false; + bool is_suppressed_ = false; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_DIAGNOSTIC_HPP_ diff --git a/lib/parser/diagnostics/DiagnosticCollector.cpp b/lib/parser/diagnostics/DiagnosticCollector.cpp new file mode 100644 index 0000000..43991ff --- /dev/null +++ b/lib/parser/diagnostics/DiagnosticCollector.cpp @@ -0,0 +1,158 @@ +#include "lib/parser/diagnostics/DiagnosticCollector.hpp" + +#include + +#include "lib/parser/diagnostics/severity/Severity.hpp" + +namespace ovum::compiler::parser { + +void DiagnosticCollector::Report(Diagnostic d) { + bool suppressed = !ShouldKeep(d); + d.SetSuppressed(suppressed); + if (suppressed) { + return; + } + + if (dedup_ && IsDuplicate(d)) { + return; + } + + if (capacity_ && diags_.size() >= *capacity_) { + return; + } + + int err_level = Severity::Error()->Level(); + int warn_level = Severity::Warning()->Level(); + int level = d.GetSeverity() ? d.GetSeverity()->Level() : 0; + + if (level >= err_level) { + if (error_limit_ && errors_ >= *error_limit_) { + return; + } + + ++errors_; + } else if (level >= warn_level) { + if (warning_limit_ && warnings_ >= *warning_limit_) { + return; + } + + ++warnings_; + } + + diags_.emplace_back(std::move(d)); +} + +bool DiagnosticCollector::HasErrors() const { + return errors_ > 0; +} +std::size_t DiagnosticCollector::Count() const { + return diags_.size(); +} +std::size_t DiagnosticCollector::ErrorCount() const { + return errors_; +} +std::size_t DiagnosticCollector::WarningCount() const { + return warnings_; +} + +void DiagnosticCollector::Note(std::string_view code, std::string_view msg, std::optional where) { + Diagnostic d{Severity::Note(), std::string{code}, std::string{msg}}; + if (where) { + d.SetWhere(*where); + } + + Report(std::move(d)); +} + +void DiagnosticCollector::Warn(std::string_view code, std::string_view msg, std::optional where) { + Diagnostic d{Severity::Warning(), std::string{code}, std::string{msg}}; + if (where) { + d.SetWhere(*where); + } + + Report(std::move(d)); +} + +void DiagnosticCollector::Error(std::string_view code, std::string_view msg, std::optional where) { + Diagnostic d{Severity::Error(), std::string{code}, std::string{msg}}; + if (where) { + d.SetWhere(*where); + } + + Report(std::move(d)); +} + +const std::vector& DiagnosticCollector::All() const { + return diags_; +} + +void DiagnosticCollector::Clear() { + diags_.clear(); + errors_ = 0; + warnings_ = 0; +} + +void DiagnosticCollector::SuppressCode(std::string code) { + suppressed_codes_.insert(std::move(code)); +} + +void DiagnosticCollector::SuppressCategory(std::string category) { + suppressed_categories_.insert(std::move(category)); +} + +void DiagnosticCollector::SetGlobalFilter(Predicate p) { + global_filter_ = std::move(p); +} + +void DiagnosticCollector::ResetGlobalFilter() { + global_filter_.reset(); +} + +void DiagnosticCollector::EnableDeduplication(bool on) { + dedup_ = on; +} + +void DiagnosticCollector::SetCapacity(std::optional max_total) { + capacity_ = max_total; +} + +void DiagnosticCollector::SetErrorLimit(std::optional max_errors) { + error_limit_ = max_errors; +} + +void DiagnosticCollector::SetWarningLimit(std::optional max_warnings) { + warning_limit_ = max_warnings; +} + +bool DiagnosticCollector::IsSuppressed(const Diagnostic& d) const { + if (!d.GetCode().empty() && suppressed_codes_.count(d.GetCode()) > 0) { + return true; + } + + if (!d.GetCategory().empty() && suppressed_categories_.count(d.GetCategory()) > 0) { + return true; + } + + if (global_filter_ && !(*global_filter_)(d)) { + return true; + } + + return false; +} + +bool DiagnosticCollector::ShouldKeep(const Diagnostic& d) const { + return !IsSuppressed(d); +} + +bool DiagnosticCollector::IsDuplicate(const Diagnostic& d) const { + for (const auto& prev : diags_) { + if (prev.GetCode() == d.GetCode() && prev.GetMessage() == d.GetMessage() && + ((prev.GetSeverity() && d.GetSeverity()) ? prev.GetSeverity()->Level() == d.GetSeverity()->Level() + : prev.GetSeverity() == d.GetSeverity())) { + return true; + } + } + return false; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/diagnostics/DiagnosticCollector.hpp b/lib/parser/diagnostics/DiagnosticCollector.hpp new file mode 100644 index 0000000..9ed4f7c --- /dev/null +++ b/lib/parser/diagnostics/DiagnosticCollector.hpp @@ -0,0 +1,67 @@ +#ifndef PARSER_DIAGNOSTICCOLLECTOR_HPP_ +#define PARSER_DIAGNOSTICCOLLECTOR_HPP_ + +#include +#include +#include +#include +#include +#include +#include + +#include "IDiagnosticSink.hpp" + +namespace ovum::compiler::parser { + +class DiagnosticCollector : public IDiagnosticSink { +public: + using Predicate = std::function; + + ~DiagnosticCollector() override = default; + + void Report(Diagnostic d) override; + bool HasErrors() const override; + std::size_t Count() const override; + std::size_t ErrorCount() const override; + std::size_t WarningCount() const override; + + void Note(std::string_view code, std::string_view msg, std::optional where = std::nullopt) override; + void Warn(std::string_view code, std::string_view msg, std::optional where = std::nullopt) override; + void Error(std::string_view code, std::string_view msg, std::optional where = std::nullopt) override; + + const std::vector& All() const; + void Clear(); + + void SuppressCode(std::string code); + void SuppressCategory(std::string category); + void SetGlobalFilter(Predicate p); + void ResetGlobalFilter(); + void EnableDeduplication(bool on); + + void SetCapacity(std::optional max_total); + void SetErrorLimit(std::optional max_errors); + void SetWarningLimit(std::optional max_warnings); + + bool IsSuppressed(const Diagnostic& d) const; + +private: + bool ShouldKeep(const Diagnostic& d) const; + bool IsDuplicate(const Diagnostic& d) const; + + std::vector diags_; + std::unordered_set suppressed_codes_; + std::unordered_set suppressed_categories_; + std::optional global_filter_; + + bool dedup_ = true; + std::optional capacity_; + std::optional error_limit_; + std::optional warning_limit_; + + std::size_t errors_ = 0; + std::size_t warnings_ = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_DIAGNOSTICCOLLECTOR_HPP_ diff --git a/lib/parser/diagnostics/FixIt.cpp b/lib/parser/diagnostics/FixIt.cpp new file mode 100644 index 0000000..f110531 --- /dev/null +++ b/lib/parser/diagnostics/FixIt.cpp @@ -0,0 +1,11 @@ +#include "lib/parser/diagnostics/FixIt.hpp" + +#include + +namespace ovum::compiler::parser { + +FixIt::FixIt(SourceSpan source_span, std::string replacement) : + where_(std::move(source_span)), replacement_(std::move(replacement)) { +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/diagnostics/FixIt.hpp b/lib/parser/diagnostics/FixIt.hpp new file mode 100644 index 0000000..fcd23f2 --- /dev/null +++ b/lib/parser/diagnostics/FixIt.hpp @@ -0,0 +1,21 @@ +#ifndef PARSER_FIXIT_HPP_ +#define PARSER_FIXIT_HPP_ + +#include + +#include "lib/parser/tokens/SourceSpan.hpp" + +namespace ovum::compiler::parser { + +class FixIt { +public: + FixIt(SourceSpan source_span, std::string replacement); + +private: + SourceSpan where_; + std::string replacement_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_FIXIT_HPP_ diff --git a/lib/parser/diagnostics/IDiagnosticSink.hpp b/lib/parser/diagnostics/IDiagnosticSink.hpp new file mode 100644 index 0000000..a9bfe62 --- /dev/null +++ b/lib/parser/diagnostics/IDiagnosticSink.hpp @@ -0,0 +1,31 @@ +#ifndef PARSER_IDIAGNOSTICSINK_HPP_ +#define PARSER_IDIAGNOSTICSINK_HPP_ + +#include +#include +#include + +#include "Diagnostic.hpp" +#include "lib/parser/tokens/SourceSpan.hpp" + +namespace ovum::compiler::parser { + +class IDiagnosticSink { +public: + virtual ~IDiagnosticSink() = default; + + virtual void Report(Diagnostic d) = 0; + + virtual bool HasErrors() const = 0; + virtual std::size_t Count() const = 0; + virtual std::size_t ErrorCount() const = 0; + virtual std::size_t WarningCount() const = 0; + + virtual void Note(std::string_view code, std::string_view msg, std::optional where = std::nullopt) = 0; + virtual void Warn(std::string_view code, std::string_view msg, std::optional where = std::nullopt) = 0; + virtual void Error(std::string_view code, std::string_view msg, std::optional where = std::nullopt) = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IDIAGNOSTICSINK_HPP_ diff --git a/lib/parser/diagnostics/RelatedInfo.cpp b/lib/parser/diagnostics/RelatedInfo.cpp new file mode 100644 index 0000000..6878cad --- /dev/null +++ b/lib/parser/diagnostics/RelatedInfo.cpp @@ -0,0 +1,11 @@ +#include "lib/parser/diagnostics/RelatedInfo.hpp" + +#include + +namespace ovum::compiler::parser { + +RelatedInfo::RelatedInfo(std::string&& message, SourceSpan&& span) : + message_(std::move(message)), where_(std::move(span)) { +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/diagnostics/RelatedInfo.hpp b/lib/parser/diagnostics/RelatedInfo.hpp new file mode 100644 index 0000000..7ec6707 --- /dev/null +++ b/lib/parser/diagnostics/RelatedInfo.hpp @@ -0,0 +1,22 @@ +#ifndef PARSER_RELATEDINFO_HPP_ +#define PARSER_RELATEDINFO_HPP_ + +#include +#include + +#include "lib/parser/tokens/SourceSpan.hpp" + +namespace ovum::compiler::parser { + +class RelatedInfo { +public: + RelatedInfo(std::string&& message, SourceSpan&& span); + +private: + std::string message_; + std::optional where_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_RELATEDINFO_HPP_ diff --git a/lib/parser/diagnostics/severity/ISeverity.hpp b/lib/parser/diagnostics/severity/ISeverity.hpp new file mode 100644 index 0000000..1738dcf --- /dev/null +++ b/lib/parser/diagnostics/severity/ISeverity.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_ISEVERITY_HPP_ +#define PARSER_ISEVERITY_HPP_ + +#include + +namespace ovum::compiler::parser { + +class ISeverity { +public: + virtual ~ISeverity() = default; + virtual std::string_view Name() const = 0; + virtual int Level() const = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_ISEVERITY_HPP_ diff --git a/lib/parser/diagnostics/severity/Severity.cpp b/lib/parser/diagnostics/severity/Severity.cpp new file mode 100644 index 0000000..860ef58 --- /dev/null +++ b/lib/parser/diagnostics/severity/Severity.cpp @@ -0,0 +1,49 @@ +#include "lib/parser/diagnostics/severity/Severity.hpp" + +#include +#include +#include +#include + +namespace ovum::compiler::parser { + +namespace { +class SimpleSeverity : public ISeverity { +public: + SimpleSeverity(std::string name, int level) : name_(std::move(name)), level_(level) { + } + + [[nodiscard]] std::string_view Name() const override { + return name_; + } + + [[nodiscard]] int Level() const override { + return level_; + } + +private: + std::string name_; + int level_; +}; +} // namespace + +const std::shared_ptr& Severity::Note() { + static const auto kInst = std::make_shared("note", 10); + return kInst; +} + +const std::shared_ptr& Severity::Warning() { + static const auto kInst = std::make_shared("warning", 20); + return kInst; +} + +const std::shared_ptr& Severity::Error() { + static const auto kInst = std::make_shared("error", 30); + return kInst; +} + +std::shared_ptr Severity::Custom(std::string_view name, int level) { + return std::make_shared(std::string{name}, level); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/diagnostics/severity/Severity.hpp b/lib/parser/diagnostics/severity/Severity.hpp new file mode 100644 index 0000000..c7bfa8b --- /dev/null +++ b/lib/parser/diagnostics/severity/Severity.hpp @@ -0,0 +1,22 @@ +#ifndef PARSER_SEVERITY_HPP_ +#define PARSER_SEVERITY_HPP_ + +#include +#include + +#include "ISeverity.hpp" + +namespace ovum::compiler::parser { + +class Severity { +public: + static const std::shared_ptr& Note(); + static const std::shared_ptr& Warning(); + static const std::shared_ptr& Error(); + + static std::shared_ptr Custom(std::string_view name, int level); +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_SEVERITY_HPP_ diff --git a/lib/parser/pratt/DefaultOperatorResolver.cpp b/lib/parser/pratt/DefaultOperatorResolver.cpp new file mode 100644 index 0000000..78ad1df --- /dev/null +++ b/lib/parser/pratt/DefaultOperatorResolver.cpp @@ -0,0 +1,3 @@ +#include "DefaultOperatorResolver.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/pratt/DefaultOperatorResolver.hpp b/lib/parser/pratt/DefaultOperatorResolver.hpp new file mode 100644 index 0000000..1e64948 --- /dev/null +++ b/lib/parser/pratt/DefaultOperatorResolver.hpp @@ -0,0 +1,31 @@ +#ifndef PARSER_DEFAULTOPERATORRESOLVER_HPP_ +#define PARSER_DEFAULTOPERATORRESOLVER_HPP_ + +#include +#include +#include + +#include "IOperatorResolver.hpp" +#include "lib/parser/ast/nodes/exprs/tags/IUnaryOpTag.hpp" +#include "specifications/InfixSpec.hpp" +#include "specifications/PostfixSpec.hpp" + +namespace ovum::compiler::parser { + +class DefaultOperatorResolver : public IOperatorResolver { +public: + ~DefaultOperatorResolver() override = default; + + std::optional> FindInfix(const Token& t) const override; + std::optional> FindPostfix(const Token& t) const override; + std::optional> FindPrefix(const Token& t) const override; + bool IsContinuation(const Token& t) const override; + +private: + std::vector infix_; + std::vector postfix_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_DEFAULTOPERATORRESOLVER_HPP_ diff --git a/lib/parser/pratt/IExpressionParser.hpp b/lib/parser/pratt/IExpressionParser.hpp new file mode 100644 index 0000000..4cdc336 --- /dev/null +++ b/lib/parser/pratt/IExpressionParser.hpp @@ -0,0 +1,21 @@ +#ifndef PARSER_IEXPRESSIONPARSER_HPP_ +#define PARSER_IEXPRESSIONPARSER_HPP_ + +#include + +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/diagnostics/IDiagnosticSink.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class IExpressionParser { +public: + virtual ~IExpressionParser() = default; + + virtual std::unique_ptr Parse(ITokenStream& ts, IDiagnosticSink& diags) = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IEXPRESSIONPARSER_HPP_ diff --git a/lib/parser/pratt/IOperatorResolver.hpp b/lib/parser/pratt/IOperatorResolver.hpp new file mode 100644 index 0000000..ffb761a --- /dev/null +++ b/lib/parser/pratt/IOperatorResolver.hpp @@ -0,0 +1,26 @@ +#ifndef PARSER_IOPERATORRESOLVER_HPP_ +#define PARSER_IOPERATORRESOLVER_HPP_ + +#include +#include + +namespace ovum::compiler::parser { + +class Token; +class IUnaryOpTag; +class InfixSpec; +class PostfixSpec; + +class IOperatorResolver { +public: + virtual ~IOperatorResolver() = default; + + virtual std::optional> FindInfix(const Token& t) const = 0; + virtual std::optional> FindPostfix(const Token& t) const = 0; + virtual std::optional> FindPrefix(const Token& t) const = 0; + virtual bool IsContinuation(const Token& t) const = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IOPERATORRESOLVER_HPP_ diff --git a/lib/parser/pratt/PrattExpressionParser.cpp b/lib/parser/pratt/PrattExpressionParser.cpp new file mode 100644 index 0000000..f63be8b --- /dev/null +++ b/lib/parser/pratt/PrattExpressionParser.cpp @@ -0,0 +1,3 @@ +#include "PrattExpressionParser.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/pratt/PrattExpressionParser.hpp b/lib/parser/pratt/PrattExpressionParser.hpp new file mode 100644 index 0000000..daadd0b --- /dev/null +++ b/lib/parser/pratt/PrattExpressionParser.hpp @@ -0,0 +1,38 @@ +#ifndef PARSER_PRATTEXPRESSIONPARSER_HPP_ +#define PARSER_PRATTEXPRESSIONPARSER_HPP_ + +#include +#include + +#include "IExpressionParser.hpp" +#include "IOperatorResolver.hpp" +#include "lib/parser/ast/IAstFactory.hpp" +#include "lib/parser/ast/nodes/base/Expr.hpp" +#include "lib/parser/diagnostics/IDiagnosticSink.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class PrattExpressionParser : public IExpressionParser { +public: + explicit PrattExpressionParser(std::unique_ptr resolver, std::shared_ptr factory); + ~PrattExpressionParser() override = default; + + std::unique_ptr Parse(ITokenStream& ts, IDiagnosticSink& diags) override; + + std::unique_ptr ParseExpr(ITokenStream& ts, IDiagnosticSink& diags, int min_bp); + std::unique_ptr ParsePrefix(ITokenStream& ts, IDiagnosticSink& diags); + std::unique_ptr ParsePostfix(ITokenStream& ts, IDiagnosticSink& diags, std::unique_ptr base); + + std::vector> ParseArgList(ITokenStream& ts, IDiagnosticSink& diags, char closing); + +private: + std::unique_ptr MakeInfix(const InfixSpec& spec, std::unique_ptr lhs, std::unique_ptr rhs); + + std::unique_ptr resolver_; + std::shared_ptr factory_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_PRATTEXPRESSIONPARSER_HPP_ diff --git a/lib/parser/pratt/specifications/InfixSpec.cpp b/lib/parser/pratt/specifications/InfixSpec.cpp new file mode 100644 index 0000000..9b3f161 --- /dev/null +++ b/lib/parser/pratt/specifications/InfixSpec.cpp @@ -0,0 +1,3 @@ +#include "InfixSpec.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/pratt/specifications/InfixSpec.hpp b/lib/parser/pratt/specifications/InfixSpec.hpp new file mode 100644 index 0000000..c2d2b8c --- /dev/null +++ b/lib/parser/pratt/specifications/InfixSpec.hpp @@ -0,0 +1,27 @@ +#ifndef PARSER_INFIXSPEC_HPP_ +#define PARSER_INFIXSPEC_HPP_ + +#include + +#include + +#include "lib/parser/ast/nodes/exprs/tags/IBinaryOpTag.hpp" + +namespace ovum::compiler::parser { + +class InfixSpec { +public: + InfixSpec(int lbp, int rbp, bool right_associative, IBinaryOpTag* tag, bool is_elvis); + // TODO: implement getters and setters +private: + std::function match_; + int lbp_ = 0; + int rbp_ = 0; + bool right_associative_ = false; + const IBinaryOpTag* tag_ = nullptr; + bool is_elvis_ = false; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_INFIXSPEC_HPP_ diff --git a/lib/parser/pratt/specifications/PostfixSpec.cpp b/lib/parser/pratt/specifications/PostfixSpec.cpp new file mode 100644 index 0000000..ebbc6b2 --- /dev/null +++ b/lib/parser/pratt/specifications/PostfixSpec.cpp @@ -0,0 +1,3 @@ +#include "PostfixSpec.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/pratt/specifications/PostfixSpec.hpp b/lib/parser/pratt/specifications/PostfixSpec.hpp new file mode 100644 index 0000000..380137c --- /dev/null +++ b/lib/parser/pratt/specifications/PostfixSpec.hpp @@ -0,0 +1,22 @@ +#ifndef PARSER_POSTFIXSPEC_HPP_ +#define PARSER_POSTFIXSPEC_HPP_ + +#include + +#include + +namespace ovum::compiler::parser { + +class PostfixSpec { +public: + PostfixSpec(std::function match, int bp, bool keyword); + // TODO: implements getters and setters +private: + std::function match_; + int bp = 0; + bool keyword = false; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_POSTFIXSPEC_HPP_ diff --git a/lib/parser/recovery/IRecoveryStrategy.hpp b/lib/parser/recovery/IRecoveryStrategy.hpp new file mode 100644 index 0000000..8df9f3e --- /dev/null +++ b/lib/parser/recovery/IRecoveryStrategy.hpp @@ -0,0 +1,18 @@ +#ifndef PARSER_IRECOVERYSTRATEGY_HPP_ +#define PARSER_IRECOVERYSTRATEGY_HPP_ + +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class IRecoveryStrategy { +public: + virtual ~IRecoveryStrategy() { + } + virtual void SyncToStmtEnd(ITokenStream& ts) = 0; + virtual void SyncToBlockEnd(ITokenStream& ts) = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_IRECOVERYSTRATEGY_HPP_ diff --git a/lib/parser/recovery/SimpleRecovery.cpp b/lib/parser/recovery/SimpleRecovery.cpp new file mode 100644 index 0000000..b942901 --- /dev/null +++ b/lib/parser/recovery/SimpleRecovery.cpp @@ -0,0 +1,3 @@ +#include "SimpleRecovery.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/recovery/SimpleRecovery.hpp b/lib/parser/recovery/SimpleRecovery.hpp new file mode 100644 index 0000000..f59f4fa --- /dev/null +++ b/lib/parser/recovery/SimpleRecovery.hpp @@ -0,0 +1,18 @@ +#ifndef PARSER_SIMPLERECOVERY_HPP_ +#define PARSER_SIMPLERECOVERY_HPP_ + +#include "IRecoveryStrategy.hpp" + +namespace ovum::compiler::parser { + +class SimpleRecovery : IRecoveryStrategy { +public: + ~SimpleRecovery() override = default; + + void SyncToStmtEnd(ITokenStream& ts) override; + void SyncToBlockEnd(ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_SIMPLERECOVERY_HPP_ diff --git a/lib/parser/states/StateBlock.cpp b/lib/parser/states/StateBlock.cpp new file mode 100644 index 0000000..39f5929 --- /dev/null +++ b/lib/parser/states/StateBlock.cpp @@ -0,0 +1,3 @@ +#include "StateBlock.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateBlock.hpp b/lib/parser/states/StateBlock.hpp new file mode 100644 index 0000000..c132b65 --- /dev/null +++ b/lib/parser/states/StateBlock.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEBLOCK_HPP_ +#define PARSER_STATEBLOCK_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateBlock : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEBLOCK_HPP_ diff --git a/lib/parser/states/StateCallDeclHdr.cpp b/lib/parser/states/StateCallDeclHdr.cpp new file mode 100644 index 0000000..bef8fc0 --- /dev/null +++ b/lib/parser/states/StateCallDeclHdr.cpp @@ -0,0 +1,3 @@ +#include "StateCallDeclHdr.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateCallDeclHdr.hpp b/lib/parser/states/StateCallDeclHdr.hpp new file mode 100644 index 0000000..f1025be --- /dev/null +++ b/lib/parser/states/StateCallDeclHdr.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATECALLDECLHDR_HPP_ +#define PARSER_STATECALLDECLHDR_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateCallDeclHdr : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATECALLDECLHDR_HPP_ diff --git a/lib/parser/states/StateDestructorDecl.cpp b/lib/parser/states/StateDestructorDecl.cpp new file mode 100644 index 0000000..d054df6 --- /dev/null +++ b/lib/parser/states/StateDestructorDecl.cpp @@ -0,0 +1,3 @@ +#include "StateDestructorDecl.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateDestructorDecl.hpp b/lib/parser/states/StateDestructorDecl.hpp new file mode 100644 index 0000000..805c7c0 --- /dev/null +++ b/lib/parser/states/StateDestructorDecl.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEDESTRUCTORDECL_HPP_ +#define PARSER_STATEDESTRUCTORDECL_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateDestructorDecl : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEDESTRUCTORDECL_HPP_ diff --git a/lib/parser/states/StateExpr.cpp b/lib/parser/states/StateExpr.cpp new file mode 100644 index 0000000..732bb7e --- /dev/null +++ b/lib/parser/states/StateExpr.cpp @@ -0,0 +1,3 @@ +#include "StateExpr.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateExpr.hpp b/lib/parser/states/StateExpr.hpp new file mode 100644 index 0000000..f520915 --- /dev/null +++ b/lib/parser/states/StateExpr.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEEXPR_HPP_ +#define PARSER_STATEEXPR_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateExpr : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEEXPR_HPP_ diff --git a/lib/parser/states/StateFieldDecl.cpp b/lib/parser/states/StateFieldDecl.cpp new file mode 100644 index 0000000..ad88b6e --- /dev/null +++ b/lib/parser/states/StateFieldDecl.cpp @@ -0,0 +1,3 @@ +#include "StateFieldDecl.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateFieldDecl.hpp b/lib/parser/states/StateFieldDecl.hpp new file mode 100644 index 0000000..672c16f --- /dev/null +++ b/lib/parser/states/StateFieldDecl.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEFIELDDECL_HPP_ +#define PARSER_STATEFIELDDECL_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateFieldDecl : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEFIELDDECL_HPP_ diff --git a/lib/parser/states/StateForHead.cpp b/lib/parser/states/StateForHead.cpp new file mode 100644 index 0000000..cae61dc --- /dev/null +++ b/lib/parser/states/StateForHead.cpp @@ -0,0 +1,3 @@ +#include "StateForHead.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateForHead.hpp b/lib/parser/states/StateForHead.hpp new file mode 100644 index 0000000..6df6546 --- /dev/null +++ b/lib/parser/states/StateForHead.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEFORHEAD_HPP_ +#define PARSER_STATEFORHEAD_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateForHead : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEFORHEAD_HPP_ diff --git a/lib/parser/states/StateGlobalVarDecl.cpp b/lib/parser/states/StateGlobalVarDecl.cpp new file mode 100644 index 0000000..767bacd --- /dev/null +++ b/lib/parser/states/StateGlobalVarDecl.cpp @@ -0,0 +1,3 @@ +#include "StateGlobalVarDecl.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateGlobalVarDecl.hpp b/lib/parser/states/StateGlobalVarDecl.hpp new file mode 100644 index 0000000..ecd860a --- /dev/null +++ b/lib/parser/states/StateGlobalVarDecl.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEGLOBALVARDECL_HPP_ +#define PARSER_STATEGLOBALVARDECL_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateGlobalVarDecl : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEGLOBALVARDECL_HPP_ diff --git a/lib/parser/states/StateIfHead.cpp b/lib/parser/states/StateIfHead.cpp new file mode 100644 index 0000000..250ddad --- /dev/null +++ b/lib/parser/states/StateIfHead.cpp @@ -0,0 +1,3 @@ +#include "StateIfHead.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateIfHead.hpp b/lib/parser/states/StateIfHead.hpp new file mode 100644 index 0000000..9ef894d --- /dev/null +++ b/lib/parser/states/StateIfHead.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEIFHEAD_HPP_ +#define PARSER_STATEIFHEAD_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateIfHead : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEIFHEAD_HPP_ diff --git a/lib/parser/states/StateIfTail.cpp b/lib/parser/states/StateIfTail.cpp new file mode 100644 index 0000000..0025258 --- /dev/null +++ b/lib/parser/states/StateIfTail.cpp @@ -0,0 +1,3 @@ +#include "StateIfTail.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateIfTail.hpp b/lib/parser/states/StateIfTail.hpp new file mode 100644 index 0000000..e1b2ef2 --- /dev/null +++ b/lib/parser/states/StateIfTail.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEIFTAIL_HPP_ +#define PARSER_STATEIFTAIL_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateIfTail : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEIFTAIL_HPP_ diff --git a/lib/parser/states/StateMethodHdr.cpp b/lib/parser/states/StateMethodHdr.cpp new file mode 100644 index 0000000..a896051 --- /dev/null +++ b/lib/parser/states/StateMethodHdr.cpp @@ -0,0 +1,3 @@ +#include "StateMethodHdr.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateMethodHdr.hpp b/lib/parser/states/StateMethodHdr.hpp new file mode 100644 index 0000000..0584002 --- /dev/null +++ b/lib/parser/states/StateMethodHdr.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEMETHODHDR_HPP_ +#define PARSER_STATEMETHODHDR_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateMethodHdr : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEMETHODHDR_HPP_ diff --git a/lib/parser/states/StateModule.cpp b/lib/parser/states/StateModule.cpp new file mode 100644 index 0000000..fad4833 --- /dev/null +++ b/lib/parser/states/StateModule.cpp @@ -0,0 +1,3 @@ +#include "StateModule.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateModule.hpp b/lib/parser/states/StateModule.hpp new file mode 100644 index 0000000..6d05277 --- /dev/null +++ b/lib/parser/states/StateModule.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEMODULE_HPP_ +#define PARSER_STATEMODULE_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateModule : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEMODULE_HPP_ diff --git a/lib/parser/states/StateParseType.cpp b/lib/parser/states/StateParseType.cpp new file mode 100644 index 0000000..0cb32e0 --- /dev/null +++ b/lib/parser/states/StateParseType.cpp @@ -0,0 +1,3 @@ +#include "StateParseType.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateParseType.hpp b/lib/parser/states/StateParseType.hpp new file mode 100644 index 0000000..f4ad9ac --- /dev/null +++ b/lib/parser/states/StateParseType.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEPARSETYPE_HPP_ +#define PARSER_STATEPARSETYPE_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateParseType : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEPARSETYPE_HPP_ diff --git a/lib/parser/states/StateReturnTail.cpp b/lib/parser/states/StateReturnTail.cpp new file mode 100644 index 0000000..b74db84 --- /dev/null +++ b/lib/parser/states/StateReturnTail.cpp @@ -0,0 +1,3 @@ +#include "StateReturnTail.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateReturnTail.hpp b/lib/parser/states/StateReturnTail.hpp new file mode 100644 index 0000000..9fda688 --- /dev/null +++ b/lib/parser/states/StateReturnTail.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATERETURNTAIL_HPP_ +#define PARSER_STATERETURNTAIL_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateReturnTail : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATERETURNTAIL_HPP_ diff --git a/lib/parser/states/StateStmt.cpp b/lib/parser/states/StateStmt.cpp new file mode 100644 index 0000000..5be5521 --- /dev/null +++ b/lib/parser/states/StateStmt.cpp @@ -0,0 +1,3 @@ +#include "StateStmt.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateStmt.hpp b/lib/parser/states/StateStmt.hpp new file mode 100644 index 0000000..0bb7d88 --- /dev/null +++ b/lib/parser/states/StateStmt.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATESTMT_HPP_ +#define PARSER_STATESTMT_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateStmt : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATESTMT_HPP_ diff --git a/lib/parser/states/StateSyncToBlockEnd.cpp b/lib/parser/states/StateSyncToBlockEnd.cpp new file mode 100644 index 0000000..c68ba42 --- /dev/null +++ b/lib/parser/states/StateSyncToBlockEnd.cpp @@ -0,0 +1,3 @@ +#include "StateSyncToBlockEnd.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateSyncToBlockEnd.hpp b/lib/parser/states/StateSyncToBlockEnd.hpp new file mode 100644 index 0000000..d0aa0a2 --- /dev/null +++ b/lib/parser/states/StateSyncToBlockEnd.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATESYNCTOBLOCKEND_HPP_ +#define PARSER_STATESYNCTOBLOCKEND_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateSyncToBlockEnd : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATESYNCTOBLOCKEND_HPP_ diff --git a/lib/parser/states/StateSyncToStmtEnd.cpp b/lib/parser/states/StateSyncToStmtEnd.cpp new file mode 100644 index 0000000..edbb355 --- /dev/null +++ b/lib/parser/states/StateSyncToStmtEnd.cpp @@ -0,0 +1,3 @@ +#include "StateSyncToStmtEnd.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateSyncToStmtEnd.hpp b/lib/parser/states/StateSyncToStmtEnd.hpp new file mode 100644 index 0000000..9de6e54 --- /dev/null +++ b/lib/parser/states/StateSyncToStmtEnd.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATESYNCTOSTMTEND_HPP_ +#define PARSER_STATESYNCTOSTMTEND_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateSyncToStmtEnd : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATESYNCTOSTMTEND_HPP_ diff --git a/lib/parser/states/StateTopDecl.cpp b/lib/parser/states/StateTopDecl.cpp new file mode 100644 index 0000000..a977e77 --- /dev/null +++ b/lib/parser/states/StateTopDecl.cpp @@ -0,0 +1,3 @@ +#include "StateTopDecl.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateTopDecl.hpp b/lib/parser/states/StateTopDecl.hpp new file mode 100644 index 0000000..3731c46 --- /dev/null +++ b/lib/parser/states/StateTopDecl.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATETOPDECL_HPP_ +#define PARSER_STATETOPDECL_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateTopDecl : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATETOPDECL_HPP_ diff --git a/lib/parser/states/StateTypeAliasDecl.cpp b/lib/parser/states/StateTypeAliasDecl.cpp new file mode 100644 index 0000000..8030979 --- /dev/null +++ b/lib/parser/states/StateTypeAliasDecl.cpp @@ -0,0 +1,3 @@ +#include "StateTypeAliasDecl.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateTypeAliasDecl.hpp b/lib/parser/states/StateTypeAliasDecl.hpp new file mode 100644 index 0000000..72ad630 --- /dev/null +++ b/lib/parser/states/StateTypeAliasDecl.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATETYPEALIASDECL_HPP_ +#define PARSER_STATETYPEALIASDECL_HPP_ + +#include "lib/parser/states/base/StateBase.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class StateTypeAliasDecl : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATETYPEALIASDECL_HPP_ diff --git a/lib/parser/states/StateUnsafeBlock.cpp b/lib/parser/states/StateUnsafeBlock.cpp new file mode 100644 index 0000000..9ca09da --- /dev/null +++ b/lib/parser/states/StateUnsafeBlock.cpp @@ -0,0 +1,3 @@ +#include "StateUnsafeBlock.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateUnsafeBlock.hpp b/lib/parser/states/StateUnsafeBlock.hpp new file mode 100644 index 0000000..931773e --- /dev/null +++ b/lib/parser/states/StateUnsafeBlock.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEUNSAFEBLOCK_HPP_ +#define PARSER_STATEUNSAFEBLOCK_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateUnsafeBlock : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEUNSAFEBLOCK_HPP_ diff --git a/lib/parser/states/StateVarDeclTail.cpp b/lib/parser/states/StateVarDeclTail.cpp new file mode 100644 index 0000000..41f64d5 --- /dev/null +++ b/lib/parser/states/StateVarDeclTail.cpp @@ -0,0 +1,3 @@ +#include "StateVarDeclTail.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateVarDeclTail.hpp b/lib/parser/states/StateVarDeclTail.hpp new file mode 100644 index 0000000..d81d64e --- /dev/null +++ b/lib/parser/states/StateVarDeclTail.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEVARDECLTAIL_HPP_ +#define PARSER_STATEVARDECLTAIL_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateVarDeclTail : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEVARDECLTAIL_HPP_ diff --git a/lib/parser/states/StateWhileHead.cpp b/lib/parser/states/StateWhileHead.cpp new file mode 100644 index 0000000..ff319f1 --- /dev/null +++ b/lib/parser/states/StateWhileHead.cpp @@ -0,0 +1,3 @@ +#include "StateWhileHead.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/StateWhileHead.hpp b/lib/parser/states/StateWhileHead.hpp new file mode 100644 index 0000000..685924f --- /dev/null +++ b/lib/parser/states/StateWhileHead.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEWHILEHEAD_HPP_ +#define PARSER_STATEWHILEHEAD_HPP_ + +#include "base/StateBase.hpp" +#include "lib/parser/context/ContextParser.hpp" + +namespace ovum::compiler::parser { + +class StateWhileHead : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEWHILEHEAD_HPP_ diff --git a/lib/parser/states/base/IState.hpp b/lib/parser/states/base/IState.hpp new file mode 100644 index 0000000..a077b10 --- /dev/null +++ b/lib/parser/states/base/IState.hpp @@ -0,0 +1,24 @@ +#ifndef PARSER_ISTATE_HPP_ +#define PARSER_ISTATE_HPP_ + +#include + +#include "StateError.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class ContextParser; // forward + +class IState { +public: + using StepResult = std::expected; + + virtual ~IState() = default; + virtual std::string_view Name() const = 0; + virtual StepResult TryStep(ContextParser& ctx, ITokenStream& ts) = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_ISTATE_HPP_ diff --git a/lib/parser/states/base/StateBase.cpp b/lib/parser/states/base/StateBase.cpp new file mode 100644 index 0000000..fd524e4 --- /dev/null +++ b/lib/parser/states/base/StateBase.cpp @@ -0,0 +1,3 @@ +#include "StateBase.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/base/StateBase.hpp b/lib/parser/states/base/StateBase.hpp new file mode 100644 index 0000000..cee25f8 --- /dev/null +++ b/lib/parser/states/base/StateBase.hpp @@ -0,0 +1,19 @@ +#ifndef PARSER_STATEBASE_HPP_ +#define PARSER_STATEBASE_HPP_ + +#include "IState.hpp" +#include "lib/parser/tokens/SourceSpan.hpp" + +namespace ovum::compiler::parser { + +class StateBase : IState { +public: + using StepResult = StepResult; + ~StateBase() override = default; + static SourceSpan SpanFrom(const Token& token); + static SourceSpan Union(const SourceSpan& lhs, const SourceSpan& rhs); +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEBASE_HPP_ diff --git a/lib/parser/states/base/StateError.cpp b/lib/parser/states/base/StateError.cpp new file mode 100644 index 0000000..9aae614 --- /dev/null +++ b/lib/parser/states/base/StateError.cpp @@ -0,0 +1,3 @@ +#include "StateError.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/base/StateError.hpp b/lib/parser/states/base/StateError.hpp new file mode 100644 index 0000000..a751e38 --- /dev/null +++ b/lib/parser/states/base/StateError.hpp @@ -0,0 +1,20 @@ +#ifndef PARSER_STATEERROR_HPP_ +#define PARSER_STATEERROR_HPP_ + +#include + +namespace ovum::compiler::parser { + +class StateError { +public: + StateError(); + explicit StateError(std::string message); + const std::string& Message() const noexcept; + +private: + std::string message_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEERROR_HPP_ diff --git a/lib/parser/states/base/StateRegistry.cpp b/lib/parser/states/base/StateRegistry.cpp new file mode 100644 index 0000000..870dc88 --- /dev/null +++ b/lib/parser/states/base/StateRegistry.cpp @@ -0,0 +1,3 @@ +#include "StateRegistry.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/base/StateRegistry.hpp b/lib/parser/states/base/StateRegistry.hpp new file mode 100644 index 0000000..a5368e3 --- /dev/null +++ b/lib/parser/states/base/StateRegistry.hpp @@ -0,0 +1,49 @@ +#ifndef PARSER_STATEREGISTRY_HPP_ +#define PARSER_STATEREGISTRY_HPP_ + +#include "IState.hpp" + +namespace ovum::compiler::parser { + +class StateRegistry { + static const IState& Module(); + static const IState& TopDecl(); + + static const IState& FuncHdr(); + static const IState& FuncParams(); + static const IState& FuncBody(); + + static const IState& ClassHdr(); + static const IState& ClassBody(); + static const IState& ClassMember(); + static const IState& InterfaceHdr(); + static const IState& InterfaceBody(); + static const IState& SignatureDecl(); + + static const IState& TypeAliasDecl(); + static const IState& GlobalVarDecl(); + + static const IState& DestructorDecl(); + static const IState& CallDeclHdr(); + static const IState& MethodHdr(); + static const IState& FieldDecl(); + + static const IState& Block(); + static const IState& Stmt(); + static const IState& IfHead(); + static const IState& IfTail(); + static const IState& WhileHead(); + static const IState& ForHead(); + static const IState& ReturnTail(); + static const IState& VarDeclTail(); + static const IState& UnsafeBlock(); + + static const IState& ParseType(); + static const IState& Expr(); + static const IState& SyncToStmtEnd(); + static const IState& SyncToBlockEnd(); +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEREGISTRY_HPP_ diff --git a/lib/parser/states/class/StateClassBody.cpp b/lib/parser/states/class/StateClassBody.cpp new file mode 100644 index 0000000..32f31bf --- /dev/null +++ b/lib/parser/states/class/StateClassBody.cpp @@ -0,0 +1,3 @@ +#include "StateClassBody.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/class/StateClassBody.hpp b/lib/parser/states/class/StateClassBody.hpp new file mode 100644 index 0000000..f5780ae --- /dev/null +++ b/lib/parser/states/class/StateClassBody.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATECLASSBODY_HPP_ +#define PARSER_STATECLASSBODY_HPP_ + +#include "lib/parser/states/base/StateBase.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class StateClassBody : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATECLASSBODY_HPP_ diff --git a/lib/parser/states/class/StateClassHdr.cpp b/lib/parser/states/class/StateClassHdr.cpp new file mode 100644 index 0000000..8926460 --- /dev/null +++ b/lib/parser/states/class/StateClassHdr.cpp @@ -0,0 +1,3 @@ +#include "StateClassHdr.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/class/StateClassHdr.hpp b/lib/parser/states/class/StateClassHdr.hpp new file mode 100644 index 0000000..cc6342f --- /dev/null +++ b/lib/parser/states/class/StateClassHdr.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATECLASSHDR_HPP_ +#define PARSER_STATECLASSHDR_HPP_ + +#include "lib/parser/states/base/StateBase.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class StateClassHdr : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATECLASSHDR_HPP_ diff --git a/lib/parser/states/class/StateClassMember.cpp b/lib/parser/states/class/StateClassMember.cpp new file mode 100644 index 0000000..bb4b51d --- /dev/null +++ b/lib/parser/states/class/StateClassMember.cpp @@ -0,0 +1,3 @@ +#include "StateClassMember.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/class/StateClassMember.hpp b/lib/parser/states/class/StateClassMember.hpp new file mode 100644 index 0000000..2901748 --- /dev/null +++ b/lib/parser/states/class/StateClassMember.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATECLASSMEMBER_HPP_ +#define PARSER_STATECLASSMEMBER_HPP_ + +#include "lib/parser/states/base/StateBase.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class StateClassMember : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATECLASSMEMBER_HPP_ diff --git a/lib/parser/states/func/StateFuncBody.cpp b/lib/parser/states/func/StateFuncBody.cpp new file mode 100644 index 0000000..3c5f696 --- /dev/null +++ b/lib/parser/states/func/StateFuncBody.cpp @@ -0,0 +1,3 @@ +#include "StateFuncBody.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/func/StateFuncBody.hpp b/lib/parser/states/func/StateFuncBody.hpp new file mode 100644 index 0000000..0397629 --- /dev/null +++ b/lib/parser/states/func/StateFuncBody.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEFUNCBODY_HPP_ +#define PARSER_STATEFUNCBODY_HPP_ + +#include "lib/parser/states/base/StateBase.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class StateFuncBody : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEFUNCBODY_HPP_ diff --git a/lib/parser/states/func/StateFuncHdr.cpp b/lib/parser/states/func/StateFuncHdr.cpp new file mode 100644 index 0000000..807ce70 --- /dev/null +++ b/lib/parser/states/func/StateFuncHdr.cpp @@ -0,0 +1,3 @@ +#include "StateFuncHdr.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/func/StateFuncHdr.hpp b/lib/parser/states/func/StateFuncHdr.hpp new file mode 100644 index 0000000..1b57c8d --- /dev/null +++ b/lib/parser/states/func/StateFuncHdr.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEFUNCHDR_HPP_ +#define PARSER_STATEFUNCHDR_HPP_ + +#include "lib/parser/states/base/StateBase.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class StateFuncHdr : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEFUNCHDR_HPP_ diff --git a/lib/parser/states/func/StateFuncParams.cpp b/lib/parser/states/func/StateFuncParams.cpp new file mode 100644 index 0000000..9fdf6b8 --- /dev/null +++ b/lib/parser/states/func/StateFuncParams.cpp @@ -0,0 +1,3 @@ +#include "StateFuncParams.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/func/StateFuncParams.hpp b/lib/parser/states/func/StateFuncParams.hpp new file mode 100644 index 0000000..7929508 --- /dev/null +++ b/lib/parser/states/func/StateFuncParams.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEFUNCPARAMS_HPP_ +#define PARSER_STATEFUNCPARAMS_HPP_ + +#include "lib/parser/states/base/StateBase.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class StateFuncParams : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEFUNCPARAMS_HPP_ diff --git a/lib/parser/states/interface/StateInterfaceBody.cpp b/lib/parser/states/interface/StateInterfaceBody.cpp new file mode 100644 index 0000000..08cfa87 --- /dev/null +++ b/lib/parser/states/interface/StateInterfaceBody.cpp @@ -0,0 +1,3 @@ +#include "StateInterfaceBody.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/interface/StateInterfaceBody.hpp b/lib/parser/states/interface/StateInterfaceBody.hpp new file mode 100644 index 0000000..fd84410 --- /dev/null +++ b/lib/parser/states/interface/StateInterfaceBody.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEINTERFACEBODY_HPP_ +#define PARSER_STATEINTERFACEBODY_HPP_ + +#include "lib/parser/states/base/StateBase.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class StateInterfaceBody : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEINTERFACEBODY_HPP_ diff --git a/lib/parser/states/interface/StateInterfaceDecl.cpp b/lib/parser/states/interface/StateInterfaceDecl.cpp new file mode 100644 index 0000000..85c9bf3 --- /dev/null +++ b/lib/parser/states/interface/StateInterfaceDecl.cpp @@ -0,0 +1,3 @@ +#include "StateInterfaceDecl.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/interface/StateInterfaceDecl.hpp b/lib/parser/states/interface/StateInterfaceDecl.hpp new file mode 100644 index 0000000..4f92a61 --- /dev/null +++ b/lib/parser/states/interface/StateInterfaceDecl.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEINTERFACEDECL_HPP_ +#define PARSER_STATEINTERFACEDECL_HPP_ + +#include "lib/parser/states/base/StateBase.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class StateInterfaceDecl : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEINTERFACEDECL_HPP_ diff --git a/lib/parser/states/interface/StateInterfaceHdr.cpp b/lib/parser/states/interface/StateInterfaceHdr.cpp new file mode 100644 index 0000000..cebb5fb --- /dev/null +++ b/lib/parser/states/interface/StateInterfaceHdr.cpp @@ -0,0 +1,3 @@ +#include "StateInterfaceHdr.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/states/interface/StateInterfaceHdr.hpp b/lib/parser/states/interface/StateInterfaceHdr.hpp new file mode 100644 index 0000000..a0887e3 --- /dev/null +++ b/lib/parser/states/interface/StateInterfaceHdr.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_STATEINTERFACEHDR_HPP_ +#define PARSER_STATEINTERFACEHDR_HPP_ + +#include "lib/parser/states/base/StateBase.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class StateInterfaceHdr : public StateBase { +public: + std::string_view Name() const override; + StepResult TryStep(ContextParser& ctx, ITokenStream& ts) override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_STATEINTERFACEHDR_HPP_ diff --git a/lib/parser/tokens/SourceId.cpp b/lib/parser/tokens/SourceId.cpp new file mode 100644 index 0000000..5d6d911 --- /dev/null +++ b/lib/parser/tokens/SourceId.cpp @@ -0,0 +1,3 @@ +#include "SourceId.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/tokens/SourceId.hpp b/lib/parser/tokens/SourceId.hpp new file mode 100644 index 0000000..4d2dea3 --- /dev/null +++ b/lib/parser/tokens/SourceId.hpp @@ -0,0 +1,30 @@ +#ifndef PARSER_SOURCEID_HPP_ +#define PARSER_SOURCEID_HPP_ + +#include +#include +#include + +namespace ovum::compiler::parser { + +class SourceId { +public: + SourceId() = default; + explicit SourceId(std::string path) : path_(std::move(path)) { + } + + [[nodiscard]] std::string_view Path() const noexcept; + + [[nodiscard]] std::string Basename() const; + + [[nodiscard]] bool IsValid() const noexcept; + [[nodiscard]] bool operator==(const SourceId& other) const noexcept; + [[nodiscard]] bool operator!=(const SourceId& other) const noexcept; + +private: + std::string path_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_SOURCEID_HPP_ diff --git a/lib/parser/tokens/SourceSpan.cpp b/lib/parser/tokens/SourceSpan.cpp new file mode 100644 index 0000000..742d499 --- /dev/null +++ b/lib/parser/tokens/SourceSpan.cpp @@ -0,0 +1,3 @@ +#include "SourceSpan.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/tokens/SourceSpan.hpp b/lib/parser/tokens/SourceSpan.hpp new file mode 100644 index 0000000..cac2607 --- /dev/null +++ b/lib/parser/tokens/SourceSpan.hpp @@ -0,0 +1,33 @@ +#ifndef PARSER_SOURCESPAN_HPP_ +#define PARSER_SOURCESPAN_HPP_ + +#include + +#include "SourceId.hpp" + +namespace ovum::compiler::parser { + +class SourceSpan { +public: + SourceSpan() = default; + SourceSpan(SourceId id, TokenPosition start, TokenPosition end); + + [[nodiscard]] const SourceId& GetSourceId() const noexcept; + [[nodiscard]] TokenPosition GetStart() const noexcept; + [[nodiscard]] TokenPosition GetEnd() const noexcept; + + [[nodiscard]] bool IsValid() const noexcept; + void Normalize() noexcept; + [[nodiscard]] static SourceSpan SinglePoint(SourceId id, TokenPosition p); + + [[nodiscard]] static SourceSpan Union(const SourceSpan& a, const SourceSpan& b); + +private: + SourceId id_; + TokenPosition begin_{}; + TokenPosition end_{}; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_SOURCESPAN_HPP_ diff --git a/lib/parser/tokens/token_streams/ITokenStream.hpp b/lib/parser/tokens/token_streams/ITokenStream.hpp new file mode 100644 index 0000000..37eaeba --- /dev/null +++ b/lib/parser/tokens/token_streams/ITokenStream.hpp @@ -0,0 +1,27 @@ +#ifndef PARSER_ITOKENSTREAM_HPP_ +#define PARSER_ITOKENSTREAM_HPP_ + +#include + +#include + +namespace ovum::compiler::parser { + +class ITokenStream { +public: + virtual ~ITokenStream() = default; + + virtual const Token& Peek(size_t k = 0) = 0; + virtual TokenPtr Consume() = 0; + + virtual size_t Position() const = 0; + virtual void Rewind(size_t n) = 0; + virtual bool IsEof() const = 0; + + virtual const Token* LastConsumed() const = 0; + virtual const Token* TryPeek(size_t k = 0) = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_ITOKENSTREAM_HPP_ diff --git a/lib/parser/tokens/token_streams/VectorTokenStream.cpp b/lib/parser/tokens/token_streams/VectorTokenStream.cpp new file mode 100644 index 0000000..6fafb4f --- /dev/null +++ b/lib/parser/tokens/token_streams/VectorTokenStream.cpp @@ -0,0 +1,74 @@ +#include "lib/parser/tokens/token_streams/VectorTokenStream.hpp" + +#include +#include + +namespace ovum::compiler::parser { + +VectorTokenStream::VectorTokenStream(std::vector tokens) : tokens_(std::move(tokens)) { +} + +const Token& VectorTokenStream::Peek(size_t k) { + const Token* token = TryPeek(k); + + if (token != nullptr) { + return *token; + } + + if (last_ != nullptr) { + return *last_; + } + + if (!tokens_.empty()) { + return *tokens_.back(); + } + + throw std::out_of_range("VectorTokenStream::Peek out of range"); +} + +TokenPtr VectorTokenStream::Consume() { + if (index_ < tokens_.size()) { + last_ = tokens_[index_].get(); + return std::move(tokens_[index_++]); + } + + last_ = nullptr; + return nullptr; +} + +size_t VectorTokenStream::Position() const { + return index_; +} + +void VectorTokenStream::Rewind(size_t n) { + if (n > index_) { + index_ = 0; + } else { + index_ -= n; + } + + last_ = nullptr; +} + +bool VectorTokenStream::IsEof() const { + return index_ >= tokens_.size(); +} + +const Token* VectorTokenStream::LastConsumed() const { + return last_; +} + +const Token* VectorTokenStream::TryPeek(size_t k) { + const size_t pos = index_ + k; + if (pos < tokens_.size()) { + return tokens_[pos].get(); + } + + return nullptr; +} + +size_t VectorTokenStream::Size() const { + return tokens_.size(); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/tokens/token_streams/VectorTokenStream.hpp b/lib/parser/tokens/token_streams/VectorTokenStream.hpp new file mode 100644 index 0000000..a5caae6 --- /dev/null +++ b/lib/parser/tokens/token_streams/VectorTokenStream.hpp @@ -0,0 +1,42 @@ +#ifndef PARSER_VECTORTOKENSTREAM_HPP_ +#define PARSER_VECTORTOKENSTREAM_HPP_ + +#include +#include +#include + +#include + +#include "ITokenStream.hpp" + +namespace ovum::compiler::parser { + +class VectorTokenStream : public ITokenStream { +public: + explicit VectorTokenStream(std::vector tokens); + + const Token& Peek(size_t k = 0) override; + + TokenPtr Consume() override; + + size_t Position() const override; + + void Rewind(size_t n) override; + + bool IsEof() const override; + + const Token* LastConsumed() const override; + + const Token* TryPeek(size_t k = 0) override; + + size_t Size() const; + +private: + std::vector tokens_; + size_t index_ = 0; + const Token* last_ = nullptr; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_VECTORTOKENSTREAM_HPP_ diff --git a/lib/parser/tokens/token_traits/ITokenMatcher.hpp b/lib/parser/tokens/token_traits/ITokenMatcher.hpp new file mode 100644 index 0000000..ed22b1f --- /dev/null +++ b/lib/parser/tokens/token_traits/ITokenMatcher.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_ITOKENMATCHER_HPP_ +#define PARSER_ITOKENMATCHER_HPP_ + +#include + +namespace ovum::compiler::parser { + +class ITokenMatcher { +public: + virtual ~ITokenMatcher() = default; + + virtual bool Match(const Token& t) const = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_ITOKENMATCHER_HPP_ diff --git a/lib/parser/tokens/token_traits/MatchIdentifier.cpp b/lib/parser/tokens/token_traits/MatchIdentifier.cpp new file mode 100644 index 0000000..fb49f8b --- /dev/null +++ b/lib/parser/tokens/token_traits/MatchIdentifier.cpp @@ -0,0 +1,3 @@ +#include "MatchIdentifier.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/tokens/token_traits/MatchIdentifier.hpp b/lib/parser/tokens/token_traits/MatchIdentifier.hpp new file mode 100644 index 0000000..2719634 --- /dev/null +++ b/lib/parser/tokens/token_traits/MatchIdentifier.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_MATCHIDENTIFIER_HPP_ +#define PARSER_MATCHIDENTIFIER_HPP_ + +#include + +#include "ITokenMatcher.hpp" + +namespace ovum::compiler::parser { + +class MatchIdentifier : public ITokenMatcher { +public: + bool Match(const Token& tok) const override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_MATCHIDENTIFIER_HPP_ diff --git a/lib/parser/tokens/token_traits/MatchLexeme.cpp b/lib/parser/tokens/token_traits/MatchLexeme.cpp new file mode 100644 index 0000000..e6866c2 --- /dev/null +++ b/lib/parser/tokens/token_traits/MatchLexeme.cpp @@ -0,0 +1,3 @@ +#include "MatchLexeme.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/tokens/token_traits/MatchLexeme.hpp b/lib/parser/tokens/token_traits/MatchLexeme.hpp new file mode 100644 index 0000000..5b1f783 --- /dev/null +++ b/lib/parser/tokens/token_traits/MatchLexeme.hpp @@ -0,0 +1,24 @@ +#ifndef PARSER_MATCHLEXEME_HPP_ +#define PARSER_MATCHLEXEME_HPP_ + +#include + +#include + +#include "ITokenMatcher.hpp" + +namespace ovum::compiler::parser { + +class MatchLexeme : public ITokenMatcher { +public: + explicit MatchLexeme(std::string_view lexeme); + + bool Match(const Token& tok) const override; + +private: + std::string_view lexeme_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_MATCHLEXEME_HPP_ diff --git a/lib/parser/tokens/token_traits/MatchLiteral.cpp b/lib/parser/tokens/token_traits/MatchLiteral.cpp new file mode 100644 index 0000000..ceaff66 --- /dev/null +++ b/lib/parser/tokens/token_traits/MatchLiteral.cpp @@ -0,0 +1,3 @@ +#include "MatchLiteral.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/tokens/token_traits/MatchLiteral.hpp b/lib/parser/tokens/token_traits/MatchLiteral.hpp new file mode 100644 index 0000000..2cd5959 --- /dev/null +++ b/lib/parser/tokens/token_traits/MatchLiteral.hpp @@ -0,0 +1,17 @@ +#ifndef PARSER_MATCHLITERAL_HPP_ +#define PARSER_MATCHLITERAL_HPP_ + +#include + +#include "ITokenMatcher.hpp" + +namespace ovum::compiler::parser { + +class MatchLiteral : public ITokenMatcher { +public: + bool Match(const Token& tok) const override; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_MATCHLITERAL_HPP_ diff --git a/lib/parser/tokens/token_traits/MatchManyOf.cpp b/lib/parser/tokens/token_traits/MatchManyOf.cpp new file mode 100644 index 0000000..8f2fb8c --- /dev/null +++ b/lib/parser/tokens/token_traits/MatchManyOf.cpp @@ -0,0 +1,3 @@ +#include "MatchManyOf.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/tokens/token_traits/MatchManyOf.hpp b/lib/parser/tokens/token_traits/MatchManyOf.hpp new file mode 100644 index 0000000..adfecaf --- /dev/null +++ b/lib/parser/tokens/token_traits/MatchManyOf.hpp @@ -0,0 +1,25 @@ +#ifndef PARSER_MATCHMANYOF_HPP_ +#define PARSER_MATCHMANYOF_HPP_ + +#include +#include + +#include + +#include "ITokenMatcher.hpp" + +namespace ovum::compiler::parser { + +class MatchAnyOf : public ITokenMatcher { +public: + explicit MatchAnyOf(std::vector> ms); + + bool Match(const Token& tok) const override; + +private: + std::vector> ms_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_MATCHMANYOF_HPP_ diff --git a/lib/parser/tokens/token_traits/MatchType.cpp b/lib/parser/tokens/token_traits/MatchType.cpp new file mode 100644 index 0000000..413410a --- /dev/null +++ b/lib/parser/tokens/token_traits/MatchType.cpp @@ -0,0 +1,3 @@ +#include "MatchType.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/tokens/token_traits/MatchType.hpp b/lib/parser/tokens/token_traits/MatchType.hpp new file mode 100644 index 0000000..3554129 --- /dev/null +++ b/lib/parser/tokens/token_traits/MatchType.hpp @@ -0,0 +1,24 @@ +#ifndef PARSER_MATCHTYPE_HPP_ +#define PARSER_MATCHTYPE_HPP_ + +#include + +#include + +#include "ITokenMatcher.hpp" + +namespace ovum::compiler::parser { + +class MatchType : public ITokenMatcher { +public: + explicit MatchType(std::string_view type_name); + + bool Match(const Token& tok) const override; + +private: + std::string_view type_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_MATCHTYPE_HPP_ diff --git a/lib/parser/type_parser/ITypeParser.hpp b/lib/parser/type_parser/ITypeParser.hpp new file mode 100644 index 0000000..fabbbd9 --- /dev/null +++ b/lib/parser/type_parser/ITypeParser.hpp @@ -0,0 +1,20 @@ +#ifndef PARSER_ITYPEPARSER_HPP_ +#define PARSER_ITYPEPARSER_HPP_ + +#include + +#include "lib/parser/diagnostics/IDiagnosticSink.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class ITypeParser { +public: + virtual ~ITypeParser() = default; + virtual std::unique_ptr ParseType(ITokenStream& ts, IDiagnosticSink& diags) = 0; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_ITYPEPARSER_HPP_ diff --git a/lib/parser/type_parser/QNameTypeParser.cpp b/lib/parser/type_parser/QNameTypeParser.cpp new file mode 100644 index 0000000..dbcb469 --- /dev/null +++ b/lib/parser/type_parser/QNameTypeParser.cpp @@ -0,0 +1,3 @@ +#include "QNameTypeParser.hpp" + +namespace ovum::compiler::parser {} // namespace ovum::compiler::parser diff --git a/lib/parser/type_parser/QNameTypeParser.hpp b/lib/parser/type_parser/QNameTypeParser.hpp new file mode 100644 index 0000000..f54cbed --- /dev/null +++ b/lib/parser/type_parser/QNameTypeParser.hpp @@ -0,0 +1,33 @@ +#ifndef PARSER_QNAMETYPEPARSER_HPP_ +#define PARSER_QNAMETYPEPARSER_HPP_ + +#include + +#include "ITypeParser.hpp" +#include "lib/parser/ast/IAstFactory.hpp" +#include "lib/parser/diagnostics/IDiagnosticSink.hpp" +#include "lib/parser/tokens/token_streams/ITokenStream.hpp" +#include "lib/parser/types/TypeReference.hpp" + +namespace ovum::compiler::parser { + +class QNameTypeParser final : public ITypeParser { +public: + explicit QNameTypeParser(IAstFactory& factory) noexcept; + ~QNameTypeParser() override = default; + + [[nodiscard]] std::unique_ptr ParseType(ITokenStream& ts, IDiagnosticSink& diags) override; + + QNameTypeParser(const QNameTypeParser&) = delete; + QNameTypeParser& operator=(const QNameTypeParser&) = delete; + + QNameTypeParser(QNameTypeParser&&) noexcept = default; + QNameTypeParser& operator=(QNameTypeParser&&) noexcept = delete; + +private: + std::shared_ptr factory_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_QNAMETYPEPARSER_HPP_ diff --git a/lib/parser/types/Nullable.cpp b/lib/parser/types/Nullable.cpp new file mode 100644 index 0000000..b231e1b --- /dev/null +++ b/lib/parser/types/Nullable.cpp @@ -0,0 +1,24 @@ +#include "Nullable.hpp" + +namespace ovum::compiler::parser { + +Nullable::Nullable(bool on) noexcept : on_(on) { +} + +bool Nullable::IsOn() const noexcept { + return on_; +} + +void Nullable::Set(bool on) noexcept { + on_ = on; +} + +void Nullable::Enable() noexcept { + on_ = true; +} + +void Nullable::Disable() noexcept { + on_ = false; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/types/Nullable.hpp b/lib/parser/types/Nullable.hpp new file mode 100644 index 0000000..ffc8c3e --- /dev/null +++ b/lib/parser/types/Nullable.hpp @@ -0,0 +1,26 @@ +#ifndef PARSER_NULLABLE_HPP_ +#define PARSER_NULLABLE_HPP_ + +namespace ovum::compiler::parser { + +class Nullable { +public: + Nullable() noexcept = default; + + explicit Nullable(bool on) noexcept; + + bool IsOn() const noexcept; + + void Set(bool on) noexcept; + + void Enable() noexcept; + + void Disable() noexcept; + +private: + bool on_ = false; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_NULLABLE_HPP_ diff --git a/lib/parser/types/Param.cpp b/lib/parser/types/Param.cpp new file mode 100644 index 0000000..bef600d --- /dev/null +++ b/lib/parser/types/Param.cpp @@ -0,0 +1,17 @@ +#include "lib/parser/types/Param.hpp" + +namespace ovum::compiler::parser { + +Param::Param(std::string name, TypeReference typeReference) : + name_(std::move(name)), reference_(std::move(typeReference)) { +} + +std::string Param::GetName() { + return name_; +} + +TypeReference Param::GetType() { + return reference_; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/types/Param.hpp b/lib/parser/types/Param.hpp new file mode 100644 index 0000000..8fd2c52 --- /dev/null +++ b/lib/parser/types/Param.hpp @@ -0,0 +1,25 @@ +#ifndef PARSER_PARAM_HPP_ +#define PARSER_PARAM_HPP_ + +#include + +#include "TypeReference.hpp" + +namespace ovum::compiler::parser { + +class Param { +public: + Param(std::string name, TypeReference typeReference); + + [[nodiscard]] std::string GetName(); + + [[nodiscard]] TypeReference GetType(); + +private: + std::string name_; + TypeReference reference_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_PARAM_HPP_ diff --git a/lib/parser/types/ResolvedTypeHandle.cpp b/lib/parser/types/ResolvedTypeHandle.cpp new file mode 100644 index 0000000..b228d66 --- /dev/null +++ b/lib/parser/types/ResolvedTypeHandle.cpp @@ -0,0 +1,27 @@ +#include "lib/parser/types/ResolvedTypeHandle.hpp" + +#include + +namespace ovum::compiler::parser { + +ResolvedTypeHandle::ResolvedTypeHandle(const void* decl, std::string mangled, bool is_interface) : + decl_(decl), mangled_(std::move(mangled)), is_interface_(is_interface) { +} + +const void* ResolvedTypeHandle::Decl() const noexcept { + return decl_; +} + +std::string_view ResolvedTypeHandle::Mangled() const noexcept { + return mangled_; +} + +bool ResolvedTypeHandle::IsInterface() const noexcept { + return is_interface_; +} + +bool ResolvedTypeHandle::IsValid() const noexcept { + return decl_ != nullptr; +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/types/ResolvedTypeHandle.hpp b/lib/parser/types/ResolvedTypeHandle.hpp new file mode 100644 index 0000000..74b9f57 --- /dev/null +++ b/lib/parser/types/ResolvedTypeHandle.hpp @@ -0,0 +1,33 @@ +#ifndef PARSER_RESOLVEDTYPEHANDLE_HPP_ +#define PARSER_RESOLVEDTYPEHANDLE_HPP_ + +#include + +namespace ovum::compiler::parser { + +class ResolvedTypeHandle { +public: + ResolvedTypeHandle() = default; + ResolvedTypeHandle(const void* decl, std::string mangled, bool is_interface); + + ResolvedTypeHandle(const ResolvedTypeHandle& other) = default; + ResolvedTypeHandle(ResolvedTypeHandle&& other) noexcept = default; + ~ResolvedTypeHandle() = default; + + ResolvedTypeHandle& operator=(const ResolvedTypeHandle& other) = default; + ResolvedTypeHandle& operator=(ResolvedTypeHandle&& other) noexcept = default; + + const void* Decl() const noexcept; + std::string_view Mangled() const noexcept; + bool IsInterface() const noexcept; + bool IsValid() const noexcept; + +private: + const void* decl_ = nullptr; + std::string mangled_; + bool is_interface_ = false; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_RESOLVEDTYPEHANDLE_HPP_ diff --git a/lib/parser/types/TypeReference.cpp b/lib/parser/types/TypeReference.cpp new file mode 100644 index 0000000..9e5bfc2 --- /dev/null +++ b/lib/parser/types/TypeReference.cpp @@ -0,0 +1,258 @@ +#include "lib/parser/types/TypeReference.hpp" + +#include +#include +#include +#include + +namespace ovum::compiler::parser { + +TypeReference::TypeReference() = default; + +TypeReference::TypeReference(std::string name) { + qname_.clear(); + qname_.push_back(std::move(name)); +} + +TypeReference::TypeReference(std::vector qname) : qname_(std::move(qname)) { +} + +TypeReference::TypeReference(const TypeReference& ref) : + qname_(ref.qname_), type_args_(ref.type_args_), nullable_(ref.nullable_) { + if (ref.resolved_) { + resolved_ = std::make_unique(*ref.resolved_); + } +} + +TypeReference::TypeReference(TypeReference&& ref) noexcept : + qname_(std::move(ref.qname_)), type_args_(std::move(ref.type_args_)), nullable_(ref.nullable_), + resolved_(std::move(ref.resolved_)) { +} + +TypeReference::~TypeReference() = default; + +TypeReference& TypeReference::operator=(const TypeReference& ref) { + if (this == &ref) { + return *this; + } + + qname_ = ref.qname_; + type_args_ = ref.type_args_; + nullable_ = ref.nullable_; + + if (ref.resolved_) { + resolved_ = std::make_unique(*ref.resolved_); + } else { + resolved_.reset(); + } + + return *this; +} + +TypeReference& TypeReference::operator=(TypeReference&& ref) noexcept { + if (this == &ref) { + return *this; + } + + qname_ = std::move(ref.qname_); + type_args_ = std::move(ref.type_args_); + nullable_ = ref.nullable_; + resolved_ = std::move(ref.resolved_); + return *this; +} + +TypeReference& TypeReference::operator=(std::string name) { + qname_.clear(); + qname_.push_back(std::move(name)); + InvalidateResolution(); + return *this; +} + +bool TypeReference::StructurallyEquals(const TypeReference& other) const noexcept { + if (nullable_.IsOn() != other.nullable_.IsOn()) { + return false; + } + + if (qname_ != other.qname_) { + return false; + } + + if (type_args_.size() != other.type_args_.size()) { + return false; + } + + for (std::size_t i = 0; i < type_args_.size(); ++i) { + if (!type_args_[i].StructurallyEquals(other.type_args_[i])) { + return false; + } + } + return true; +} + +std::string TypeReference::StableKey() const { + std::ostringstream out; + out << JoinQualified(qname_); + if (!type_args_.empty()) { + out << '<' << ArgsToString(type_args_) << '>'; + } + + if (nullable_.IsOn()) { + out << '?'; + } + + return out.str(); +} + +std::string TypeReference::ToStringHuman() const { + return StableKey(); +} + +const std::vector& TypeReference::QualifiedName() const noexcept { + return qname_; +} + +std::string_view TypeReference::SimpleName() const noexcept { + if (qname_.empty()) { + return {}; + } + + return qname_.back(); +} + +void TypeReference::SetQualifiedName(std::vector qname) { + qname_ = std::move(qname); + InvalidateResolution(); +} + +void TypeReference::SetSimpleName(std::string name) { + if (qname_.empty()) { + qname_.push_back(std::move(name)); + } else { + qname_.back() = std::move(name); + } + + InvalidateResolution(); +} + +void TypeReference::PushQualifier(std::string qualifier) { + qname_.push_back(std::move(qualifier)); + InvalidateResolution(); +} + +bool TypeReference::PopFrontQualifier() { + if (qname_.empty()) { + return false; + } + + qname_.erase(qname_.begin()); + InvalidateResolution(); + return true; +} + +bool TypeReference::PopBackQualifier() { + if (qname_.empty()) { + return false; + } + + qname_.pop_back(); + InvalidateResolution(); + return true; +} + +const std::vector& TypeReference::TypeArguments() const noexcept { + return type_args_; +} + +std::vector& TypeReference::MutableTypeArguments() noexcept { + return type_args_; +} + +void TypeReference::ClearTypeArguments() { + type_args_.clear(); + InvalidateResolution(); +} + +void TypeReference::AddTypeArgument(TypeReference arg) { + type_args_.emplace_back(std::move(arg)); + InvalidateResolution(); +} + +std::size_t TypeReference::Arity() const noexcept { + return type_args_.size(); +} + +const Nullable& TypeReference::Nullability() const noexcept { + return nullable_; +} + +bool TypeReference::IsNullable() const noexcept { + return nullable_.IsOn(); +} + +void TypeReference::SetNullable(bool on) noexcept { + nullable_.Set(on); +} + +void TypeReference::MakeNullable() noexcept { + nullable_.Enable(); +} + +void TypeReference::MakeNonNullable() noexcept { + nullable_.Disable(); +} + +TypeReference TypeReference::WithoutNullable() const { + TypeReference copy{*this}; + copy.MakeNonNullable(); + copy.InvalidateResolution(); + return copy; +} + +bool TypeReference::IsResolved() const noexcept { + return static_cast(resolved_); +} + +const ResolvedTypeHandle* TypeReference::Resolved() const noexcept { + return resolved_ ? resolved_.get() : nullptr; +} + +void TypeReference::SetResolvedHandle(const void* decl, std::string mangled, bool is_interface) { + resolved_ = std::make_unique(decl, std::move(mangled), is_interface); +} + +void TypeReference::ResetResolvedHandle() noexcept { + resolved_.reset(); +} + +std::string TypeReference::JoinQualified(const std::vector& parts) { + if (parts.empty()) { + return {}; + } + + std::ostringstream out; + for (std::size_t i = 0; i < parts.size(); ++i) { + if (i) { + out << "."; + } + out << parts[i]; + } + return out.str(); +} + +std::string TypeReference::ArgsToString(const std::vector& args) { + std::ostringstream out; + for (std::size_t i = 0; i < args.size(); ++i) { + if (i) { + out << ", "; + } + + out << args[i].StableKey(); + } + return out.str(); +} + +void TypeReference::InvalidateResolution() noexcept { + resolved_.reset(); +} + +} // namespace ovum::compiler::parser diff --git a/lib/parser/types/TypeReference.hpp b/lib/parser/types/TypeReference.hpp new file mode 100644 index 0000000..3aaf354 --- /dev/null +++ b/lib/parser/types/TypeReference.hpp @@ -0,0 +1,79 @@ +#ifndef PARSER_TYPEREFERENCE_HPP_ +#define PARSER_TYPEREFERENCE_HPP_ + +#include +#include +#include +#include + +#include "Nullable.hpp" +#include "ResolvedTypeHandle.hpp" + +namespace ovum::compiler::parser { + +class TypeReference { +public: + TypeReference(); + explicit TypeReference(std::string name); + explicit TypeReference(std::vector qname); + + TypeReference(const TypeReference& ref); + TypeReference(TypeReference&& ref) noexcept; + + ~TypeReference(); + + TypeReference& operator=(const TypeReference& ref); + TypeReference& operator=(TypeReference&& ref) noexcept; + + TypeReference& operator=(std::string name); + + bool StructurallyEquals(const TypeReference& other) const noexcept; + + std::string StableKey() const; + std::string ToStringHuman() const; + + const std::vector& QualifiedName() const noexcept; + std::string_view SimpleName() const noexcept; + + void SetQualifiedName(std::vector qname); + void SetSimpleName(std::string name); + void PushQualifier(std::string qualifier); + bool PopFrontQualifier(); + bool PopBackQualifier(); + + const std::vector& TypeArguments() const noexcept; + std::vector& MutableTypeArguments() noexcept; + + void ClearTypeArguments(); + void AddTypeArgument(TypeReference arg); + std::size_t Arity() const noexcept; + + const Nullable& Nullability() const noexcept; + bool IsNullable() const noexcept; + void SetNullable(bool on) noexcept; + void MakeNullable() noexcept; + void MakeNonNullable() noexcept; + + TypeReference WithoutNullable() const; + + bool IsResolved() const noexcept; + const ResolvedTypeHandle* Resolved() const noexcept; + + void SetResolvedHandle(const void* decl, std::string mangled, bool is_interface); + void ResetResolvedHandle() noexcept; + +private: + static std::string JoinQualified(const std::vector& parts); + static std::string ArgsToString(const std::vector& args); + + void InvalidateResolution() noexcept; + + std::vector qname_; + std::vector type_args_; + Nullable nullable_; + std::unique_ptr resolved_; +}; + +} // namespace ovum::compiler::parser + +#endif // PARSER_TYPEREFERENCE_HPP_