-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathQMatchExpression.cpp
More file actions
145 lines (125 loc) · 3.63 KB
/
Copy pathQMatchExpression.cpp
File metadata and controls
145 lines (125 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <assert.h>
#include <iostream>
#include "FileLexer.h"
#include "Type.h"
#include "Expression.h"
#include "CompilerHelpers.h"
#include "logging.h"
SET_LOG_CAT( LOG_CAT_ALL );
SET_LOG_LEVEL( LOG_LVL_NOISE );
using namespace QLang;
using namespace std;
MatchExpression *MatchExpression::Parse( Lexer &l, Scope *scope, bool exprMode )
{
TRACE_BEGIN( LOG_LVL_INFO );
SourceLocation loc = l.getTokenLocation();
// Consume 'match' keyword
int sym = l.getSymbol();
if ( sym != Lexer::KEYWORD_MATCH )
{
COMPILE_ERROR( l, "Internal Error: expected 'match' keyword" );
}
MatchExpression *expr = new MatchExpression;
expr->setLocation( loc );
expr->mExprMode = exprMode;
// Parse the subject expression (a primary expression before '{')
expr->mSubject = Expression::ParsePrimary( l, scope );
if ( expr->mSubject == nullptr )
{
COMPILE_ERROR( l, "Expected expression after 'match'" );
}
// Expect '{'
sym = l.getSymbol();
if ( sym != '{' )
{
COMPILE_ERROR( l, "Expected '{' after match subject" );
}
// Parse match arms until '}'
while ( l.peekSymbol() != '}' )
{
MatchArm arm;
// Parse pattern: integer literal, string literal, identifier, wildcard (_),
// or destructuring pattern like ok(value), some(x)
sym = l.peekSymbol();
if ( sym == Lexer::CONSTANT_NUMBER ||
sym == Lexer::CONSTANT_FLOAT ||
sym == Lexer::CONSTANT_STRING ||
sym == Lexer::CONSTANT_CHAR )
{
l.getSymbol();
arm.mPattern = l.getSymbolText();
arm.mPatternIsString = ( sym == Lexer::CONSTANT_STRING );
}
else if ( sym == Lexer::WILDCARD )
{
l.getSymbol();
arm.mPattern = "_";
arm.mIsWildcard = true;
}
else if ( sym == Lexer::SYMBOL )
{
l.getSymbol();
arm.mPattern = l.getSymbolText();
// Check for destructuring: pattern(binding, ...) — one binding per
// variant associated type: ok(value), some(x), pair(a, b)
if ( l.peekSymbol() == '(' )
{
l.getSymbol(); // consume '('
sym = l.getSymbol();
while ( sym == Lexer::SYMBOL )
{
arm.mBindingNames.push_back( l.getSymbolText() );
sym = l.getSymbol();
if ( sym == ',' )
sym = l.getSymbol();
else
break;
}
if ( sym != ')' )
COMPILE_ERROR( l, "Expected ')' after binding name(s) in match pattern" );
}
}
else
{
COMPILE_ERROR( l, "Expected pattern in match arm (constant, identifier, or '_')" );
}
// Parse the arm body as a Block
Scope *armScope = new Scope( Scope::kScope_Anonymous );
armScope->setParent( scope );
// Add each binding to the arm scope
for ( auto &bname : arm.mBindingNames )
{
Type *varType = new Type( "var" );
VariableDefinition *binding = new VariableDefinition( varType, bname );
armScope->addSymbol( binding );
}
if ( exprMode )
{
// Expression-form arm: `pattern { expression }` — exactly one
// expression, no semicolon; its value is the arm's result.
sym = l.getSymbol();
if ( sym != '{' )
COMPILE_ERROR( l, "Expected '{' after match arm pattern" );
arm.mValue = Expression::ParseExpr( l, armScope, 0 );
if ( arm.mValue == nullptr )
COMPILE_ERROR( l, "Expected expression in match arm (a value-producing match arm holds a single expression)" );
sym = l.getSymbol();
if ( sym != '}' )
COMPILE_ERROR( l, "Expected '}' after match arm expression (a value-producing match arm holds a single expression, no ';')" );
arm.mScope = armScope;
}
else
{
arm.mBody = Block::Parse( l, armScope );
if ( arm.mBody == nullptr )
{
COMPILE_ERROR( l, "Expected block body for match arm" );
}
}
expr->mArms.push_back( arm );
}
// Consume '}'
sym = l.getSymbol();
assert( sym == '}' );
return expr;
}