Initial Parser Implementation and Feature Completion #1
@ -50,35 +50,60 @@ namespace arti::lang::ast {
|
|||||||
Optional,
|
Optional,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class UnaryOperator {
|
enum class PrefixOperator {
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
Not,
|
Not,
|
||||||
Minus,
|
Minus,
|
||||||
BitNot,
|
BitNot,
|
||||||
Ampersand,
|
MemPtr,
|
||||||
Star,
|
DerefPtr,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class BinaryOperator {
|
enum class InfixOperator {
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
|
Modulo,
|
||||||
|
Addition,
|
||||||
|
Substraction,
|
||||||
|
Division,
|
||||||
|
Multiplication,
|
||||||
Equal,
|
Equal,
|
||||||
NotEqual,
|
NotEqual,
|
||||||
GreaterThan,
|
|
||||||
LessThan,
|
LessThan,
|
||||||
GreaterEqual,
|
GreaterThan,
|
||||||
LessEqual,
|
LessEqual,
|
||||||
BitAnd,
|
GreaterEqual,
|
||||||
BitXor,
|
|
||||||
BitOr,
|
|
||||||
LeftShift,
|
LeftShift,
|
||||||
RightShift,
|
RightShift,
|
||||||
Adition,
|
|
||||||
Substraction,
|
|
||||||
Multiplication,
|
|
||||||
Division,
|
|
||||||
Modulo,
|
|
||||||
BoolAnd,
|
BoolAnd,
|
||||||
BoolOr,
|
BoolOr,
|
||||||
|
BitAnd,
|
||||||
|
BitOr,
|
||||||
|
BitXor,
|
||||||
|
Assignment,
|
||||||
|
ModuleAccess,
|
||||||
|
MemberAccess,
|
||||||
|
PointerMemberAccess,
|
||||||
|
AdditionAssignment,
|
||||||
|
SubstractionAssignment,
|
||||||
|
MultiplicationAssignment,
|
||||||
|
DivisionAssignment,
|
||||||
|
ModuloAssignment,
|
||||||
|
BitAndAssignment,
|
||||||
|
BitOrAssignment,
|
||||||
|
LShiftAssignment,
|
||||||
|
RShiftAssignment,
|
||||||
|
BoolAndAssignment,
|
||||||
|
BoolOrAssignment,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class PostfixOperator {
|
||||||
|
Uninitialized,
|
||||||
|
FunctionCall,
|
||||||
|
SliceAccess,
|
||||||
|
SliceSize,
|
||||||
|
PtrToSlice,
|
||||||
|
SliceToPtr,
|
||||||
|
Reflect,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class CompoundAssignOperator {
|
enum class CompoundAssignOperator {
|
||||||
|
|||||||
@ -32,8 +32,8 @@ namespace arti::lang::ast {
|
|||||||
|
|
||||||
/* Main declaration node types */
|
/* Main declaration node types */
|
||||||
struct IdentifierExpression;
|
struct IdentifierExpression;
|
||||||
struct UnaryExpression;
|
struct PrefixExpression;
|
||||||
struct BinaryExpression;
|
struct InfixExpression;
|
||||||
struct AssignExpression;
|
struct AssignExpression;
|
||||||
struct CompoundAssignExpression;
|
struct CompoundAssignExpression;
|
||||||
struct FunctionCallExpression;
|
struct FunctionCallExpression;
|
||||||
@ -41,7 +41,7 @@ namespace arti::lang::ast {
|
|||||||
struct SliceRangeExpression;
|
struct SliceRangeExpression;
|
||||||
struct MemberAccessExpression;
|
struct MemberAccessExpression;
|
||||||
struct PointerAccessExpression;
|
struct PointerAccessExpression;
|
||||||
struct ScopeAccessExpression;
|
struct ModuleAccessExpression;
|
||||||
struct ReflectionExpression;
|
struct ReflectionExpression;
|
||||||
struct SliceCreationExpression;
|
struct SliceCreationExpression;
|
||||||
struct SliceLengthExpression;
|
struct SliceLengthExpression;
|
||||||
@ -51,8 +51,8 @@ namespace arti::lang::ast {
|
|||||||
|
|
||||||
/* Public Aliases */
|
/* Public Aliases */
|
||||||
using IdentifierExprNode = Ptr<nodes::IdentifierExpression>;
|
using IdentifierExprNode = Ptr<nodes::IdentifierExpression>;
|
||||||
using UnaryExprNode = Ptr<nodes::UnaryExpression>;
|
using PrefixExprNode = Ptr<nodes::PrefixExpression>;
|
||||||
using BinaryExprNode = Ptr<nodes::BinaryExpression>;
|
using InfixExprNode = Ptr<nodes::InfixExpression>;
|
||||||
using AssignExprNode = Ptr<nodes::AssignExpression>;
|
using AssignExprNode = Ptr<nodes::AssignExpression>;
|
||||||
using CompoundAssignExprNode = Ptr<nodes::CompoundAssignExpression>;
|
using CompoundAssignExprNode = Ptr<nodes::CompoundAssignExpression>;
|
||||||
using FunctionCallExprNode = Ptr<nodes::FunctionCallExpression>;
|
using FunctionCallExprNode = Ptr<nodes::FunctionCallExpression>;
|
||||||
@ -60,7 +60,7 @@ namespace arti::lang::ast {
|
|||||||
using SliceRangeExprNode = Ptr<nodes::SliceRangeExpression>;
|
using SliceRangeExprNode = Ptr<nodes::SliceRangeExpression>;
|
||||||
using MemberAccessExprNode = Ptr<nodes::MemberAccessExpression>;
|
using MemberAccessExprNode = Ptr<nodes::MemberAccessExpression>;
|
||||||
using PointerAccessExprNode = Ptr<nodes::PointerAccessExpression>;
|
using PointerAccessExprNode = Ptr<nodes::PointerAccessExpression>;
|
||||||
using ScopeAccessExprNode = Ptr<nodes::ScopeAccessExpression>;
|
using ModuleAccessExprNode = Ptr<nodes::ModuleAccessExpression>;
|
||||||
using ReflectionExprNode = Ptr<nodes::ReflectionExpression>;
|
using ReflectionExprNode = Ptr<nodes::ReflectionExpression>;
|
||||||
using SliceCreationExprNode = Ptr<nodes::SliceCreationExpression>;
|
using SliceCreationExprNode = Ptr<nodes::SliceCreationExpression>;
|
||||||
using SliceLengthExprNode = Ptr<nodes::SliceLengthExpression>;
|
using SliceLengthExprNode = Ptr<nodes::SliceLengthExpression>;
|
||||||
@ -77,8 +77,8 @@ namespace arti::lang::ast {
|
|||||||
StructLtrlNode,
|
StructLtrlNode,
|
||||||
SliceLtrlNode,
|
SliceLtrlNode,
|
||||||
IdentifierExprNode,
|
IdentifierExprNode,
|
||||||
UnaryExprNode,
|
PrefixExprNode,
|
||||||
BinaryExprNode,
|
InfixExprNode,
|
||||||
AssignExprNode,
|
AssignExprNode,
|
||||||
CompoundAssignExprNode,
|
CompoundAssignExprNode,
|
||||||
FunctionCallExprNode,
|
FunctionCallExprNode,
|
||||||
@ -86,7 +86,7 @@ namespace arti::lang::ast {
|
|||||||
SliceRangeExprNode,
|
SliceRangeExprNode,
|
||||||
MemberAccessExprNode,
|
MemberAccessExprNode,
|
||||||
PointerAccessExprNode,
|
PointerAccessExprNode,
|
||||||
ScopeAccessExprNode,
|
ModuleAccessExprNode,
|
||||||
SliceCreationExprNode,
|
SliceCreationExprNode,
|
||||||
SliceLengthExprNode,
|
SliceLengthExprNode,
|
||||||
SlicePtrExprNode,
|
SlicePtrExprNode,
|
||||||
@ -99,16 +99,16 @@ namespace arti::lang::ast {
|
|||||||
String identifierName;
|
String identifierName;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nodes::UnaryExpression {
|
struct nodes::PrefixExpression {
|
||||||
SourceLocation location;
|
SourceLocation location;
|
||||||
UnaryOperator op;
|
PrefixOperator op;
|
||||||
ExpressionNode right;
|
ExpressionNode right;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nodes::BinaryExpression {
|
struct nodes::InfixExpression {
|
||||||
SourceLocation location;
|
SourceLocation location;
|
||||||
|
|
||||||
BinaryOperator op;
|
InfixOperator op;
|
||||||
ExpressionNode left;
|
ExpressionNode left;
|
||||||
ExpressionNode right;
|
ExpressionNode right;
|
||||||
};
|
};
|
||||||
@ -164,7 +164,7 @@ namespace arti::lang::ast {
|
|||||||
ExpressionNode object;
|
ExpressionNode object;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nodes::ScopeAccessExpression {
|
struct nodes::ModuleAccessExpression {
|
||||||
SourceLocation location;
|
SourceLocation location;
|
||||||
|
|
||||||
String memberName;
|
String memberName;
|
||||||
|
|||||||
@ -167,7 +167,40 @@ namespace arti::lang {
|
|||||||
parseExpressionStatement();
|
parseExpressionStatement();
|
||||||
|
|
||||||
Expected<ast::ExpressionNode>
|
Expected<ast::ExpressionNode>
|
||||||
parseExpression();
|
parseExpression(std::uint16_t p = 0);
|
||||||
|
|
||||||
|
Expected<ast::Optional<ast::ExpressionNode>>
|
||||||
|
parsePrimaryExpression();
|
||||||
|
|
||||||
|
Expected<ast::ExpressionNode>
|
||||||
|
parsePrefixExpression();
|
||||||
|
|
||||||
|
Expected<ast::ExpressionNode>
|
||||||
|
parseInfixExpression(ast::ExpressionNode lhs);
|
||||||
|
|
||||||
|
Expected<ast::ExpressionNode>
|
||||||
|
parsePostfixExpression(ast::ExpressionNode lhs);
|
||||||
|
|
||||||
|
Expected<ast::IdentifierExprNode>
|
||||||
|
parseIdentifierExpression();
|
||||||
|
|
||||||
|
Expected<ast::CharLtrlNode>
|
||||||
|
parseCharLiteral();
|
||||||
|
|
||||||
|
Expected<ast::NullLtrlNode>
|
||||||
|
parseNullLiteral();
|
||||||
|
|
||||||
|
Expected<ast::StringLtrlNode>
|
||||||
|
parseStringLiteral();
|
||||||
|
|
||||||
|
Expected<ast::FloatLtrlNode>
|
||||||
|
parseFloatLiteral();
|
||||||
|
|
||||||
|
Expected<ast::IntegerLtrlNode>
|
||||||
|
parseIntegerLiteral();
|
||||||
|
|
||||||
|
Expected<ast::BooleanLtrlNode>
|
||||||
|
parseBooleanLiteral();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string unitName;
|
std::string unitName;
|
||||||
|
|||||||
48
lib/include/artichoke/Parser/Pratt.hpp
Normal file
48
lib/include/artichoke/Parser/Pratt.hpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
//============================================================================//
|
||||||
|
// //
|
||||||
|
// artichoke programming language //
|
||||||
|
// //
|
||||||
|
// Copyright (C) 2025 Erick Saul Guzman Ramos, whoami.artichoke.dev //
|
||||||
|
// //
|
||||||
|
// //
|
||||||
|
// This program is free software: you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU Affero General Public License as published //
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU Affero General Public License for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU Affero General Public License //
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
|
||||||
|
// //
|
||||||
|
//============================================================================//
|
||||||
|
|
||||||
|
#include <artichoke/Parser/Parser.hpp>
|
||||||
|
|
||||||
|
namespace arti::lang::pratt {
|
||||||
|
|
||||||
|
struct BindingPower {
|
||||||
|
std::uint16_t left;
|
||||||
|
std::uint16_t right;
|
||||||
|
};
|
||||||
|
|
||||||
|
ast::PostfixOperator getPostfixOperator(TokenV tokenType);
|
||||||
|
ast::PrefixOperator getPrefixOperator(TokenV tokenType);
|
||||||
|
ast::InfixOperator getInfixOperator(TokenV tokenType);
|
||||||
|
|
||||||
|
bool isPostfixOperator(TokenV tokenType);
|
||||||
|
bool isPrefixOperator(TokenV tokenType);
|
||||||
|
bool isInfixOperator(TokenV tokenType);
|
||||||
|
|
||||||
|
std::uint16_t postfixBindingPower(ast::PostfixOperator op);
|
||||||
|
std::uint16_t prefixBindingPower(ast::PrefixOperator op);
|
||||||
|
BindingPower infixBindingPower(ast::InfixOperator op);
|
||||||
|
|
||||||
|
bool isCompoundAssignOperator(ast::InfixOperator op);
|
||||||
|
|
||||||
|
ast::CompoundAssignOperator getCompoundOperatorType(ast::InfixOperator op);
|
||||||
|
|
||||||
|
}
|
||||||
@ -81,41 +81,57 @@ namespace arti::lang::ast {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Operator label helpers (matching AST.cpp)
|
// Operator label helpers (matching AST.cpp)
|
||||||
std::string toString(UnaryOperator op) {
|
std::string toString(PrefixOperator op) {
|
||||||
using enum UnaryOperator;
|
using enum PrefixOperator;
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Not: return "Not (!)";
|
case Not: return "Not (!)";
|
||||||
case Minus: return "Minus (-)";
|
case Minus: return "Minus (-)";
|
||||||
case BitNot: return "BitNot (~)";
|
case BitNot: return "BitNot (~)";
|
||||||
case Ampersand: return "Ampersand (&)";
|
case MemPtr: return "MemPtr (&)";
|
||||||
case Star: return "Star (*)";
|
case DerefPtr: return "DerefPtr (*)";
|
||||||
default: std::unreachable(); break;
|
default: std::unreachable(); break;
|
||||||
}
|
}
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString(BinaryOperator op) {
|
std::string toString(InfixOperator op) {
|
||||||
using enum BinaryOperator;
|
using enum InfixOperator;
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Equal: return "Equal (==)";
|
case Equal: return "Equal (==)";
|
||||||
case NotEqual: return "NotEqual (!=)";
|
case NotEqual: return "NotEqual (!=)";
|
||||||
case GreaterThan: return "GreaterThan (>)";
|
case GreaterThan: return "GreaterThan (>)";
|
||||||
case LessThan: return "LessThan (<)";
|
case LessThan: return "LessThan (<)";
|
||||||
case GreaterEqual: return "GreaterEqual (>=)";
|
case GreaterEqual: return "GreaterEqual (>=)";
|
||||||
case LessEqual: return "LessEqual (<=)";
|
case LessEqual: return "LessEqual (<=)";
|
||||||
case BitAnd: return "BitAnd (&)";
|
case BitAnd: return "BitAnd (&)";
|
||||||
case BitXor: return "BitXor (^)";
|
case BitXor: return "BitXor (^)";
|
||||||
case BitOr: return "BitOr (|)";
|
case BitOr: return "BitOr (|)";
|
||||||
case LeftShift: return "LeftShift (<<)";
|
case LeftShift: return "LeftShift (<<)";
|
||||||
case RightShift: return "RightShift (>>)";
|
case RightShift: return "RightShift (>>)";
|
||||||
case Adition: return "Adition (+)";
|
case Addition: return "Addition (+)";
|
||||||
case Substraction: return "Substraction (-)";
|
case Substraction: return "Substraction (-)";
|
||||||
case Multiplication: return "Multiplication (*)";
|
case Multiplication: return "Multiplication (*)";
|
||||||
case Division: return "Division (/)";
|
case Division: return "Division (/)";
|
||||||
case Modulo: return "Modulo (%)";
|
case Modulo: return "Modulo (%)";
|
||||||
case BoolAnd: return "BoolAnd (&&)";
|
case BoolAnd: return "BoolAnd (&&)";
|
||||||
case BoolOr: return "BoolOr (||)";
|
case BoolOr: return "BoolOr (||)";
|
||||||
default: std::unreachable(); break;
|
case Assignment: return "Assignment (=)";
|
||||||
|
case ModuleAccess: return "ModuleAccess (::)";
|
||||||
|
case MemberAccess: return "MemberAccess (.)";
|
||||||
|
case PointerMemberAccess: return "PointerMemberAccess (->)";
|
||||||
|
case AdditionAssignment: return "AdditionAssignment (+=)";
|
||||||
|
case SubstractionAssignment: return "SubstractionAssignment (-=)";
|
||||||
|
case MultiplicationAssignment: return "MultiplicationAssignment (*=)";
|
||||||
|
case DivisionAssignment: return "DivisionAssignment (/=)";
|
||||||
|
case ModuloAssignment: return "ModuloAssignment (%=)";
|
||||||
|
case BitAndAssignment: return "BitAndAssignment (&=)";
|
||||||
|
case BitOrAssignment: return "BitOrAssignment (|=)";
|
||||||
|
case BoolAndAssignment: return "BoolAndAssignment (&&=)";
|
||||||
|
case BoolOrAssignment: return "BoolOrAssignment (||=)";
|
||||||
|
case LShiftAssignment: return "LShiftAssignment (<<=)";
|
||||||
|
case RShiftAssignment: return "RShiftAssignment (>>=)";
|
||||||
|
|
||||||
|
default: std::unreachable(); break;
|
||||||
}
|
}
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
}
|
}
|
||||||
@ -172,8 +188,8 @@ namespace arti::lang::ast {
|
|||||||
std::string emit(const StructLtrlPositionalInitializerNode&, GraphBuilder&);
|
std::string emit(const StructLtrlPositionalInitializerNode&, GraphBuilder&);
|
||||||
std::string emit(const StructLtrlInitializerNode &, GraphBuilder &);
|
std::string emit(const StructLtrlInitializerNode &, GraphBuilder &);
|
||||||
std::string emit(const IdentifierExprNode &, GraphBuilder &);
|
std::string emit(const IdentifierExprNode &, GraphBuilder &);
|
||||||
std::string emit(const UnaryExprNode &, GraphBuilder &);
|
std::string emit(const PrefixExprNode &, GraphBuilder &);
|
||||||
std::string emit(const BinaryExprNode &, GraphBuilder &);
|
std::string emit(const InfixExprNode &, GraphBuilder &);
|
||||||
std::string emit(const AssignExprNode &, GraphBuilder &);
|
std::string emit(const AssignExprNode &, GraphBuilder &);
|
||||||
std::string emit(const CompoundAssignExprNode &, GraphBuilder &);
|
std::string emit(const CompoundAssignExprNode &, GraphBuilder &);
|
||||||
std::string emit(const FunctionCallExprNode &, GraphBuilder &);
|
std::string emit(const FunctionCallExprNode &, GraphBuilder &);
|
||||||
@ -181,7 +197,7 @@ namespace arti::lang::ast {
|
|||||||
std::string emit(const SliceRangeExprNode &, GraphBuilder &);
|
std::string emit(const SliceRangeExprNode &, GraphBuilder &);
|
||||||
std::string emit(const MemberAccessExprNode &, GraphBuilder &);
|
std::string emit(const MemberAccessExprNode &, GraphBuilder &);
|
||||||
std::string emit(const PointerAccessExprNode &, GraphBuilder &);
|
std::string emit(const PointerAccessExprNode &, GraphBuilder &);
|
||||||
std::string emit(const ScopeAccessExprNode &, GraphBuilder &);
|
std::string emit(const ModuleAccessExprNode &, GraphBuilder &);
|
||||||
std::string emit(const ReflectionExprNode &, GraphBuilder &);
|
std::string emit(const ReflectionExprNode &, GraphBuilder &);
|
||||||
std::string emit(const SliceCreationExprNode &, GraphBuilder &);
|
std::string emit(const SliceCreationExprNode &, GraphBuilder &);
|
||||||
std::string emit(const SliceLengthExprNode &, GraphBuilder &);
|
std::string emit(const SliceLengthExprNode &, GraphBuilder &);
|
||||||
@ -629,8 +645,8 @@ namespace arti::lang::ast {
|
|||||||
return g.makeNode(std::format("Identifier `{}`", node->identifierName));
|
return g.makeNode(std::format("Identifier `{}`", node->identifierName));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string emit(const UnaryExprNode &node, GraphBuilder &g) {
|
std::string emit(const PrefixExprNode &node, GraphBuilder &g) {
|
||||||
auto id = g.makeNode("UnaryExpression");
|
auto id = g.makeNode("PrefixExpression");
|
||||||
auto opLeaf = makeLeaf(g, toString(node->op));
|
auto opLeaf = makeLeaf(g, toString(node->op));
|
||||||
g.addEdge(id, opLeaf, "Operator");
|
g.addEdge(id, opLeaf, "Operator");
|
||||||
auto rhs = emit(node->right, g);
|
auto rhs = emit(node->right, g);
|
||||||
@ -638,8 +654,8 @@ namespace arti::lang::ast {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string emit(const BinaryExprNode &node, GraphBuilder &g) {
|
std::string emit(const InfixExprNode &node, GraphBuilder &g) {
|
||||||
auto id = g.makeNode("BinaryExpression");
|
auto id = g.makeNode("InfixExpression");
|
||||||
auto opLeaf = makeLeaf(g, toString(node->op));
|
auto opLeaf = makeLeaf(g, toString(node->op));
|
||||||
g.addEdge(id, opLeaf, "Operator");
|
g.addEdge(id, opLeaf, "Operator");
|
||||||
auto lhs = emit(node->left, g);
|
auto lhs = emit(node->left, g);
|
||||||
@ -709,7 +725,7 @@ namespace arti::lang::ast {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string emit(const ScopeAccessExprNode &node, GraphBuilder &g) {
|
std::string emit(const ModuleAccessExprNode &node, GraphBuilder &g) {
|
||||||
auto id = g.makeNode("ScopeAccessExpression");
|
auto id = g.makeNode("ScopeAccessExpression");
|
||||||
g.addEdge(id, emit(node->scope, g), "Object");
|
g.addEdge(id, emit(node->scope, g), "Object");
|
||||||
if (! node->genericParams.empty()) {
|
if (! node->genericParams.empty()) {
|
||||||
@ -764,8 +780,8 @@ namespace arti::lang::ast {
|
|||||||
[&g](const StructLtrlNode &n) { return emit(n, g); },
|
[&g](const StructLtrlNode &n) { return emit(n, g); },
|
||||||
[&g](const SliceLtrlNode &n) { return emit(n, g); },
|
[&g](const SliceLtrlNode &n) { return emit(n, g); },
|
||||||
[&g](const IdentifierExprNode &n) { return emit(n, g); },
|
[&g](const IdentifierExprNode &n) { return emit(n, g); },
|
||||||
[&g](const UnaryExprNode &n) { return emit(n, g); },
|
[&g](const PrefixExprNode &n) { return emit(n, g); },
|
||||||
[&g](const BinaryExprNode &n) { return emit(n, g); },
|
[&g](const InfixExprNode &n) { return emit(n, g); },
|
||||||
[&g](const AssignExprNode &n) { return emit(n, g); },
|
[&g](const AssignExprNode &n) { return emit(n, g); },
|
||||||
[&g](const CompoundAssignExprNode &n) { return emit(n, g); },
|
[&g](const CompoundAssignExprNode &n) { return emit(n, g); },
|
||||||
[&g](const FunctionCallExprNode &n) { return emit(n, g); },
|
[&g](const FunctionCallExprNode &n) { return emit(n, g); },
|
||||||
@ -773,7 +789,7 @@ namespace arti::lang::ast {
|
|||||||
[&g](const SliceRangeExprNode &n) { return emit(n, g); },
|
[&g](const SliceRangeExprNode &n) { return emit(n, g); },
|
||||||
[&g](const MemberAccessExprNode &n) { return emit(n, g); },
|
[&g](const MemberAccessExprNode &n) { return emit(n, g); },
|
||||||
[&g](const PointerAccessExprNode &n) { return emit(n, g); },
|
[&g](const PointerAccessExprNode &n) { return emit(n, g); },
|
||||||
[&g](const ScopeAccessExprNode &n) { return emit(n, g); },
|
[&g](const ModuleAccessExprNode &n) { return emit(n, g); },
|
||||||
[&g](const SliceCreationExprNode &n) { return emit(n, g); },
|
[&g](const SliceCreationExprNode &n) { return emit(n, g); },
|
||||||
[&g](const SliceLengthExprNode &n) { return emit(n, g); },
|
[&g](const SliceLengthExprNode &n) { return emit(n, g); },
|
||||||
[&g](const SlicePtrExprNode &n) { return emit(n, g); },
|
[&g](const SlicePtrExprNode &n) { return emit(n, g); },
|
||||||
|
|||||||
@ -62,8 +62,8 @@ namespace arti::lang::ast {
|
|||||||
std::string toString(const StructLtrlPositionalInitializerNode&, std::string);
|
std::string toString(const StructLtrlPositionalInitializerNode&, std::string);
|
||||||
std::string toString(const StructLtrlInitializerNode &, std::string);
|
std::string toString(const StructLtrlInitializerNode &, std::string);
|
||||||
std::string toString(const IdentifierExprNode &, std::string);
|
std::string toString(const IdentifierExprNode &, std::string);
|
||||||
std::string toString(const UnaryExprNode &, std::string);
|
std::string toString(const PrefixExprNode &, std::string);
|
||||||
std::string toString(const BinaryExprNode &, std::string);
|
std::string toString(const InfixExprNode &, std::string);
|
||||||
std::string toString(const AssignExprNode &, std::string);
|
std::string toString(const AssignExprNode &, std::string);
|
||||||
std::string toString(const CompoundAssignExprNode &, std::string);
|
std::string toString(const CompoundAssignExprNode &, std::string);
|
||||||
std::string toString(const FunctionCallExprNode &, std::string);
|
std::string toString(const FunctionCallExprNode &, std::string);
|
||||||
@ -71,7 +71,7 @@ namespace arti::lang::ast {
|
|||||||
std::string toString(const SliceRangeExprNode &, std::string);
|
std::string toString(const SliceRangeExprNode &, std::string);
|
||||||
std::string toString(const MemberAccessExprNode &, std::string);
|
std::string toString(const MemberAccessExprNode &, std::string);
|
||||||
std::string toString(const PointerAccessExprNode &, std::string);
|
std::string toString(const PointerAccessExprNode &, std::string);
|
||||||
std::string toString(const ScopeAccessExprNode &, std::string);
|
std::string toString(const ModuleAccessExprNode &, std::string);
|
||||||
std::string toString(const ReflectionExprNode &, std::string);
|
std::string toString(const ReflectionExprNode &, std::string);
|
||||||
std::string toString(const SliceCreationExprNode &, std::string);
|
std::string toString(const SliceCreationExprNode &, std::string);
|
||||||
std::string toString(const SliceLengthExprNode &, std::string);
|
std::string toString(const SliceLengthExprNode &, std::string);
|
||||||
@ -100,8 +100,8 @@ namespace arti::lang::ast {
|
|||||||
std::string toString(const ElseBranchNode &, std::string);
|
std::string toString(const ElseBranchNode &, std::string);
|
||||||
std::string toString(const DeferableNode &, std::string);
|
std::string toString(const DeferableNode &, std::string);
|
||||||
std::string toString(const PreLoopStmtNode &, std::string);
|
std::string toString(const PreLoopStmtNode &, std::string);
|
||||||
std::string toString(UnaryOperator op);
|
std::string toString(PrefixOperator op);
|
||||||
std::string toString(BinaryOperator op);
|
std::string toString(InfixOperator op);
|
||||||
std::string toString(CompoundAssignOperator op);
|
std::string toString(CompoundAssignOperator op);
|
||||||
|
|
||||||
const auto StrTreeNoNode = "│ ";
|
const auto StrTreeNoNode = "│ ";
|
||||||
@ -725,9 +725,9 @@ namespace arti::lang::ast {
|
|||||||
return std::format("Identifier `{}`", node->identifierName);
|
return std::format("Identifier `{}`", node->identifierName);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString(const UnaryExprNode &node, std::string prefix) {
|
std::string toString(const PrefixExprNode &node, std::string prefix) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "UnaryExpression";
|
ss << "PrefixExpression";
|
||||||
int total = 2;
|
int total = 2;
|
||||||
int emitted = 0;
|
int emitted = 0;
|
||||||
appendGroupLeaf(
|
appendGroupLeaf(
|
||||||
@ -741,9 +741,9 @@ namespace arti::lang::ast {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString(const BinaryExprNode &node, std::string prefix) {
|
std::string toString(const InfixExprNode &node, std::string prefix) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "BinaryExpression";
|
ss << "InfixExpression";
|
||||||
int total = 3;
|
int total = 3;
|
||||||
int emitted = 0;
|
int emitted = 0;
|
||||||
appendGroupLeaf(
|
appendGroupLeaf(
|
||||||
@ -849,7 +849,7 @@ namespace arti::lang::ast {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString(const ScopeAccessExprNode &node, std::string prefix) {
|
std::string toString(const ModuleAccessExprNode &node, std::string prefix) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "ScopeAccessExpression";
|
ss << "ScopeAccessExpression";
|
||||||
int total = 2;
|
int total = 2;
|
||||||
@ -943,10 +943,10 @@ namespace arti::lang::ast {
|
|||||||
[padding](const IdentifierExprNode &node) -> std::string {
|
[padding](const IdentifierExprNode &node) -> std::string {
|
||||||
return toString(node, padding);
|
return toString(node, padding);
|
||||||
},
|
},
|
||||||
[padding](const UnaryExprNode &node) -> std::string {
|
[padding](const PrefixExprNode &node) -> std::string {
|
||||||
return toString(node, padding);
|
return toString(node, padding);
|
||||||
},
|
},
|
||||||
[padding](const BinaryExprNode &node) -> std::string {
|
[padding](const InfixExprNode &node) -> std::string {
|
||||||
return toString(node, padding);
|
return toString(node, padding);
|
||||||
},
|
},
|
||||||
[padding](const AssignExprNode &node) -> std::string {
|
[padding](const AssignExprNode &node) -> std::string {
|
||||||
@ -970,7 +970,7 @@ namespace arti::lang::ast {
|
|||||||
[padding](const PointerAccessExprNode &node) -> std::string {
|
[padding](const PointerAccessExprNode &node) -> std::string {
|
||||||
return toString(node, padding);
|
return toString(node, padding);
|
||||||
},
|
},
|
||||||
[padding](const ScopeAccessExprNode &node) -> std::string {
|
[padding](const ModuleAccessExprNode &node) -> std::string {
|
||||||
return toString(node, padding);
|
return toString(node, padding);
|
||||||
},
|
},
|
||||||
[padding](const SliceCreationExprNode &node) -> std::string {
|
[padding](const SliceCreationExprNode &node) -> std::string {
|
||||||
@ -1466,46 +1466,60 @@ namespace arti::lang::ast {
|
|||||||
return std::visit(visitor, node);
|
return std::visit(visitor, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString(UnaryOperator op) {
|
std::string toString(PrefixOperator op) {
|
||||||
using enum UnaryOperator;
|
using enum PrefixOperator;
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Not: return "Not (!)";
|
case Not: return "Not (!)";
|
||||||
case Minus: return "Minus (-)";
|
case Minus: return "Minus (-)";
|
||||||
case BitNot: return "BitNot (~)";
|
case BitNot: return "BitNot (~)";
|
||||||
case Ampersand: return "Ampersand (&)";
|
case MemPtr: return "MemPtr (&)";
|
||||||
case Star: return "Star (*)";
|
case DerefPtr: return "DerefPtr (*)";
|
||||||
default: std::unreachable(); break;
|
default: std::unreachable(); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string toString(BinaryOperator op) {
|
std::string toString(InfixOperator op) {
|
||||||
using enum BinaryOperator;
|
using enum InfixOperator;
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Equal: return "Equal (==)";
|
case Equal: return "Equal (==)";
|
||||||
case NotEqual: return "NotEqual (!=)";
|
case NotEqual: return "NotEqual (!=)";
|
||||||
case GreaterThan: return "GreaterThan (>)";
|
case GreaterThan: return "GreaterThan (>)";
|
||||||
case LessThan: return "LessThan (<)";
|
case LessThan: return "LessThan (<)";
|
||||||
case GreaterEqual: return "GreaterEqual (>=)";
|
case GreaterEqual: return "GreaterEqual (>=)";
|
||||||
case LessEqual: return "LessEqual (<=)";
|
case LessEqual: return "LessEqual (<=)";
|
||||||
case BitAnd: return "BitAnd (&)";
|
case BitAnd: return "BitAnd (&)";
|
||||||
case BitXor: return "BitXor (^)";
|
case BitXor: return "BitXor (^)";
|
||||||
case BitOr: return "BitOr (|)";
|
case BitOr: return "BitOr (|)";
|
||||||
case LeftShift: return "LeftShift (<<)";
|
case LeftShift: return "LeftShift (<<)";
|
||||||
case RightShift: return "RightShift (>>)";
|
case RightShift: return "RightShift (>>)";
|
||||||
case Adition: return "Adition (+)";
|
case Addition: return "Addition (+)";
|
||||||
case Substraction: return "Substraction (-)";
|
case Substraction: return "Substraction (-)";
|
||||||
case Multiplication: return "Multiplication (*)";
|
case Multiplication: return "Multiplication (*)";
|
||||||
case Division: return "Division (/)";
|
case Division: return "Division (/)";
|
||||||
case Modulo: return "Modulo (%)";
|
case Modulo: return "Modulo (%)";
|
||||||
case BoolAnd: return "BoolAnd (&&)";
|
case BoolAnd: return "BoolAnd (&&)";
|
||||||
case BoolOr: return "BoolOr (||)";
|
case BoolOr: return "BoolOr (||)";
|
||||||
default: std::unreachable(); break;
|
case Assignment: return "Assignment (=)";
|
||||||
}
|
case ModuleAccess: return "ModuleAccess (::)";
|
||||||
|
case MemberAccess: return "MemberAccess (.)";
|
||||||
|
case PointerMemberAccess: return "PointerMemberAccess (->)";
|
||||||
|
case AdditionAssignment: return "AdditionAssignment (+=)";
|
||||||
|
case SubstractionAssignment: return "SubstractionAssignment (-=)";
|
||||||
|
case MultiplicationAssignment: return "MultiplicationAssignment (*=)";
|
||||||
|
case DivisionAssignment: return "DivisionAssignment (/=)";
|
||||||
|
case ModuloAssignment: return "ModuloAssignment (%=)";
|
||||||
|
case BitAndAssignment: return "BitAndAssignment (&=)";
|
||||||
|
case BitOrAssignment: return "BitOrAssignment (|=)";
|
||||||
|
case BoolAndAssignment: return "BoolAndAssignment (&&=)";
|
||||||
|
case BoolOrAssignment: return "BoolOrAssignment (||=)";
|
||||||
|
case LShiftAssignment: return "LShiftAssignment (<<=)";
|
||||||
|
case RShiftAssignment: return "RShiftAssignment (>>=)";
|
||||||
|
|
||||||
|
default: std::unreachable(); break;
|
||||||
|
}
|
||||||
std::unreachable();
|
std::unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,12 +21,530 @@
|
|||||||
//============================================================================//
|
//============================================================================//
|
||||||
|
|
||||||
#include <artichoke/Parser/Parser.hpp>
|
#include <artichoke/Parser/Parser.hpp>
|
||||||
|
#include <artichoke/Parser/Pratt.hpp>
|
||||||
|
|
||||||
namespace arti::lang {
|
namespace arti::lang {
|
||||||
|
|
||||||
Expected<ast::ExpressionNode>
|
Expected<ast::ExpressionNode>
|
||||||
Parser::parseExpression() {
|
Parser::parseExpression(std::uint16_t minBindingPower) {
|
||||||
return {};
|
auto peekToken = tokenizer.peek();
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool keepParsing = true;
|
||||||
|
ast::Optional<ast::ExpressionNode> lhs = std::nullopt;
|
||||||
|
|
||||||
|
if (peekToken->value == TokenV::opLParen) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
if (auto lhsExpr = parseExpression(); ! lhsExpr) {
|
||||||
|
return Unexpected<>{ std::move(lhsExpr).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (auto rParen = consume(TokenV::opRParen, "')'"); ! rParen) {
|
||||||
|
return Unexpected<>{ std::move(rParen).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
lhs = std::move(lhsExpr).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pratt::isPrefixOperator(peekToken->value)) {
|
||||||
|
if (auto newLhs = parsePrefixExpression(); ! newLhs) {
|
||||||
|
return Unexpected<>{ std::move(newLhs).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lhs = std::move(newLhs).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (auto expr = parsePrimaryExpression(); ! expr) {
|
||||||
|
return Unexpected<>{ std::move(expr).error() };
|
||||||
|
}
|
||||||
|
else if (not expr.value().has_value()) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekToken->line,
|
||||||
|
peekToken->column,
|
||||||
|
toString(*peekToken),
|
||||||
|
"primary expression, i.e. "
|
||||||
|
"any of ( null, boolean, number, character, string, identifier )"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lhs = std::move(expr).value().value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (keepParsing) {
|
||||||
|
peekToken = tokenizer.peek();
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pratt::isPostfixOperator(peekToken->value)) {
|
||||||
|
auto op = pratt::getPostfixOperator(peekToken->value);
|
||||||
|
auto bindingPower = pratt::postfixBindingPower(op);
|
||||||
|
|
||||||
|
if (bindingPower < minBindingPower) {
|
||||||
|
keepParsing = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (auto newLhs = parsePostfixExpression(std::move(lhs).value());
|
||||||
|
! newLhs) {
|
||||||
|
return Unexpected<>{ std::move(newLhs).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lhs = std::move(newLhs).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pratt::isInfixOperator(peekToken->value)) {
|
||||||
|
auto op = pratt::getInfixOperator(peekToken->value);
|
||||||
|
auto [lbp, rbp] = pratt::infixBindingPower(op);
|
||||||
|
|
||||||
|
if (lbp < minBindingPower) {
|
||||||
|
keepParsing = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (auto newLhs = parseInfixExpression(std::move(lhs).value());
|
||||||
|
! newLhs) {
|
||||||
|
return Unexpected<>{ std::move(newLhs).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lhs = std::move(newLhs).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
keepParsing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not lhs.has_value()) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekToken->line,
|
||||||
|
peekToken->column,
|
||||||
|
toString(*peekToken),
|
||||||
|
"primary expression, i.e. "
|
||||||
|
"any of ( null, boolean, number, character, string, identifier )"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::move(lhs).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::Optional<ast::ExpressionNode>>
|
||||||
|
Parser::parsePrimaryExpression() {
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekToken->value == TokenV::tkInteger) {
|
||||||
|
if (auto expr = parseIntegerLiteral(); ! expr) {
|
||||||
|
return Unexpected<>{ std::move(expr).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::move(expr).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::tkDecimal) {
|
||||||
|
if (auto expr = parseFloatLiteral(); ! expr) {
|
||||||
|
return Unexpected<>{ std::move(expr).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::move(expr).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::tkCharacter) {
|
||||||
|
if (auto expr = parseCharLiteral(); ! expr) {
|
||||||
|
return Unexpected<>{ std::move(expr).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::move(expr).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::tkString) {
|
||||||
|
if (auto expr = parseStringLiteral(); ! expr) {
|
||||||
|
return Unexpected<>{ std::move(expr).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::move(expr).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::kwTrue ||
|
||||||
|
peekToken->value == TokenV::kwFalse) {
|
||||||
|
if (auto expr = parseBooleanLiteral(); ! expr) {
|
||||||
|
return Unexpected<>{ std::move(expr).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::move(expr).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::kwNull) {
|
||||||
|
if (auto expr = parseNullLiteral(); ! expr) {
|
||||||
|
return Unexpected<>{ std::move(expr).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::move(expr).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::tkIdentifier) {
|
||||||
|
if (auto expr = parseIdentifierExpression(); ! expr) {
|
||||||
|
return Unexpected<>{ std::move(expr).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return std::move(expr).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::kwThis) {
|
||||||
|
auto node = ast::MakeNode<ast::IdentifierExprNode>();
|
||||||
|
|
||||||
|
if (auto ltrl = consume(TokenV::kwThis, "'this' keyword"); ! ltrl) {
|
||||||
|
return Unexpected<>{ std::move(ltrl).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = {
|
||||||
|
.line = ltrl->line,
|
||||||
|
.column = ltrl->column
|
||||||
|
};
|
||||||
|
node->identifierName = ltrl->strValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::kwUnderscore) {
|
||||||
|
auto node = ast::MakeNode<ast::IdentifierExprNode>();
|
||||||
|
|
||||||
|
if (auto ltrl = consume(TokenV::kwUnderscore, "'_' keyword"); ! ltrl) {
|
||||||
|
return Unexpected<>{ std::move(ltrl).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = {
|
||||||
|
.line = ltrl->line,
|
||||||
|
.column = ltrl->column
|
||||||
|
};
|
||||||
|
node->identifierName = ltrl->strValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expected<ast::ExpressionNode>
|
||||||
|
Parser::parsePrefixExpression() {
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
auto op = pratt::getPrefixOperator(peekToken->value);
|
||||||
|
auto bindingPower = pratt::prefixBindingPower(op);
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto rhs = parseExpression(bindingPower);
|
||||||
|
|
||||||
|
auto node = ast::MakeNode<ast::PrefixExprNode>();
|
||||||
|
|
||||||
|
node->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
node->op = op;
|
||||||
|
node->right = std::move(rhs).value();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::ExpressionNode>
|
||||||
|
Parser::parseInfixExpression(ast::ExpressionNode lhs) {
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto op = pratt::getInfixOperator(peekToken->value);
|
||||||
|
auto [lbp, rbp] = pratt::infixBindingPower(op);
|
||||||
|
|
||||||
|
auto rhs = parseExpression(rbp);
|
||||||
|
|
||||||
|
if (! rhs) {
|
||||||
|
return Unexpected<>{ std::move(rhs).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: MemberAccess and PointerMemberAccess do not use their respective
|
||||||
|
* nodes types yet */
|
||||||
|
/* TODO: ModuleAccess do not use its respective node type yet */
|
||||||
|
if (op == ast::InfixOperator::Assignment) {
|
||||||
|
auto node = ast::MakeNode<ast::AssignExprNode>();
|
||||||
|
|
||||||
|
node->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
node->left = std::move(lhs);
|
||||||
|
node->right = std::move(rhs).value();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
else if (pratt::isCompoundAssignOperator(op)) {
|
||||||
|
auto node = ast::MakeNode<ast::CompoundAssignExprNode>();
|
||||||
|
|
||||||
|
node->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
node->op = pratt::getCompoundOperatorType(op);
|
||||||
|
node->left = std::move(lhs);
|
||||||
|
node->right = std::move(rhs).value();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto node = ast::MakeNode<ast::InfixExprNode>();
|
||||||
|
|
||||||
|
node->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
node->op = op;
|
||||||
|
node->left = std::move(lhs);
|
||||||
|
node->right = std::move(rhs).value();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::ExpressionNode>
|
||||||
|
Parser::parsePostfixExpression(ast::ExpressionNode lhs) {
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto op = pratt::getPostfixOperator(peekToken->value);
|
||||||
|
auto bindingPower = pratt::postfixBindingPower(op);
|
||||||
|
|
||||||
|
std::optional<ast::ExpressionNode> node = std::nullopt;
|
||||||
|
|
||||||
|
if (op == ast::PostfixOperator::FunctionCall) {
|
||||||
|
auto newNode = ast::MakeNode<ast::FunctionCallExprNode>();
|
||||||
|
|
||||||
|
newNode->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
bool stillParams = true;
|
||||||
|
|
||||||
|
if (auto close = match(TokenV::opRParen); ! close) {
|
||||||
|
return Unexpected<>{ std::move(close).error() };
|
||||||
|
}
|
||||||
|
else if (close.value()) {
|
||||||
|
stillParams = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (stillParams) {
|
||||||
|
auto arg = parseExpression();
|
||||||
|
|
||||||
|
if (! arg) {
|
||||||
|
return Unexpected<>{ std::move(arg).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode->arguments.emplace_back(std::move(arg).value());
|
||||||
|
|
||||||
|
if (auto comma = matchAndConsume(TokenV::opComma); ! comma) {
|
||||||
|
return Unexpected{ std::move(comma).error() };
|
||||||
|
}
|
||||||
|
else if (! comma.value()) {
|
||||||
|
if (auto ntok = tokenizer.peek(); ! ntok) {
|
||||||
|
return Unexpected{ std::move(ntok).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ntok->value != TokenV::opRParen) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
ntok->line,
|
||||||
|
ntok->column,
|
||||||
|
toString(*ntok),
|
||||||
|
"',' or ')'"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stillParams = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto close = match(TokenV::opRParen); ! close) {
|
||||||
|
return Unexpected<>{ std::move(close).error() };
|
||||||
|
}
|
||||||
|
else if (close.value()) {
|
||||||
|
stillParams = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto close = consume(TokenV::opRParen, "')'"); ! close) {
|
||||||
|
return Unexpected<>{ std::move(close).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode->callee = std::move(lhs);
|
||||||
|
|
||||||
|
node = std::move(newNode);
|
||||||
|
}
|
||||||
|
else if (op == ast::PostfixOperator::SliceAccess) {
|
||||||
|
auto idx = parseExpression();
|
||||||
|
|
||||||
|
if (! idx) {
|
||||||
|
return Unexpected<>{ std::move(idx).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto range = matchAndConsume(TokenV::opColon); ! range) {
|
||||||
|
return Unexpected<>{ std::move(range).error() };
|
||||||
|
}
|
||||||
|
else if (range.value()) {
|
||||||
|
auto newNode = ast::MakeNode<ast::SliceRangeExprNode>();
|
||||||
|
|
||||||
|
newNode->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
newNode->start = std::move(idx).value();
|
||||||
|
|
||||||
|
auto endIdx = parseExpression();
|
||||||
|
|
||||||
|
if (! endIdx) {
|
||||||
|
return Unexpected<>{ std::move(endIdx).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode->end = std::move(endIdx).value();
|
||||||
|
|
||||||
|
if (auto close = consume(TokenV::opRBracket, "']'"); ! close) {
|
||||||
|
return Unexpected<>{ std::move(close).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode->slice = std::move(lhs);
|
||||||
|
|
||||||
|
node = std::move(newNode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto newNode = ast::MakeNode<ast::SliceAccessExprNode>();
|
||||||
|
|
||||||
|
newNode->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
newNode->index = std::move(idx).value();
|
||||||
|
|
||||||
|
if (auto close = consume(TokenV::opRBracket, "']'"); ! close) {
|
||||||
|
return Unexpected<>{ std::move(close).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode->slice = std::move(lhs);
|
||||||
|
|
||||||
|
node = std::move(newNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (op == ast::PostfixOperator::SliceSize) {
|
||||||
|
auto newNode = ast::MakeNode<ast::SliceLengthExprNode>();
|
||||||
|
|
||||||
|
newNode->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
newNode->object = std::move(lhs);
|
||||||
|
|
||||||
|
node = std::move(newNode);
|
||||||
|
}
|
||||||
|
else if (op == ast::PostfixOperator::PtrToSlice) {
|
||||||
|
auto newNode = ast::MakeNode<ast::SliceCreationExprNode>();
|
||||||
|
|
||||||
|
newNode->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
auto len = parseExpression();
|
||||||
|
|
||||||
|
if (! len) {
|
||||||
|
return Unexpected<>{ std::move(len).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode->length = std::move(len).value();
|
||||||
|
|
||||||
|
if (auto close = consume(TokenV::opRBracket, "']'"); ! close) {
|
||||||
|
return Unexpected<>{ std::move(close).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode->object = std::move(lhs);
|
||||||
|
|
||||||
|
node = std::move(newNode);
|
||||||
|
}
|
||||||
|
else if (op == ast::PostfixOperator::SliceToPtr) {
|
||||||
|
auto newNode = ast::MakeNode<ast::SlicePtrExprNode>();
|
||||||
|
|
||||||
|
newNode->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
newNode->object = std::move(lhs);
|
||||||
|
|
||||||
|
node = std::move(newNode);
|
||||||
|
}
|
||||||
|
else if (op == ast::PostfixOperator::Reflect) {
|
||||||
|
auto newNode = ast::MakeNode<ast::ReflectionExprNode>();
|
||||||
|
|
||||||
|
newNode->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auto ident = match(TokenV::tkIdentifier); ! ident) {
|
||||||
|
return Unexpected<>{ std::move(ident).error() };
|
||||||
|
}
|
||||||
|
else if (ident.value()) {
|
||||||
|
if (auto ident = consume(TokenV::tkIdentifier, "identifier");
|
||||||
|
! ident) {
|
||||||
|
return Unexpected<>{ std::move(ident).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newNode->attribute = ident->strValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode->object = std::move(lhs);
|
||||||
|
|
||||||
|
node = std::move(newNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not node.has_value()) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekToken->line,
|
||||||
|
peekToken->column,
|
||||||
|
toString(*peekToken),
|
||||||
|
"postfix operator, i.e. "
|
||||||
|
"any of ( /*TODO*/ )"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(node).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace arti::lang
|
} // namespace arti::lang
|
||||||
|
|||||||
@ -20,3 +20,159 @@
|
|||||||
// //
|
// //
|
||||||
//============================================================================//
|
//============================================================================//
|
||||||
|
|
||||||
|
#include <artichoke/Parser/Parser.hpp>
|
||||||
|
|
||||||
|
namespace arti::lang {
|
||||||
|
|
||||||
|
Expected<ast::CharLtrlNode>
|
||||||
|
Parser::parseCharLiteral() {
|
||||||
|
auto node = ast::MakeNode<ast::CharLtrlNode>();
|
||||||
|
|
||||||
|
if (auto ltrl = consume(TokenV::tkCharacter, "character literal"); ! ltrl) {
|
||||||
|
return Unexpected<>{ std::move(ltrl).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = {
|
||||||
|
.line = ltrl->line,
|
||||||
|
.column = ltrl->column
|
||||||
|
};
|
||||||
|
node->value = static_cast<uint8_t>(ltrl->strValue[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::NullLtrlNode>
|
||||||
|
Parser::parseNullLiteral() {
|
||||||
|
auto node = ast::MakeNode<ast::NullLtrlNode>();
|
||||||
|
|
||||||
|
if (auto ltrl = consume(TokenV::kwNull, "null keyword"); ! ltrl) {
|
||||||
|
return Unexpected<>{ std::move(ltrl).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = {
|
||||||
|
.line = ltrl->line,
|
||||||
|
.column = ltrl->column
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::StringLtrlNode>
|
||||||
|
Parser::parseStringLiteral() {
|
||||||
|
auto node = ast::MakeNode<ast::StringLtrlNode>();
|
||||||
|
|
||||||
|
if (auto ltrl = consume(TokenV::tkString, "string literal"); ! ltrl) {
|
||||||
|
return Unexpected<>{ std::move(ltrl).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = {
|
||||||
|
.line = ltrl->line,
|
||||||
|
.column = ltrl->column
|
||||||
|
};
|
||||||
|
|
||||||
|
ltrl->strValue.remove_suffix(1);
|
||||||
|
ltrl->strValue.remove_prefix(1);
|
||||||
|
|
||||||
|
node->value = ltrl->strValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::FloatLtrlNode>
|
||||||
|
Parser::parseFloatLiteral() {
|
||||||
|
auto node = ast::MakeNode<ast::FloatLtrlNode>();
|
||||||
|
|
||||||
|
if (auto ltrl = consume(TokenV::tkDecimal, "number literal"); ! ltrl) {
|
||||||
|
return Unexpected<>{ std::move(ltrl).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = {
|
||||||
|
.line = ltrl->line,
|
||||||
|
.column = ltrl->column
|
||||||
|
};
|
||||||
|
/* TODO: This could throw? */
|
||||||
|
std::string value{ ltrl->strValue };
|
||||||
|
node->value = std::stold(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::IntegerLtrlNode>
|
||||||
|
Parser::parseIntegerLiteral() {
|
||||||
|
auto node = ast::MakeNode<ast::IntegerLtrlNode>();
|
||||||
|
|
||||||
|
if (auto ltrl = consume(TokenV::tkInteger, "integer literal"); ! ltrl) {
|
||||||
|
return Unexpected<>{ std::move(ltrl).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = {
|
||||||
|
.line = ltrl->line,
|
||||||
|
.column = ltrl->column
|
||||||
|
};
|
||||||
|
/* TODO: This could throw? */
|
||||||
|
std::string value{ ltrl->strValue };
|
||||||
|
node->value = std::stoul(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::BooleanLtrlNode>
|
||||||
|
Parser::parseBooleanLiteral() {
|
||||||
|
auto node = ast::MakeNode<ast::BooleanLtrlNode>();
|
||||||
|
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->location = {
|
||||||
|
.line = peekToken->line,
|
||||||
|
.column = peekToken->column
|
||||||
|
};
|
||||||
|
|
||||||
|
if (peekToken->value == TokenV::kwTrue) {
|
||||||
|
node->value = true;
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::kwFalse) {
|
||||||
|
node->value = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekToken->line,
|
||||||
|
peekToken->column,
|
||||||
|
toString(*peekToken),
|
||||||
|
"boolean literal, i.e. "
|
||||||
|
"any of ( true, false )"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::IdentifierExprNode>
|
||||||
|
Parser::parseIdentifierExpression() {
|
||||||
|
auto node = ast::MakeNode<ast::IdentifierExprNode>();
|
||||||
|
|
||||||
|
if (auto ltrl = consume(TokenV::tkIdentifier, "identifier"); ! ltrl) {
|
||||||
|
return Unexpected<>{ std::move(ltrl).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = {
|
||||||
|
.line = ltrl->line,
|
||||||
|
.column = ltrl->column
|
||||||
|
};
|
||||||
|
node->identifierName = ltrl->strValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace arti::lang
|
||||||
|
|||||||
288
lib/src/Parser/Operators.cpp
Normal file
288
lib/src/Parser/Operators.cpp
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
//============================================================================//
|
||||||
|
// //
|
||||||
|
// artichoke programming language //
|
||||||
|
// //
|
||||||
|
// Copyright (C) 2025 Erick Saul Guzman Ramos, whoami.artichoke.dev //
|
||||||
|
// //
|
||||||
|
// //
|
||||||
|
// This program is free software: you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU Affero General Public License as published //
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU Affero General Public License for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU Affero General Public License //
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
|
||||||
|
// //
|
||||||
|
//============================================================================//
|
||||||
|
|
||||||
|
#include <artichoke/Parser/Pratt.hpp>
|
||||||
|
|
||||||
|
namespace arti::lang::pratt {
|
||||||
|
|
||||||
|
bool isPrefixOperator(TokenV tokenType) {
|
||||||
|
switch(tokenType) {
|
||||||
|
using enum TokenV;
|
||||||
|
|
||||||
|
case opHyphen:
|
||||||
|
case opBang:
|
||||||
|
case opStar:
|
||||||
|
case opTilde:
|
||||||
|
case opAnd:
|
||||||
|
case opLParen:
|
||||||
|
case kwNot:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isInfixOperator(TokenV tokenType) {
|
||||||
|
switch(tokenType) {
|
||||||
|
using enum TokenV;
|
||||||
|
|
||||||
|
case opDot:
|
||||||
|
case opMod:
|
||||||
|
case opPlus:
|
||||||
|
case opHyphen:
|
||||||
|
case opSlash:
|
||||||
|
case opStar:
|
||||||
|
case opAssign:
|
||||||
|
case opAccess:
|
||||||
|
case opEq:
|
||||||
|
case opNeq:
|
||||||
|
case opLt:
|
||||||
|
case opGt:
|
||||||
|
case opLtEq:
|
||||||
|
case opGtEq:
|
||||||
|
case opLShift:
|
||||||
|
case opRShift:
|
||||||
|
case opBoolAnd:
|
||||||
|
case opBoolOr:
|
||||||
|
case kwAnd:
|
||||||
|
case kwOr:
|
||||||
|
case opAnd:
|
||||||
|
case opOr:
|
||||||
|
case opCaret:
|
||||||
|
case opArrow:
|
||||||
|
case opPlusAssign:
|
||||||
|
case opHyphenAssign:
|
||||||
|
case opStarAssign:
|
||||||
|
case opSlashAssign:
|
||||||
|
case opModAssign:
|
||||||
|
case opAndAssign:
|
||||||
|
case opOrAssign:
|
||||||
|
case opLShiftAssign:
|
||||||
|
case opRShiftAssign:
|
||||||
|
case opBoolAndAssign:
|
||||||
|
case opBoolOrAssign:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPostfixOperator(TokenV tokenType) {
|
||||||
|
switch(tokenType) {
|
||||||
|
using enum TokenV;
|
||||||
|
|
||||||
|
case opLParen:
|
||||||
|
case opLBracket:
|
||||||
|
case opSliceSize:
|
||||||
|
case opPtrSlice:
|
||||||
|
case opSlicePtr:
|
||||||
|
case opReflect:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ast::PrefixOperator getPrefixOperator(TokenV tokenType) {
|
||||||
|
using enum ast::PrefixOperator;
|
||||||
|
|
||||||
|
switch(tokenType) {
|
||||||
|
using enum TokenV;
|
||||||
|
|
||||||
|
case opHyphen:
|
||||||
|
return Minus;
|
||||||
|
case kwNot:
|
||||||
|
case opBang:
|
||||||
|
return Not;
|
||||||
|
case opStar:
|
||||||
|
return DerefPtr;
|
||||||
|
case opTilde:
|
||||||
|
return BitNot;
|
||||||
|
case opAnd:
|
||||||
|
return MemPtr;
|
||||||
|
default:
|
||||||
|
return Uninitialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::InfixOperator getInfixOperator(TokenV tokenType) {
|
||||||
|
using enum ast::InfixOperator;
|
||||||
|
|
||||||
|
switch(tokenType) {
|
||||||
|
using enum TokenV;
|
||||||
|
|
||||||
|
case opMod:
|
||||||
|
return Modulo;
|
||||||
|
case opPlus:
|
||||||
|
return Addition;
|
||||||
|
case opHyphen:
|
||||||
|
return Substraction;
|
||||||
|
case opSlash:
|
||||||
|
return Division;
|
||||||
|
case opStar:
|
||||||
|
return Multiplication;
|
||||||
|
case opEq:
|
||||||
|
return Equal;
|
||||||
|
case opNeq:
|
||||||
|
return NotEqual;
|
||||||
|
case opLt:
|
||||||
|
return LessThan;
|
||||||
|
case opGt:
|
||||||
|
return GreaterThan;
|
||||||
|
case opLtEq:
|
||||||
|
return LessEqual;
|
||||||
|
case opGtEq:
|
||||||
|
return GreaterEqual;
|
||||||
|
case opLShift:
|
||||||
|
return LeftShift;
|
||||||
|
case opRShift:
|
||||||
|
return RightShift;
|
||||||
|
case kwAnd:
|
||||||
|
case opBoolAnd:
|
||||||
|
return BoolAnd;
|
||||||
|
case kwOr:
|
||||||
|
case opBoolOr:
|
||||||
|
return BoolOr;
|
||||||
|
case opAnd:
|
||||||
|
return BitAnd;
|
||||||
|
case opOr:
|
||||||
|
return BitOr;
|
||||||
|
case opCaret:
|
||||||
|
return BitXor;
|
||||||
|
case opAssign:
|
||||||
|
return Assignment;
|
||||||
|
case opAccess:
|
||||||
|
return ModuleAccess;
|
||||||
|
case opDot:
|
||||||
|
return MemberAccess;
|
||||||
|
case opArrow:
|
||||||
|
return PointerMemberAccess;
|
||||||
|
case opPlusAssign:
|
||||||
|
return AdditionAssignment;
|
||||||
|
case opHyphenAssign:
|
||||||
|
return SubstractionAssignment;
|
||||||
|
case opStarAssign:
|
||||||
|
return MultiplicationAssignment;
|
||||||
|
case opSlashAssign:
|
||||||
|
return DivisionAssignment;
|
||||||
|
case opModAssign:
|
||||||
|
return ModuloAssignment;
|
||||||
|
case opAndAssign:
|
||||||
|
return BitAndAssignment;
|
||||||
|
case opOrAssign:
|
||||||
|
return BitOrAssignment;
|
||||||
|
case opLShiftAssign:
|
||||||
|
return LShiftAssignment;
|
||||||
|
case opRShiftAssign:
|
||||||
|
return RShiftAssignment;
|
||||||
|
case opBoolAndAssign:
|
||||||
|
return BoolAndAssignment;
|
||||||
|
case opBoolOrAssign:
|
||||||
|
return BoolOrAssignment;
|
||||||
|
default:
|
||||||
|
return Uninitialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::PostfixOperator getPostfixOperator(TokenV tokenType) {
|
||||||
|
using enum ast::PostfixOperator;
|
||||||
|
|
||||||
|
switch(tokenType) {
|
||||||
|
using enum TokenV;
|
||||||
|
|
||||||
|
case opLParen:
|
||||||
|
return FunctionCall;
|
||||||
|
case opLBracket:
|
||||||
|
return SliceAccess;
|
||||||
|
case opSliceSize:
|
||||||
|
return SliceSize;
|
||||||
|
case opPtrSlice:
|
||||||
|
return PtrToSlice;
|
||||||
|
case opSlicePtr:
|
||||||
|
return SliceToPtr;
|
||||||
|
case opReflect:
|
||||||
|
return Reflect;
|
||||||
|
default:
|
||||||
|
return Uninitialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isCompoundAssignOperator(ast::InfixOperator op) {
|
||||||
|
|
||||||
|
switch(op) {
|
||||||
|
using enum ast::InfixOperator;
|
||||||
|
|
||||||
|
case AdditionAssignment:
|
||||||
|
case SubstractionAssignment:
|
||||||
|
case MultiplicationAssignment:
|
||||||
|
case DivisionAssignment:
|
||||||
|
case ModuloAssignment:
|
||||||
|
case BitAndAssignment:
|
||||||
|
case BitOrAssignment:
|
||||||
|
case LShiftAssignment:
|
||||||
|
case RShiftAssignment:
|
||||||
|
case BoolAndAssignment:
|
||||||
|
case BoolOrAssignment:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::CompoundAssignOperator getCompoundOperatorType(ast::InfixOperator op) {
|
||||||
|
switch(op) {
|
||||||
|
using enum ast::InfixOperator;
|
||||||
|
|
||||||
|
case AdditionAssignment:
|
||||||
|
return ast::CompoundAssignOperator::Addition;
|
||||||
|
case SubstractionAssignment:
|
||||||
|
return ast::CompoundAssignOperator::Substraction;
|
||||||
|
case MultiplicationAssignment:
|
||||||
|
return ast::CompoundAssignOperator::Multiplication;
|
||||||
|
case DivisionAssignment:
|
||||||
|
return ast::CompoundAssignOperator::Division;
|
||||||
|
case ModuloAssignment:
|
||||||
|
return ast::CompoundAssignOperator::Modulo;
|
||||||
|
case BitAndAssignment:
|
||||||
|
return ast::CompoundAssignOperator::BitAnd;
|
||||||
|
case BitOrAssignment:
|
||||||
|
return ast::CompoundAssignOperator::BitOr;
|
||||||
|
case LShiftAssignment:
|
||||||
|
return ast::CompoundAssignOperator::LeftShift;
|
||||||
|
case RShiftAssignment:
|
||||||
|
return ast::CompoundAssignOperator::RightShift;
|
||||||
|
case BoolAndAssignment:
|
||||||
|
return ast::CompoundAssignOperator::BoolAnd;
|
||||||
|
case BoolOrAssignment:
|
||||||
|
return ast::CompoundAssignOperator::BoolOr;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ast::CompoundAssignOperator::Uninitialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
111
lib/src/Parser/Pratt.cpp
Normal file
111
lib/src/Parser/Pratt.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
//============================================================================//
|
||||||
|
// //
|
||||||
|
// artichoke programming language //
|
||||||
|
// //
|
||||||
|
// Copyright (C) 2025 Erick Saul Guzman Ramos, whoami.artichoke.dev //
|
||||||
|
// //
|
||||||
|
// //
|
||||||
|
// This program is free software: you can redistribute it and/or modify //
|
||||||
|
// it under the terms of the GNU Affero General Public License as published //
|
||||||
|
// by the Free Software Foundation, either version 3 of the License, or //
|
||||||
|
// (at your option) any later version. //
|
||||||
|
// //
|
||||||
|
// This program is distributed in the hope that it will be useful, //
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
|
// GNU Affero General Public License for more details. //
|
||||||
|
// //
|
||||||
|
// You should have received a copy of the GNU Affero General Public License //
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
|
||||||
|
// //
|
||||||
|
//============================================================================//
|
||||||
|
|
||||||
|
#include <artichoke/Parser/Pratt.hpp>
|
||||||
|
|
||||||
|
namespace arti::lang::pratt {
|
||||||
|
|
||||||
|
std::uint16_t prefixBindingPower(ast::PrefixOperator op) {
|
||||||
|
switch (op) {
|
||||||
|
// Unary operators generally bind very tightly
|
||||||
|
case ast::PrefixOperator::Not:
|
||||||
|
case ast::PrefixOperator::Minus:
|
||||||
|
case ast::PrefixOperator::BitNot:
|
||||||
|
case ast::PrefixOperator::MemPtr:
|
||||||
|
case ast::PrefixOperator::DerefPtr:
|
||||||
|
return 17; // Should be higher than most infix but lower than postfix
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BindingPower infixBindingPower(ast::InfixOperator op) {
|
||||||
|
switch (op) {
|
||||||
|
// Member Access (Highest)
|
||||||
|
case ast::InfixOperator::ModuleAccess:
|
||||||
|
case ast::InfixOperator::MemberAccess:
|
||||||
|
case ast::InfixOperator::PointerMemberAccess: return { 21, 22 };
|
||||||
|
|
||||||
|
// Multiplicative
|
||||||
|
case ast::InfixOperator::Multiplication:
|
||||||
|
case ast::InfixOperator::Division:
|
||||||
|
case ast::InfixOperator::Modulo: return { 15, 16 };
|
||||||
|
|
||||||
|
// Additive
|
||||||
|
case ast::InfixOperator::Addition:
|
||||||
|
case ast::InfixOperator::Substraction: return { 13, 14 };
|
||||||
|
|
||||||
|
// Shift
|
||||||
|
case ast::InfixOperator::LeftShift:
|
||||||
|
case ast::InfixOperator::RightShift: return { 11, 12 };
|
||||||
|
|
||||||
|
// Relational
|
||||||
|
case ast::InfixOperator::LessThan:
|
||||||
|
case ast::InfixOperator::GreaterThan:
|
||||||
|
case ast::InfixOperator::LessEqual:
|
||||||
|
case ast::InfixOperator::GreaterEqual: return { 9, 10 };
|
||||||
|
|
||||||
|
// Equality
|
||||||
|
case ast::InfixOperator::Equal:
|
||||||
|
case ast::InfixOperator::NotEqual: return { 7, 8 };
|
||||||
|
|
||||||
|
// Bitwise
|
||||||
|
case ast::InfixOperator::BitAnd: return { 6, 7 };
|
||||||
|
case ast::InfixOperator::BitXor: return { 5, 6 };
|
||||||
|
case ast::InfixOperator::BitOr: return { 4, 5 };
|
||||||
|
|
||||||
|
// Logical
|
||||||
|
case ast::InfixOperator::BoolAnd: return { 3, 4 };
|
||||||
|
case ast::InfixOperator::BoolOr: return { 1, 2 };
|
||||||
|
|
||||||
|
// Assignment (Right-associative: left > right)
|
||||||
|
case ast::InfixOperator::Assignment:
|
||||||
|
case ast::InfixOperator::AdditionAssignment:
|
||||||
|
case ast::InfixOperator::SubstractionAssignment:
|
||||||
|
case ast::InfixOperator::MultiplicationAssignment:
|
||||||
|
case ast::InfixOperator::DivisionAssignment:
|
||||||
|
case ast::InfixOperator::ModuloAssignment:
|
||||||
|
case ast::InfixOperator::BitAndAssignment:
|
||||||
|
case ast::InfixOperator::BitOrAssignment:
|
||||||
|
case ast::InfixOperator::BoolAndAssignment:
|
||||||
|
case ast::InfixOperator::BoolOrAssignment:
|
||||||
|
case ast::InfixOperator::LShiftAssignment:
|
||||||
|
case ast::InfixOperator::RShiftAssignment: return { 2, 1 };
|
||||||
|
|
||||||
|
default: return { 0, 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint16_t postfixBindingPower(ast::PostfixOperator op) {
|
||||||
|
switch (op) {
|
||||||
|
// Postfix usually has the highest precedence (e.g., function calls,
|
||||||
|
// slicing)
|
||||||
|
case ast::PostfixOperator::FunctionCall:
|
||||||
|
case ast::PostfixOperator::SliceAccess:
|
||||||
|
case ast::PostfixOperator::SliceSize:
|
||||||
|
case ast::PostfixOperator::PtrToSlice:
|
||||||
|
case ast::PostfixOperator::SliceToPtr:
|
||||||
|
case ast::PostfixOperator::Reflect: return 19;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace arti::lang::pratt
|
||||||
Loading…
x
Reference in New Issue
Block a user