1 // =================================
  2 // Copyright (c) 2020 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 [hpp]#include <sngcm/cmparser/ParserApi.hpp>
  7 [hpp]#include <sngcm/ast/Concept.hpp>
  8 [hpp]#include <sngcm/cmparser/ParsingContext.hpp>
  9 [cpp]#include <sngcm/cmparser/Parameter.hpp>
 10 [cpp]#include <sngcm/cmparser/Specifier.hpp>
 11 [cpp]#include <sngcm/cmparser/TypeExpr.hpp>
 12 [cpp]#include <sngcm/cmparser/Identifier.hpp>
 13 [cpp]#include <sngcm/cmparser/Expression.hpp>
 14 [cpp]#include <sngcm/cmparser/Function.hpp>
 15 [cpp]#include <sngcm/cmlexer/CmajorLexer.hpp>
 16 [cpp]#include <sngcm/cmlexer/CmajorTokens.hpp>
 17 
 18 using namespace sngcm::ast;
 19 using namespace CmajorTokens;
 20 
 21 parser api(SNGCM_PARSER_API) ConceptParser
 22 {
 23     uselexer CmajorLexer;
 24 
 25     using SpecifierParser.Specifiers;
 26     using IdentifierParser.Identifier;
 27     using IdentifierParser.QualifiedId;
 28     using ParameterParser.ParameterList;
 29     using ExpressionParser.Expression;
 30     using ExpressionParser.InvokeExpr;
 31     using TypeExprParser.TypeExpr;
 32     using FunctionParser.FunctionGroupId;
 33 
 34     Concept(ParsingContext* ctx, var std::unique_ptr conceptNode, var std::unique_ptr constraint,
 35         var Span s, var Span beginBraceSpan, var Span endBraceSpan) : ConceptNode*
 36         ::= empty{ ctx->BeginParsingConcept(); }
 37         (   (Specifiers:specifiers{ s = span; } CONCEPT Identifier:conceptName!){ conceptNode.reset(new ConceptNode(span, specifiers, conceptName)); }
 38             LANGLE! (Identifier:typeParam{ conceptNode->AddTypeParameter(typeParam); } % COMMA) RANGLE!
 39             ((Refinement:refinement{ conceptNode->SetRefinement(refinement); })?
 40             (WhereConstraint(ctx):c{ s.end = span.end; constraint.reset(c); constraint->SetHeaderConstraint(); conceptNode->AddConstraint(constraint.release()); })?){ conceptNode->SetSpan(s); }
 41             LBRACE!{ beginBraceSpan = span; } ConceptBody(ctx, conceptNode.get()):body! RBRACE!{ endBraceSpan = span; }
 42         )
 43         {
 44             ctx->EndParsingConcept();
 45             conceptNode->SetBeginBraceSpan(beginBraceSpan);
 46             conceptNode->SetEndBraceSpan(endBraceSpan);
 47             return conceptNode.release();
 48         }
 49         /
 50         {
 51             ctx->EndParsingConcept();
 52         }
 53         ;
 54 
 55     Refinement(var std::unique_ptr conceptId) : ConceptIdNode*
 56         ::= (COLON QualifiedId:refinedConcept{ conceptId.reset(new ConceptIdNode(span, refinedConcept)); }
 57             LANGLE! (Identifier:typeParam{ conceptId->AddTypeParameter(typeParam); } % COMMA) RANGLE!){ return conceptId.release(); }
 58         ;
 59 
 60 
 61     ConceptBody(ParsingContext* ctx, sngcm::ast::ConceptNode* conceptNode)
 62         ::= (ConceptBodyConstraint(ctx, conceptNode):bodyConstraint | Axiom(ctx, conceptNode):axiom)*
 63         ;
 64 
 65     ConceptBodyConstraint(ParsingContext* ctx, sngcm::ast::ConceptNode* conceptNode)
 66         ::= TypeNameConstraint(ctx):typeNameConstraint{ conceptNode->AddConstraint(typeNameConstraint); }
 67         |   SignatureConstraint(ctx, conceptNode->TypeParameters()[0]):signatureConstraint{ conceptNode->AddConstraint(signatureConstraint); }
 68         |   EmbeddedConstraint(ctx):embeddedConstraint{ conceptNode->AddConstraint(embeddedConstraint); }
 69         ;
 70 
 71     TypeNameConstraint(ParsingContext* ctx, var Span s) : ConstraintNode*
 72         ::= TYPENAME{ s = span; } TypeExpr(ctx):type! SEMICOLON!{ s.end = span.end; return new TypeNameConstraintNode(s, type); }
 73         ;
 74 
 75     SignatureConstraint(ParsingContext* ctx, sngcm::ast::IdentifierNode* firstTypeParameter) : ConstraintNode*
 76         ::= ConstructorConstraint(ctx, firstTypeParameter):constructorConstraint{ return constructorConstraint; }
 77         |   DestructorConstraint(ctx, firstTypeParameter):destructorConstraint{ return destructorConstraint; }
 78         |   MemberFunctionConstraint(ctx):memberFunctionConstraint{ return memberFunctionConstraint; }
 79         |   FunctionConstraint(ctx):functionConstraint{ return functionConstraint; }
 80         ;
 81 
 82     ConstructorConstraint(ParsingContext* ctx, sngcm::ast::IdentifierNode* firstTypeParameter, var std::unique_ptr ctorConstraint, var Span e) : ConstraintNode*
 83         ::= (EXPLICIT? Identifier:id{ std::u32string className = lexer.GetMatch(span); pass = className == firstTypeParameter->Str(); if (pass) ctorConstraint.reset(new ConstructorConstraintNode(span, id)); }
 84             ParameterList(ctx, ctorConstraint.get()):paramList SEMICOLON!{ e = span; }){ ctorConstraint->SetSpanEnd(e.end); return ctorConstraint.release(); }
 85         ;
 86 
 87     DestructorConstraint(ParsingContext* ctx, sngcm::ast::IdentifierNode* firstTypeParameter, var Span s) : ConstraintNode*
 88         ::= (CPL{ s = span; } Identifier:id{ std::u32string className = lexer.GetMatch(span); pass = className == firstTypeParameter->Str(); } LPAREN! RPAREN! SEMICOLON!{ s.end = span.end; })
 89         {
 90             return new DestructorConstraintNode(s, id);
 91         }
 92         ;
 93 
 94     MemberFunctionConstraint(ParsingContext* ctx, var std::unique_ptr memberFunctionConstraint) : ConstraintNode*
 95         ::= (TypeExpr(ctx):returnType Identifier:typeParam DOT FunctionGroupId(ctx):functionGroupId!){ memberFunctionConstraint.reset(new MemberFunctionConstraintNode(span, returnType, typeParam, functionGroupId)); }
 96             ParameterList(ctx, memberFunctionConstraint.get()):paramList! SEMICOLON!{ memberFunctionConstraint->SetSpanEnd(span.end); return memberFunctionConstraint.release(); }
 97         ;
 98 
 99     FunctionConstraint(ParsingContext* ctx, var std::unique_ptr functionConstraint) : ConstraintNode*
100         ::= (TypeExpr(ctx):returnType FunctionGroupId(ctx):functionGroupId!){ functionConstraint.reset(new FunctionConstraintNode(span, returnType, functionGroupId)); }
101             ParameterList(ctx, functionConstraint.get()):paramList! SEMICOLON!{ functionConstraint->SetSpanEnd(span.end); return functionConstraint.release(); }
102         ;
103 
104     EmbeddedConstraint(ParsingContext* ctx, var std::unique_ptr constraint) : WhereConstraintNode*
105         ::= (WhereConstraint(ctx):c SEMICOLON!){ constraint.reset(c); constraint->SetSemicolon(); return constraint.release(); }
106         ;
107 
108     WhereConstraint(ParsingContext* ctx, var Span s) : WhereConstraintNode*
109         ::= WHERE{ s = span; } ConstraintExpr(ctx):constraint!{ s.end = span.end; return new WhereConstraintNode(s, constraint); }
110         ;
111 
112     ConstraintExpr(ParsingContext* ctx) : ConstraintNode*
113         ::= DisjunctiveConstraintExpr(ctx):disjunctiveConstraint{ return disjunctiveConstraint; }
114         ;
115 
116     DisjunctiveConstraintExpr(ParsingContext* ctx, var Span s, var std::unique_ptr constraint) : ConstraintNode*
117         ::=
118         (   ConjunctiveConstraintExpr(ctx):left{ constraint.reset(left); s = span; }
119             (   OR ConjunctiveConstraintExpr(ctx):right{ s.end = span.end; constraint.reset(new DisjunctiveConstraintNode(s, constraint.release(), right)); })*
120         )
121         {
122             return constraint.release();
123         }
124         ;
125 
126     ConjunctiveConstraintExpr(ParsingContext* ctx, var Span s, var std::unique_ptr constraint) : ConstraintNode*
127         ::=
128         (   PrimaryConstraintExpr(ctx):left{ constraint.reset(left); s = span; }
129             (   AND PrimaryConstraintExpr(ctx):right{ s.end = span.end; constraint.reset(new ConjunctiveConstraintNode(s, constraint.release(), right)); })*
130         )
131         {
132             return constraint.release();
133         }
134         ;
135 
136     PrimaryConstraintExpr(ParsingContext* ctx, var Span s) : ConstraintNode*
137         ::= LPAREN{ s = span; } ConstraintExpr(ctx):constraint RPAREN!{ s.end = span.end; return new ParenthesizedConstraintNode(s, constraint); }
138         |   AtomicConstraintExpr(ctx):atomicConstraint{ return atomicConstraint; }
139         ;
140 
141     AtomicConstraintExpr(ParsingContext* ctx) : ConstraintNode*
142         ::= PredicateConstraint(ctx):predicateConstraint{ return predicateConstraint; }
143         |   IsConstraint(ctx):isConstraint{ return isConstraint; }
144         |   MultiParamConstraint(ctx):multiParamConstraint{ return multiParamConstraint; }
145         ;
146 
147     PredicateConstraint(ParsingContext* ctx) : ConstraintNode*
148         ::= InvokeExpr(ctx):invokeExpr{ return new PredicateConstraintNode(span, invokeExpr); }
149         ;
150 
151     IsConstraint(ParsingContext* ctx, var Span s) : ConstraintNode*
152         ::= TypeExpr(ctx):type{ s = span; } IS ConceptOrTypeName(ctx):conceptOrTypeName!{ s.end = span.end; return new IsConstraintNode(s, type, conceptOrTypeName); }
153         ;
154 
155     ConceptOrTypeName(ParsingContext* ctx) : Node*
156         ::= TypeExpr(ctx):conceptOrTypeName{ return conceptOrTypeName; }
157         ;
158 
159     MultiParamConstraint(ParsingContext* ctx, var std::unique_ptr constraint) : ConstraintNode*
160         ::= QualifiedId:id{ constraint.reset(new MultiParamConstraintNode(span, id)); }
161             LANGLE (TypeExpr(ctx):typeExpr{ constraint->AddTypeExpr(typeExpr); } % COMMA) RANGLE!{ constraint->SetSpanEnd(span.end); return constraint.release(); }
162         ;
163 
164     Axiom(ParsingContext* ctx, sngcm::ast::ConceptNode* conceptNode, var std::unique_ptr axiomNode, var Span axiomSpan, var Span beginBraceSpan, var Span endBraceSpan)
165         ::=
166         (   AXIOM{ axiomSpan = span; } Identifier:id? empty{ axiomNode.reset(new AxiomNode(axiomSpan, id)); }
167             ParameterList(ctx, axiomNode.get()):paramList?
168             LBRACE!{ beginBraceSpan = span; } AxiomBody(ctx, axiomNode.get()):axiomBody! RBRACE!{ endBraceSpan = span; }
169         )
170         {
171             axiomNode->SetBeginBraceSpan(beginBraceSpan);
172             axiomNode->SetEndBraceSpan(endBraceSpan);
173             conceptNode->AddAxiom(axiomNode.release());
174         }
175         ;
176 
177     AxiomBody(ParsingContext* ctx, sngcm::ast::AxiomNode* axiom)
178         ::= (AxiomStatement(ctx):stmt{ axiom->AddStatement(stmt); })*
179         ;
180 
181     AxiomStatement(ParsingContext* ctx, var Span s) : AxiomStatementNode*
182         ::= (Expression(ctx):expr{ s = span; } SEMICOLON!{ s.end = span.end; }){ return new AxiomStatementNode(s, expr, lexer.GetMatch(s)); }
183         ;
184 
185     ruleinfo
186     {
187         (Concept, "conceptNode"), (Refinement, "refinement"), (ConceptBody, "concept body"), (ConceptBodyConstraint, "concept body constraint"), (TypeNameConstraint, "type name constraint"),
188         (SignatureConstraint, "signature constraint"), (ConstructorConstraint, "constructor constraint"), (DestructorConstraint, "destructor constraint"),
189         (MemberFunctionConstraint, "member function constraint"), (FunctionConstraint, "function constraint"), (EmbeddedConstraint, "embedded constraint"),
190         (WhereConstraint, "where constraint"), (ConstraintExpr, "constraint expression"), (DisjunctiveConstraintExpr, "disjunctive constraint expression"),
191         (ConjunctiveConstraintExpr, "conjunctive constraint expression"), (PrimaryConstraintExpr, "primary constraint expression"), (AtomicConstraintExpr, "atomic constraint expression"),
192         (PredicateConstraint, "preficate constraint"), (IsConstraint,"is constraint"), (ConceptOrTypeName, "concept or type name"), (MultiParamConstraint, "multiparameter constraint"),
193         (Axiom, "axiom"), (AxiomBody, "axiom body"), (AxiomStatement, "axiom statement")
194     }
195 
196 }