Skip to content

Several fixes #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
657 changes: 459 additions & 198 deletions dist/regexer.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/regexer.min.js

Large diffs are not rendered by default.

23 changes: 14 additions & 9 deletions src/Regexer.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,17 @@ export default class Regexer {
}

/**
* @param {Regexer<Parser<any>>} lhs
* @param {Regexer<Parser<any>>} rhs
* @param {Regexer<Parser<any>> | Parser<any>} lhs
* @param {Regexer<Parser<any>> | Parser<any>} rhs
*/
static equals(lhs, rhs, strict = false) {
const a = lhs.getParser()
const b = rhs.getParser()
return a.equals(Reply.makeContext(lhs), b, strict)
const a = lhs instanceof Regexer ? lhs.getParser() : lhs
const b = rhs instanceof Regexer ? rhs.getParser() : rhs
return a.equals(
Reply.makeContext(lhs instanceof Regexer ? lhs : rhs instanceof Regexer ? rhs : null),
b,
strict
)
}

getParser() {
Expand Down Expand Up @@ -146,11 +150,11 @@ export default class Regexer {
}

static success(value = undefined) {
return new this(new SuccessParser(value))
return new this(value === undefined ? SuccessParser.instance : new SuccessParser())
}

static failure() {
return new this(new FailureParser())
return new this(FailureParser.instance)
}

// Combinators
Expand Down Expand Up @@ -265,7 +269,7 @@ export default class Regexer {
*/
assert(fn) {
return this.chain((v, input, position) => fn(v, input, position)
? this.Self.success(v)
? this.Self.success().map(() => v)
: this.Self.failure()
)
}
Expand All @@ -275,6 +279,7 @@ export default class Regexer {
}

toString(indent = 0, newline = false) {
return (newline ? "\n" + Parser.indentation.repeat(indent) : "") + this.#parser.toString(indent)
return (newline ? "\n" + Parser.indentation.repeat(indent) : "")
+ this.#parser.toString(Reply.makeContext(this, ""), indent)
}
}
3 changes: 2 additions & 1 deletion src/Reply.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ export default class Reply {
return /** @type {Context} */({
regexer: regexer,
input: input,
visited: new PairMap()
equals: new PairMap(),
visited: new Set(),
})
}
}
44 changes: 40 additions & 4 deletions src/parser/AlternativeParser.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Parser from "./Parser.js"
import Reply from "../Reply.js"
import StringParser from "./StringParser.js"
import SuccessParser from "./SuccessParser.js"

/**
* @template {Parser<any>[]} T
Expand All @@ -21,6 +23,27 @@ export default class AlternativeParser extends Parser {
constructor(...parsers) {
super()
this.#parsers = parsers
if (this.#parsers.length === 1) {
this.isActualParser = false
}
}

/** @protected */
doMatchesEmpty() {
return this.#parsers.some(p => p.matchesEmpty())
}

/**
* @protected
* @param {Context} context
*/
doStarterList(context, additional = /** @type {Parser<any>[]} */([])) {
return this.#parsers
.flatMap(p => p.starterList(context))
.reduce(
(acc, cur) => acc.some(p => p.equals(context, cur, true)) ? acc : (acc.push(cur), acc),
/** @type {Parser<any>[]} */([])
)
}

