Skip to content
Snippets Groups Projects
Commit bca3622f authored by Brady James Garvin's avatar Brady James Garvin
Browse files

Initial commit.

parents
No related branches found
No related tags found
No related merge requests found
# Disable line-ending conversions for this repository.
* -text
# dependencies
/node_modules
# testing
/coverage
# production
/build
# environments
.env.local
.env.development.local
.env.test.local
.env.production.local
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# misc
*~
.DS_Store
[submodule "eslint-config"]
path = eslint-config
url = git@git.unl.edu:csce-310/eslint-config.git
# Homework 5
Starter code for Homework 5 in the CSCE 310 course at UNL.
# Quick Start
Recursively clone this repository and `cd` into the root folder:
```
$ git clone --recursive git@git.unl.edu:csce-310/2023-fall-homework-5.git
$ cd 2023-fall-homework-5
```
(If you forget `--recursive` when cloning, you can `cd` into your clone and run
`git submodule update --init --recursive` instead.)
Install dependencies:
```
$ npm install
```
# Instructions
See <https://canvas.unl.edu/courses/158348/assignments/1576252>.
Subproject commit 16524f5ac58d4b13378261f1ab29bc1acc2a2099
{
"folders": [
{
"path": "."
}
],
"settings": {
"files.eol": "\n",
"files.exclude": {
"**/node_modules": true
},
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true
}
}
# dependencies
/node_modules
# testing
/coverage
# production
/build
# environments
.env.local
.env.development.local
.env.test.local
.env.production.local
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# misc
*~
.DS_Store
This diff is collapsed.
{
"name": "@unlcsce/homework-5",
"version": "1.0.0",
"description": "Starter code for Homework 5.",
"type": "module",
"private": true,
"license": "UNLICENSED",
"scripts": {
"lint:js": "eslint --max-warnings 0 ./src",
"lint": "run-s --continue-on-error lint:**",
"test-once:ascent": "node --experimental-vm-modules node_modules/jest/bin/jest.js -t \"after just ascent\"",
"test-once:matching": "node --experimental-vm-modules node_modules/jest/bin/jest.js -t \"after ascent and descent\"",
"test-once": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watchAll"
},
"dependencies": {
"npm-run-all": "^4.1.5"
},
"devDependencies": {
"@unlcsce/eslint-config": "file:../eslint-config",
"eslint": "^8.20.0",
"jest": "^29.5.0",
"jest-environment-node": "^29.5.0"
},
"eslintConfig": {
"extends": "@unlcsce"
},
"jest": {
"clearMocks": true,
"resetMocks": false,
"restoreMocks": false,
"testEnvironment": "./src/testing/failFast.js",
"transform": {}
},
"//": [
"See https://github.com/facebook/jest/issues/9430 for information on Jest+ES6."
]
}
export class MonoidalAnnotation {
constructor(identity, convert, combine, compare) {
this.identity = identity;
this.convert = convert;
this.combine = combine;
this.compare = compare;
}
}
class Node {
constructor(tree, parent) {
this.tree = tree;
this.parent = parent;
}
}
class Branch extends Node {
constructor(tree, parent, children) {
super(tree, parent);
this.children = children;
if (parent === undefined) {
this.tree.root = this;
} else {
for (const [index, candidate] of parent.children.entries()) {
if (children.includes(candidate)) {
parent.children[index] = this;
}
}
}
for (const child of children) {
child.parent = this;
}
this.update();
}
updateWithoutRecursion() {
console.assert(this.children.length === 2);
const [left, right] = this.children;
this.height = Math.max(left.height, right.height) + 1;
this.summary = this.tree.annotation.combine(left.summary, right.summary);
}
replaceWith(child) {
console.assert(this.children.includes(child));
if (this.parent === undefined) {
this.tree.root = child;
child.parent = undefined;
} else {
this.parent.children[this.parent.children.indexOf(this)] = child;
child.parent = this.parent;
}
}
rotateLeft() {
console.assert(this.children.length === 2);
const child = this.children[1];
console.assert(child.children.length === 2);
const grandchild = child.children[0];
this.replaceWith(child);
child.children[0] = this;
this.parent = child;
this.children[1] = grandchild;
grandchild.parent = this;
this.updateWithoutRecursion();
}
rotateRight() {
console.assert(this.children.length === 2);
const child = this.children[0];
console.assert(child.children.length === 2);
const grandchild = child.children[1];
this.replaceWith(child);
child.children[1] = this;
this.parent = child;
this.children[0] = grandchild;
grandchild.parent = this;
this.updateWithoutRecursion();
}
update() {
if (this.children.length === 1) {
this.replaceWith(this.children[0]);
} else {
console.assert(this.children.length === 2);
const [left, right] = this.children;
if (left.height < right.height - 1) {
console.assert(right.children.length === 2);
if (right.children[1].height < right.height - 1) {
right.rotateRight();
}
this.rotateLeft();
} else if (right.height < left.height - 1) {
console.assert(left.children.length === 2);
if (left.children[0].height < left.height - 1) {
left.rotateLeft();
}
this.rotateRight();
} else {
this.updateWithoutRecursion();
}
}
if (this.parent !== undefined) {
this.parent.update();
}
}
get leftmost() {
console.assert(this.children.length === 2);
return this.children[0].leftmost;
}
get rightmost() {
console.assert(this.children.length === 2);
return this.children[0].rightmost;
}
find(position, accumulation) {
console.assert(this.children.length === 2);
const candidateAccumulation = this.tree.annotation.combine(accumulation, this.children[0].summary);
if (this.tree.annotation.compare(position, candidateAccumulation) < 0) {
return this.children[0].find(position, accumulation);
}
return this.children[1].find(position, candidateAccumulation);
}
toString() {
const children = this.children.map((child) => `${child},`.replaceAll(/^/gum, ' ')).join('\n');
return `${this.summary} {\n${children}\n}`;
}
}
class Leaf extends Node {
constructor(tree, element) {
super(tree, undefined);
this.element = element;
this.summary = tree.annotation.convert(element);
}
get successor() {
let [child, current] = [this, this.parent];
while (current !== undefined) {
console.assert(current.children.length === 2);
if (current.children[0] === child) {
current = current.children[1];
while (current instanceof Branch) {
current = current.children[0];
}
return current;
}
[child, current] = [current, current.parent];
}
return undefined;
}
get height() {
return 0;
}
get leftmost() {
return this;
}
get rightmost() {
return this;
}
find(position, accumulation) {
return [this, accumulation];
}
get(position, accumulation) {
if (this.tree.annotation.compare(position, accumulation) !== 0) {
return undefined;
}
return this.element;
}
add(position, element, accumulation) {
const sibling = new Leaf(this.tree, element);
// eslint-disable-next-line no-new -- false positive; the branch is actually linked to other objects
new Branch(
this.tree,
this.parent,
this.tree.annotation.compare(position, this.tree.annotation.combine(accumulation, this.summary)) < 0 ?
[sibling, this] :
[this, sibling],
);
return sibling;
}
delete(position, accumulation) {
if (this.tree.annotation.compare(position, accumulation) !== 0) {
return undefined;
}
if (this.parent === undefined) {
this.tree.root = undefined;
} else {
this.parent.children.splice(this.parent.children.indexOf(this), 1);
this.parent.update();
}
return this.element;
}
toString() {
return `${this.summary} from "${this.element}"`;
}
}
export class OrderedLeafyTree {
constructor(annotation) {
this.annotation = annotation;
this.root = undefined;
}
find(position) {
if (this.root === undefined) {
return [undefined, this.annotation.identity];
}
return this.root.find(position, this.annotation.identity);
}
get(position) {
const [leaf, accumulation] = this.find(position);
return leaf?.get(position, accumulation);
}
match(position, isTooFar) {
const [leaf, preaccumulation] = this.find(position);
if (leaf === undefined || this.annotation.compare(position, preaccumulation) !== 0) {
return undefined;
}
let current = leaf;
let accumulation = this.annotation.identity;
// Implement the rest of this method per the assignment instructions. You
// can do everything with loops; no recursion is required.
return this.annotation.combine(this.annotation.combine(preaccumulation, leaf.summary), accumulation);
}
*[Symbol.iterator]() {
let current = this.root?.leftmost;
while (current !== undefined) {
yield current.element;
current = current.successor;
}
}
*subrange(begin, end) {
let [current, accumulation] = this.find(begin);
if (this.annotation.compare(accumulation, begin) < 0) {
return;
}
while (current !== undefined) {
accumulation = this.annotation.combine(accumulation, current.summary);
if (this.annotation.compare(accumulation, end) > 0) {
return;
}
yield current.element;
current = current.successor;
}
}
add(position, element) {
if (this.root === undefined) {
this.root = new Leaf(this, element);
return this.root;
}
const [leaf, accumulation] = this.find(position);
console.assert(leaf !== undefined);
return leaf.add(position, element, accumulation);
}
delete(position) {
if (this.root === undefined) {
return undefined;
}
const [leaf, accumulation] = this.find(position);
console.assert(leaf !== undefined);
return leaf.delete(position, accumulation);
}
toString() {
return this.root === undefined ? '[empty tree]' : `${this.root}`;
}
}
import { MonoidalAnnotation, OrderedLeafyTree } from './orderedLeafyTree.js';
class MonoidElement {
constructor(count, minimumNestingLevel, finalNestingLevel) {
this.count = count;
this.minimumNestingLevel = minimumNestingLevel;
this.finalNestingLevel = finalNestingLevel;
}
toString() {
return `(${this.count}, ${this.minimumNestingLevel}, ${this.finalNestingLevel})`;
}
}
const IDENTITY_ELEMENT = new MonoidElement(0, 0, 0);
const OPEN_PARENTHESIS = new MonoidElement(1, 0, 1);
const CLOSE_PARENTHESIS = new MonoidElement(1, -1, -1);
const OTHER_CHARACTER = new MonoidElement(1, 0, 0);
function encodeAsMonoidElement(character) {
switch (character) {
case '(':
return OPEN_PARENTHESIS;
case ')':
return CLOSE_PARENTHESIS;
default:
return OTHER_CHARACTER;
}
}
function combineMonoidElements(left, right) {
return new MonoidElement(
left.count + right.count,
Math.min(left.minimumNestingLevel, left.finalNestingLevel + right.minimumNestingLevel),
left.finalNestingLevel + right.finalNestingLevel,
);
}
function compareMonoidElements(left, right) {
const leftValue = left instanceof MonoidElement ? left.count : left;
const rightValue = right instanceof MonoidElement ? right.count : right;
return leftValue - rightValue;
}
const PARENTHESIS_MATCHING_ROPE_ANNOTATION = new MonoidalAnnotation(
IDENTITY_ELEMENT,
encodeAsMonoidElement,
combineMonoidElements,
compareMonoidElements,
);
export class ParenthesisMatchingRope {
constructor(string) {
this.tree = new OrderedLeafyTree(PARENTHESIS_MATCHING_ROPE_ANNOTATION);
this.splice(0, 0, string);
}
get(index) {
const result = this.tree.get(index);
return result !== undefined ? result : '';
}
match(index) {
console.assert(this.get(index) === '(');
const monoidElement = this.tree.match(index, (candidate) => candidate.minimumNestingLevel < 0);
return monoidElement !== undefined ? monoidElement.count : undefined;
}
slice(begin, end) {
let result = '';
for (const character of this.tree.subrange(begin, end)) {
result += character;
}
return result;
}
splice(begin, deleteCount, newText) {
let result = '';
for (let i = 0; i < deleteCount; ++i) {
const deletion = this.tree.delete(begin);
if (deletion === undefined) {
break;
}
result += deletion;
}
for (let i = 0; i < newText.length; ++i) {
this.tree.add(begin + i, newText[i]);
}
return result;
}
toString() {
let result = '';
for (const character of this.tree) {
result += character;
}
return result;
}
}
This diff is collapsed.
import jestEnvironmentNode from 'jest-environment-node';
export default class FailFastEnvironment extends jestEnvironmentNode.default {
constructor(...rest) {
super(...rest);
this.failed = false;
}
async handleTestEvent(event, state) {
switch (event.name) {
case 'hook_failure':
case 'test_fn_failure':
this.failed = true;
break;
case 'test_start':
if (this.failed) {
event.test.mode = 'skip';
}
break;
default:
}
if (super.handleTestEvent !== undefined) {
await super.handleTestEvent(event, state);
}
}
}
This diff is collapsed.
{
"name": "@unlcsce/homework-5",
"version": "1.0.0",
"description": "Starter code for Homework 5.",
"private": true,
"license": "UNLICENSED",
"scripts": {
"postinstall:eslint-config": "cd eslint-config && npm install",
"postinstall:app": "cd homework-5 && npm install",
"postinstall": "run-s postinstall:**",
"lint:app": "cd homework-5 && npm run lint",
"lint": "run-s --continue-on-error lint:**",
"test-once:ascent": "cd homework-5 && npm run test-once:ascent",
"test-once:matching": "cd homework-5 && npm run test-once:matching",
"test-once": "cd homework-5 && npm run test-once",
"test": "run-s test-once"
},
"devDependencies": {
"ghooks": "^2.0.4",
"npm-run-all": "^4.1.5"
},
"config": {
"ghooks": {
"pre-commit": "npm run lint"
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment