add find-closing-brace util function
This commit is contained in:
@ -1,6 +1,24 @@
|
|||||||
import { abstractSyntaxTree } from "./abstractSyntaxTree";
|
import { abstractSyntaxTree, findClosingBrace } from "./abstractSyntaxTree";
|
||||||
import { lexer } from "./tokeniser";
|
import { lexer } from "./tokeniser";
|
||||||
|
|
||||||
|
describe("findClosingBrace", () => {
|
||||||
|
test("finds the closing brace", () => {
|
||||||
|
const basic = "( hey )"
|
||||||
|
expect(findClosingBrace(lexer(basic), 0)).toBe(4)
|
||||||
|
|
||||||
|
const handlesNonZeroIndex = "(indexForBracketToRightOfThisIsTwo(shouldBeFour)AndNotThisSix)"
|
||||||
|
expect(findClosingBrace(lexer(handlesNonZeroIndex), 2)).toBe(4)
|
||||||
|
expect(findClosingBrace(lexer(handlesNonZeroIndex), 0)).toBe(6)
|
||||||
|
|
||||||
|
const handlesNested = "{a{b{c(}d]}eathou athoeu tah u} thatOneToTheLeftIsLast }"
|
||||||
|
expect(findClosingBrace(lexer(handlesNested), 0)).toBe(18)
|
||||||
|
|
||||||
|
// throws when not started on a brace
|
||||||
|
expect(() => findClosingBrace(lexer(handlesNested), 1)).toThrow()
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("testing AST", () => {
|
describe("testing AST", () => {
|
||||||
test("test 5 + 6", () => {
|
test("test 5 + 6", () => {
|
||||||
const tokens = lexer("5 +6");
|
const tokens = lexer("5 +6");
|
||||||
|
@ -402,3 +402,57 @@ export const abstractSyntaxTree = (tokens: Token[]): Program => {
|
|||||||
};
|
};
|
||||||
return program;
|
return program;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function findClosingBrace(
|
||||||
|
tokens: Token[],
|
||||||
|
index: number,
|
||||||
|
_braceCount: number = 0,
|
||||||
|
_searchOpeningBrace: string = ""
|
||||||
|
): number {
|
||||||
|
const closingBraceMap: { [key: string]: string } = {
|
||||||
|
"(": ")",
|
||||||
|
"{": "}",
|
||||||
|
"[": "]",
|
||||||
|
};
|
||||||
|
const currentToken = tokens[index];
|
||||||
|
let searchOpeningBrace = _searchOpeningBrace;
|
||||||
|
|
||||||
|
const isFirstCall = !searchOpeningBrace && _braceCount === 0;
|
||||||
|
if (isFirstCall) {
|
||||||
|
searchOpeningBrace = currentToken.value;
|
||||||
|
if (!["(", "{", "["].includes(searchOpeningBrace)) {
|
||||||
|
throw new Error(
|
||||||
|
`expected to be started on a opening brace ( { [, instead found '${searchOpeningBrace}'`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const foundClosingBrace =
|
||||||
|
_braceCount === 1 &&
|
||||||
|
currentToken.value === closingBraceMap[searchOpeningBrace];
|
||||||
|
const foundAnotherOpeningBrace = currentToken.value === searchOpeningBrace;
|
||||||
|
const foundAnotherClosingBrace =
|
||||||
|
currentToken.value === closingBraceMap[searchOpeningBrace];
|
||||||
|
|
||||||
|
if (foundClosingBrace) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
if (foundAnotherOpeningBrace) {
|
||||||
|
return findClosingBrace(
|
||||||
|
tokens,
|
||||||
|
index + 1,
|
||||||
|
_braceCount + 1,
|
||||||
|
searchOpeningBrace
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (foundAnotherClosingBrace) {
|
||||||
|
return findClosingBrace(
|
||||||
|
tokens,
|
||||||
|
index + 1,
|
||||||
|
_braceCount - 1,
|
||||||
|
searchOpeningBrace
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// non-brace token, increment and continue
|
||||||
|
return findClosingBrace(tokens, index + 1, _braceCount, searchOpeningBrace);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user