Skip to content

Commit 6e62c9a

Browse files
committed
first pass at implementing match expression
1 parent 7de81ca commit 6e62c9a

File tree

8 files changed

+123
-0
lines changed

8 files changed

+123
-0
lines changed

src/ast.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ AST.prototype.checkNodes = function () {
486486
require("./ast/declaration"),
487487
require("./ast/declare"),
488488
require("./ast/declaredirective"),
489+
require("./ast/defaultkeyword"),
489490
require("./ast/do"),
490491
require("./ast/echo"),
491492
require("./ast/empty"),
@@ -514,6 +515,7 @@ AST.prototype.checkNodes = function () {
514515
require("./ast/literal"),
515516
require("./ast/lookup"),
516517
require("./ast/magic"),
518+
require("./ast/match"),
517519
require("./ast/method"),
518520
require("./ast/name"),
519521
require("./ast/namespace"),

src/ast/defaultkeyword.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Copyright (C) 2018 Glayzzle (BSD3 License)
3+
* @authors https://github.com/glayzzle/php-parser/graphs/contributors
4+
* @url http://glayzzle.com
5+
*/
6+
"use strict";
7+
8+
const Node = require("./node");
9+
const KIND = "defaultkeyword";
10+
11+
/**
12+
* Represents the null keyword
13+
* @constructor NullKeyword
14+
* @extends {Node}
15+
*/
16+
module.exports = Node.extends(KIND, function DefaultKeyword(
17+
raw,
18+
docs,
19+
location
20+
) {
21+
Node.apply(this, [KIND, docs, location]);
22+
this.raw = raw;
23+
});

src/ast/match.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Copyright (C) 2018 Glayzzle (BSD3 License)
3+
* @authors https://github.com/glayzzle/php-parser/graphs/contributors
4+
* @url http://glayzzle.com
5+
*/
6+
"use strict";
7+
8+
const Expression = require("./expression");
9+
const KIND = "match";
10+
11+
/**
12+
* Defines a match expression
13+
* @constructor Match
14+
* @extends {Expression}
15+
* @property {Expression} test
16+
* @property {Block} body
17+
* @property {boolean} shortForm
18+
*/
19+
module.exports = Expression.extends(KIND, function Match(
20+
test,
21+
body,
22+
docs,
23+
location
24+
) {
25+
Expression.apply(this, [KIND, docs, location]);
26+
this.test = test;
27+
this.body = body;
28+
});

src/lexer.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ const lexer = function (engine) {
106106
or: this.tok.T_LOGICAL_OR,
107107
and: this.tok.T_LOGICAL_AND,
108108
xor: this.tok.T_LOGICAL_XOR,
109+
match: this.tok.T_MATCH,
109110
};
110111
this.castKeywords = {
111112
int: this.tok.T_INT_CAST,

src/parser.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ const parser = function (lexer, ast) {
9696
this.tok.T_LOGICAL_AND,
9797
this.tok.T_LOGICAL_OR,
9898
this.tok.T_LOGICAL_XOR,
99+
this.tok.T_MATCH,
99100
this.tok.T_METHOD_C,
100101
this.tok.T_NAMESPACE,
101102
this.tok.T_NEW,
@@ -192,6 +193,7 @@ const parser = function (lexer, ast) {
192193
this.tok.T_NEW,
193194
this.tok.T_ISSET,
194195
this.tok.T_EMPTY,
196+
this.tok.T_MATCH,
195197
this.tok.T_INCLUDE,
196198
this.tok.T_INCLUDE_ONCE,
197199
this.tok.T_REQUIRE,

src/parser/expr.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,9 @@ module.exports = {
320320
case this.tok.T_REQUIRE:
321321
case this.tok.T_REQUIRE_ONCE:
322322
return this.read_internal_functions_in_yacc();
323+
324+
case this.tok.T_MATCH:
325+
return this.read_match_statement();
323326
case this.tok.T_INT_CAST:
324327
return this.read_expr_cast("int");
325328

@@ -602,6 +605,53 @@ module.exports = {
602605
);
603606
},
604607

608+
read_match_statement: function () {
609+
const node = this.node("match");
610+
this.expect(this.tok.T_MATCH) && this.next();
611+
if (!this.version >= 800) {
612+
this.reaseError("Match statements are not allowed");
613+
}
614+
let source = null;
615+
let body = null;
616+
if (this.expect("(")) this.next();
617+
source = this.read_expr();
618+
if (this.expect(")")) this.next();
619+
if (this.expect("{")) this.next();
620+
body = this.read_match_list();
621+
if (this.expect("}")) this.next();
622+
return node(source, body);
623+
},
624+
625+
read_match_list: function () {
626+
return this.read_list(() => this.read_match_pair(), ",", true);
627+
},
628+
629+
read_match_pair: function () {
630+
if (this.token === "}") {
631+
return;
632+
}
633+
634+
if (this.token === ",") {
635+
return this.node("noop")();
636+
}
637+
638+
const entry = this.node("entry");
639+
640+
let key = null;
641+
if (this.token === this.tok.T_DEFAULT) {
642+
key = this.node("defaultkeyword")("default");
643+
this.next();
644+
} else {
645+
key = this.read_expr();
646+
}
647+
if (this.expect(this.tok.T_DOUBLE_ARROW)) {
648+
this.next();
649+
}
650+
const value = this.read_expr();
651+
652+
return entry(key, value, false, false);
653+
},
654+
605655
/**
606656
* ```ebnf
607657
* new_expr ::= T_NEW (namespace_name function_argument_list) | (T_CLASS ... class declaration)

src/tokens.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ module.exports = {
147147
234: "T_COALESCE_EQUAL",
148148
235: "T_FN",
149149
236: "T_NULLSAFE_OBJECT_OPERATOR",
150+
237: "T_MATCH",
150151
},
151152
names: {
152153
T_HALT_COMPILER: 101,
@@ -285,5 +286,6 @@ module.exports = {
285286
T_COALESCE_EQUAL: 234,
286287
T_FN: 235,
287288
T_NULLSAFE_OBJECT_OPERATOR: 236,
289+
T_MATCH: 237,
288290
},
289291
};

test/snapshot/match.test.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const parser = require("../main");
2+
3+
describe("match", () => {
4+
it("can be parsed", () => {
5+
const ast = parser.parseEval(`
6+
$test = match($a) {
7+
true => 'yes',
8+
false => 'no',
9+
default => null,
10+
};
11+
`);
12+
console.log(ast.children[0].expression.right.body);
13+
// expect (ast).toMatchSnapshot();
14+
});
15+
});

0 commit comments

Comments
 (0)