Skip to content

Commit

Permalink
fix(lexer): handle unary minus operator (#262)
Browse files Browse the repository at this point in the history
* fix(lexer): handle unary minus operator

add tests for lexer

* avoid duplication of top value

---------

Co-authored-by: Jeremy Valentine <[email protected]>
  • Loading branch information
twiescha and valentine195 authored Oct 26, 2023
1 parent 0f2c599 commit 139cbfa
Show file tree
Hide file tree
Showing 4 changed files with 446 additions and 12 deletions.
44 changes: 32 additions & 12 deletions src/parser/lexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as moo from "moo";
import DiceRollerPlugin from "src/main";
import { Conditional } from "src/types";
import { Parser } from "./parser";
import copy from "fast-copy";

export const TAG_REGEX =
/(?:\d+[Dd])?#(?:[\p{Letter}\p{Emoji_Presentation}\w/-]+)(?:\|(?:[+-]))?(?:\|(?:[^+-]+))?/u;
Expand Down Expand Up @@ -133,7 +134,7 @@ export default class Lexer {
"^": exponent
});
}
parse(input: string) {
parse(input: string): LexicalToken[] {
const tokens = Array.from(this.lexer.reset(input));
this.lexer.reset();
return this.parser.parse(this.transform(tokens));
Expand All @@ -142,18 +143,37 @@ export default class Lexer {
tokens = tokens.filter((token) => {
return token.type != "WS";
});
let clone: LexicalToken[] = [];
/** If the first token is a negative sign and the second is a dice roller, just make the dice roller negative. */
if (tokens.length >= 2) {
if (
(tokens[0].type === "-" ||
(tokens[0].type === "math" && tokens[0].value === "-")) &&
tokens[1].type === "dice"
) {
tokens[1].value = `-${tokens[1].value}`;
tokens.shift();

let isPlus = (t: moo.Token) =>
t.type === "+" || (t.type === "math" && t.value === "+");
let isMinus = (t: moo.Token) =>
t.type === "-" || (t.type === "math" && t.value === "-");
let isPlusOrMinus = (t: moo.Token) => isPlus(t) || isMinus(t);
let peek = (arr: moo.Token[]) => arr[arr.length - 1];
let replaceTop = (arr: moo.Token[], newTop: moo.Token) =>
arr.splice(arr.length - 1, 1, newTop);

tokens = tokens.reduce((acc, e) => {
if (acc.length == 0) {
acc.push(e);
} else {
let top = peek(acc);

if (isPlusOrMinus(top) && isPlusOrMinus(e)) {
if (isMinus(top) != isMinus(e)) {
// one minus => minus
if (!isMinus(top)) replaceTop(acc, e);
} else if (isMinus(top)) {
top.type = top.type === "math" ? top.type : "+";
top.value = "+";
}
} else {
acc.push(e);
}
}
}
return acc;
}, [] as moo.Token[]);
let clone: LexicalToken[] = [];
for (const token of tokens) {
if (token.type == "condition" && clone.length > 0) {
const previous = clone[clone.length - 1];
Expand Down
Loading

0 comments on commit 139cbfa

Please sign in to comment.