unwrap() {
Expand Down Expand Up @@ -61,6 +84,7 @@ export default class AlternativeParser extends Parser {
}

/**
* @protected
* @param {Context} context
* @param {Parser<any>} other
* @param {Boolean} strict
Expand All @@ -81,13 +105,25 @@ export default class AlternativeParser extends Parser {
return true
}

toString(indent = 0) {
/**
* @protected
* @param {Context} context
*/
doToString(context, indent = 0) {
const indentation = Parser.indentation.repeat(indent)
const deeperIndentation = Parser.indentation.repeat(indent + 1)
if (this.#parsers.length === 2 && this.#parsers[1] instanceof SuccessParser) {
let result = this.#parsers[0].toString(context, indent)
if (!(this.#parsers[0] instanceof StringParser) && !context.visited.has(this.#parsers[0])) {
result = "<" + result + ">"
}
result += "?"
return result
}
return "ALT<\n"
+ this.#parsers
.map(p => deeperIndentation + p.toString(indent + 1))
.join("\n" + deeperIndentation + "|\n")
+ deeperIndentation + this.#parsers
.map(p => p.toString(context, indent + 1))
.join("\n" + deeperIndentation + "| ")
+ "\n" + indentation + ">"
}
}
22 changes: 21 additions & 1 deletion src/parser/AnchorParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export const AnchorType = {
*/
export default class AnchorParser extends Parser {

static isTerminal = true

#type

/** @param {T} type */
Expand All @@ -25,6 +27,19 @@ export default class AnchorParser extends Parser {
this.#type = type
}

/** @protected */
doMatchesEmpty() {
return true
}

/**
* @protected
* @param {Context} context
*/
doStarterList(context, additional = /** @type {Parser<any>[]} */([])) {
return [this]
}

/**
* @param {Context} context
* @param {Number} position
Expand All @@ -43,6 +58,7 @@ export default class AnchorParser extends Parser {
}

/**
* @protected
* @param {Context} context
* @param {Parser<any>} other
* @param {Boolean} strict
Expand All @@ -51,7 +67,11 @@ export default class AnchorParser extends Parser {
return other instanceof AnchorParser && this.#type === other.#type
}

toString(indent = 0) {
/**
* @protected
* @param {Context} context
*/
doToString(context, indent = 0) {
return this.#type
}
}
17 changes: 11 additions & 6 deletions src/parser/AnyCharParser.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import Reply from "../Reply.js"
import RegExpParser from "./RegExpParser.js"

/** @extends RegExpParser<0> */
export default class AnyCharParser extends RegExpParser {

static isTerminal = true

#dotAll

/** @param {Boolean} dotAll */
Expand All @@ -13,14 +14,18 @@ export default class AnyCharParser extends RegExpParser {
}

/**
* In an alternative, this would always match parser could might
* @param {Parser<any>} parser
* @protected
* @param {Context} context
*/
dominates(parser) {
return this.#dotAll || !parser.actualParser().parse(Reply.makeContext("\n"), 0).status
doStarterList(context, additional = /** @type {Parser<any>[]} */([])) {
return [this]
}

toString(indent = 0) {
/**
* @protected
* @param {Context} context
*/
doToString(context, indent = 0) {
return "."
}
}
9 changes: 7 additions & 2 deletions src/parser/AtomicGroupParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default class AtomicGroupParser extends Parser {
}

/**
* @protected
* @param {Context} context
* @param {Parser<any>} other
* @param {Boolean} strict
Expand All @@ -48,7 +49,11 @@ export default class AtomicGroupParser extends Parser {
return other instanceof AtomicGroupParser && this.#parser.equals(context, other.#parser, strict)
}

toString(indent = 0) {
return "(?>" + this.#parser.toString(indent) + ")"
/**
* @protected
* @param {Context} context
*/
doToString(context, indent = 0) {
return "(?>" + this.#parser.toString(context, indent) + ")"
}
}
9 changes: 7 additions & 2 deletions src/parser/CapturingGroupParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export default class CapturingGroupParser extends Parser {
}

/**
* @protected
* @param {Context} context
* @param {Parser<any>} other
* @param {Boolean} strict
Expand All @@ -54,7 +55,11 @@ export default class CapturingGroupParser extends Parser {
&& this.#parser.equals(context, other.#parser, strict)
}

toString(indent = 0) {
return "(" + (this.#id !== "" ? `?<${this.#id}>` : "") + this.#parser.toString(indent) + ")"
/**
* @protected
* @param {Context} context
*/
doToString(context, indent = 0) {
return "(" + (this.#id !== "" ? `?<${this.#id}>` : "") + this.#parser.toString(context, indent) + ")"
}
}
14 changes: 12 additions & 2 deletions src/parser/ChainedParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ export default class ChainedParser extends Parser {
this.#fn = chained
}

/** @protected */
doMatchesEmpty() {
return false
}

unwrap() {
return [this.#parser]
}
Expand Down Expand Up @@ -52,6 +57,7 @@ export default class ChainedParser extends Parser {
}

/**
* @protected
* @param {Context} context
* @param {Parser<any>} other
* @param {Boolean} strict
Expand All @@ -62,7 +68,11 @@ export default class ChainedParser extends Parser {
&& this.#parser.equals(context, other.parser, strict)
}

toString(indent = 0) {
return this.#parser.toString(indent) + " => chained<f()>"
/**
* @protected
* @param {Context} context
*/
doToString(context, indent = 0) {
return this.#parser.toString(context, indent) + " => chained<f()>"
}
}
11 changes: 8 additions & 3 deletions src/parser/ClassParser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Reply from "../Reply.js"
import AlternativeParser from "./AlternativeParser.js"
import Parser from "./Parser.js"
import Reply from "../Reply.js"

/**
* @template {Parser<any>[]} T
Expand Down Expand Up @@ -45,6 +45,7 @@ export default class ClassParser extends AlternativeParser {
}

/**
* @protected
* @param {Context} context
* @param {Parser<any>} other
* @param {Boolean} strict
Expand All @@ -57,9 +58,13 @@ export default class ClassParser extends AlternativeParser {
&& super.doEquals(context, other, strict)
}

toString(indent = 0) {
/**
* @protected
* @param {Context} context
*/
doToString(context, indent = 0) {
return "["
+ this.parsers.map(p => p.toString(indent)).join("")
+ this.parsers.map(p => p.toString(context, indent)).join("")
+ "]"
}
}
7 changes: 6 additions & 1 deletion src/parser/ClassShorthandParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default class ClassShorthandParser extends RegExpParser {
}

/**
* @protected
* @param {Context} context
* @param {Parser<any>} other
* @param {Boolean} strict
Expand All @@ -40,7 +41,11 @@ export default class ClassShorthandParser extends RegExpParser {
return other instanceof ClassShorthandParser && this.#char == other.#char
}

toString(indent = 0) {
/**
* @protected
* @param {Context} context
*/
doToString(context, indent = 0) {
return "\\" + this.#char
}
}
11 changes: 8 additions & 3 deletions src/parser/EscapedCharParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export default class EscapedCharParser extends StringParser {
}

/**
* @protected
* @param {Context} context
* @param {Parser<any>} other
* @param {Boolean} strict
Expand All @@ -52,14 +53,18 @@ export default class EscapedCharParser extends StringParser {
&& super.doEquals(context, other, strict)
}

toString(indent = 0) {
/**
* @protected
* @param {Context} context
*/
doToString(context, indent = 0) {
switch (this.#type) {
case EscapedCharParser.Type.NORMAL:
return "\\" + (
Object.entries(EscapedCharParser.specialEscapedCharacters)
.find(([k, v]) => this.value === v)
?.[0]
?? super.toString(indent)
?? super.doToString(context, indent)
)
case EscapedCharParser.Type.HEX:
return "\\x" + this.value.codePointAt(0).toString(16)
Expand All @@ -68,6 +73,6 @@ export default class EscapedCharParser extends StringParser {
case EscapedCharParser.Type.UNICODE_FULL:
return "\\u{" + this.value.codePointAt(0).toString(16) + "}"
}
return super.toString(indent)
return super.doToString(context, indent)
}
}
Loading