Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
EthanThatOneKid committed Nov 27, 2021
1 parent 8f21d7e commit d9d9c1f
Show file tree
Hide file tree
Showing 15 changed files with 309 additions and 27 deletions.
9 changes: 9 additions & 0 deletions lib/cartridge/cartridge.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
import { assertEquals } from "../../deps/std/testing.ts";
import { Cartridge } from "./cartridge.ts";
import { CartridgeEvent } from "./cartridge_event.ts";

/**
* @todo @ethanthatonekid write tests that reflect cartridge api design/usage
*/
Deno.test("hello world", () => {
const cartridge = new Cartridge();
cartridge.on(CartridgeEvent.FileStart, console.log);
assertEquals(1, 1);
});
58 changes: 58 additions & 0 deletions lib/cartridge/cartridge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,64 @@
import { CartridgeEvent } from "./cartridge_event.ts";
import type {
CartridgeEventContext,
CartridgeHandler,
CartridgeHandlerMap,
} from "./cartridge_event.ts";

/**
* @todo @ethanthatonekid pass all tests in ./cartridge.test.ts
* @todo @ethanthatonekid refactor <https://github.com/EthanThatOneKid/fart/blob/c43f2333458b2cbc40d167610d87e2a2e3f89885/lib/gen/cart.ts>
*/
export class Cartridge {
constructor(
private handlers: CartridgeHandlerMap = {},
) {}

addEventListener(
name: CartridgeEvent.FileStart,
handler: CartridgeHandler<CartridgeEvent.FileStart>,
): void;
addEventListener(
name: CartridgeEvent.InlineComment,
handler: CartridgeHandler<CartridgeEvent.InlineComment>,
): void;
addEventListener(
name: CartridgeEvent.MultilineComment,
handler: CartridgeHandler<CartridgeEvent.MultilineComment>,
): void;
addEventListener(
name: CartridgeEvent.Load,
handler: CartridgeHandler<CartridgeEvent.Load>,
): void;
addEventListener(
name: CartridgeEvent.StructOpen,
handler: CartridgeHandler<CartridgeEvent.StructOpen>,
): void;
addEventListener(
name: CartridgeEvent.SetProperty,
handler: CartridgeHandler<CartridgeEvent.StructClose>,
): void;
addEventListener(
name: CartridgeEvent.FileEnd,
handler: CartridgeHandler<CartridgeEvent.FileEnd>,
): void;
addEventListener(
name: CartridgeEvent,
// deno-lint-ignore no-explicit-any
handler: any,
) {
this.handlers[name] = handler;
}

/**
* `on` is an alias for `addEventListener`
*/
on = this.addEventListener.bind(this);

removeEventListener(name: CartridgeEvent) {
delete this.handlers[name];
}

// TODO(@ethanthatonekid): add a `dispatch` method
// @see <https://github.com/EthanThatOneKid/fart/blob/c43f233345/lib/gen/cart.ts#L120>
}
50 changes: 50 additions & 0 deletions lib/cartridge/cartridge_event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { Token } from "../tokenize/mod.ts";

export enum CartridgeEvent {
FileStart = "file_start",
InlineComment = "inline_comment",
MultilineComment = "multiline_comment",
Load = "load",
StructOpen = "struct_open",
SetProperty = "set_property",
StructClose = "struct_close",
FileEnd = "file_end",
}

export interface CartridgeEventContext<T extends CartridgeEvent> {
type: T;
code: { append: (code: string) => void };
tokens: Token[];
data: T extends CartridgeEvent.InlineComment ? { comments: string[] }
: T extends CartridgeEvent.MultilineComment ? { comments: string[] }
: T extends CartridgeEvent.Load ? { comments: string[] }
: T extends CartridgeEvent.StructOpen
? { comments: string[]; name?: string } // undefined name implies anonymous struct
: T extends CartridgeEvent.SetProperty
? { comments: string[]; name: string; value: string }
: null;
}

/**
* If a code generation function returns null, that means that the
* target language omits the requested generated code. A null return
* value will prevent the requested line from being appended to the result.
*/
export type CartridgeHandler<T extends CartridgeEvent> = (
event: CartridgeEventContext<T>,
) => void | Promise<void>;

export interface CartridgeHandlerMap {
[CartridgeEvent.FileStart]?: CartridgeHandler<CartridgeEvent.FileStart>;
[CartridgeEvent.InlineComment]?: CartridgeHandler<
CartridgeEvent.InlineComment
>;
[CartridgeEvent.MultilineComment]?: CartridgeHandler<
CartridgeEvent.MultilineComment
>;
[CartridgeEvent.Load]?: CartridgeHandler<CartridgeEvent.Load>;
[CartridgeEvent.StructOpen]?: CartridgeHandler<CartridgeEvent.StructOpen>;
[CartridgeEvent.SetProperty]?: CartridgeHandler<CartridgeEvent.SetProperty>;
[CartridgeEvent.StructClose]?: CartridgeHandler<CartridgeEvent.StructClose>;
[CartridgeEvent.FileEnd]?: CartridgeHandler<CartridgeEvent.FileEnd>;
}
6 changes: 6 additions & 0 deletions lib/cartridge/mod.ts
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
export { Cartridge } from "./cartridge.ts";
export { CartridgeEvent } from "./cartridge_event.ts";
export type {
CartridgeEventContext,
CartridgeHandler,
CartridgeHandlerMap,
} from "./cartridge_event.ts";
9 changes: 0 additions & 9 deletions lib/indent/indent.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
import { assertEquals } from "../../deps/std/testing.ts";
import { INDENT, Indent } from "./indent.ts";

// TODO(@ethanthatonekid): generate tests for the length of each indentation level

// let result = "";
// for (let i = 1; i <= 16; i++) {
// result += `Deno.test("cache of Indent.Tab${i} equals ${i} tab", () => {
// assertEquals(INDENT[Indent.Tab${i}], "\t".repeat(${i}));
// });`;
// }

Deno.test("cache of Indent.Tab1 equals 1 tab", () => {
assertEquals(INDENT[Indent.Tab1], "\t".repeat(1));
});
Expand Down
3 changes: 3 additions & 0 deletions lib/indent/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { INDENT, Indent } from "./indent.ts";
export type { IndentCacheIndex, IndentOption } from "./indent.ts";
export { getCachedIndent, getIndent, getIndentOption } from "./utils.ts";
27 changes: 14 additions & 13 deletions lib/indent/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import {
import { INDENT, Indent } from "./indent.ts";
import { getCachedIndent } from "./utils.ts";

const C = 0x10; // 16, cache size
const CACHE_BENCH_ID = "CACHE_TEST";
const COMPUTED_BENCH_ID = "COMPUTED_TEST";
const BENCH_RUNS = 1000; // the higher the number, the more accurate the benchmark results
const BENCH_RUNS = 1e3; // the higher the number, the more accurate the benchmark results

/**
* @see https://deno.land/[email protected]/testing#benching
Expand All @@ -21,12 +22,12 @@ bench({
func: (timer: BenchmarkTimer): void => {
const store: string[] = [];
timer.start();
for (let i = 1; i <= 16; i++) store.push(getCachedIndent(Indent.Tab1, i));
for (let i = 1; i <= 16; i++) store.push(getCachedIndent(Indent.Tab2, i));
for (let i = 1; i <= 16; i++) store.push(getCachedIndent(Indent.Space1, i));
for (let i = 1; i <= 16; i++) store.push(getCachedIndent(Indent.Space2, i));
for (let i = 1; i <= 16; i++) store.push(getCachedIndent(Indent.Space3, i));
for (let i = 1; i <= 16; i++) store.push(getCachedIndent(Indent.Space4, i));
for (let i = 1; i <= C; i++) store.push(getCachedIndent(Indent.Tab1, i));
for (let i = 1; i <= C; i++) store.push(getCachedIndent(Indent.Tab2, i));
for (let i = 1; i <= C; i++) store.push(getCachedIndent(Indent.Space1, i));
for (let i = 1; i <= C; i++) store.push(getCachedIndent(Indent.Space2, i));
for (let i = 1; i <= C; i++) store.push(getCachedIndent(Indent.Space3, i));
for (let i = 1; i <= C; i++) store.push(getCachedIndent(Indent.Space4, i));
timer.stop();
},
});
Expand All @@ -37,12 +38,12 @@ bench({
func: (timer: BenchmarkTimer): void => {
const store: string[] = [];
timer.start();
for (let i = 1; i <= 16; i++) store.push(INDENT[Indent.Tab1].repeat(i));
for (let i = 1; i <= 16; i++) store.push(INDENT[Indent.Tab2].repeat(i));
for (let i = 1; i <= 16; i++) store.push(INDENT[Indent.Space1].repeat(i));
for (let i = 1; i <= 16; i++) store.push(INDENT[Indent.Space2].repeat(i));
for (let i = 1; i <= 16; i++) store.push(INDENT[Indent.Space3].repeat(i));
for (let i = 1; i <= 16; i++) store.push(INDENT[Indent.Space4].repeat(i));
for (let i = 1; i <= C; i++) store.push(INDENT[Indent.Tab1].repeat(i));
for (let i = 1; i <= C; i++) store.push(INDENT[Indent.Tab2].repeat(i));
for (let i = 1; i <= C; i++) store.push(INDENT[Indent.Space1].repeat(i));
for (let i = 1; i <= C; i++) store.push(INDENT[Indent.Space2].repeat(i));
for (let i = 1; i <= C; i++) store.push(INDENT[Indent.Space3].repeat(i));
for (let i = 1; i <= C; i++) store.push(INDENT[Indent.Space4].repeat(i));
timer.stop();
},
});
Expand Down
54 changes: 54 additions & 0 deletions lib/text_builder/code_block/code_block.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { assertEquals } from "../../../deps/std/testing.ts";
import { CodeBlock } from "./code_block.ts";

Deno.test("new code block is empty", () => {
assertEquals(new CodeBlock().export(), "");
});

Deno.test("add 3 lines of code to the block", () => {
const block = new CodeBlock();
block.append("a");
block.append("b");
block.append("c");
const expectation = "a\nb\nc";
const reality = block.export();
assertEquals(expectation, reality);
});

Deno.test("add 3 lines of code to the block (indented)", () => {
const block = new CodeBlock();
block.append("a", 0);
block.append("b", 1);
block.append("c", 2);
const expectation = "a\n b\n c";
const reality = block.export();
assertEquals(expectation, reality);
});

Deno.test("join 3 code blocks", () => {
const block1 = new CodeBlock();
block1.append("a", 0);
block1.append("b", 1);
block1.append("c", 2);
const block2 = new CodeBlock();
block2.append("d", 1);
block2.append("e", 0);
block2.append("f", 1);
const block3 = new CodeBlock();
block3.append("g", 2);
block3.append("h", 1);
block3.append("i", 0);
const expectation = `a
b
c
d
e
f
g
h
i`;
const reality = CodeBlock.join(block1, block2, block3);
assertEquals(expectation, reality);
});
54 changes: 54 additions & 0 deletions lib/text_builder/code_block/code_block.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { getIndent, Indent, IndentOption } from "../../indent/mod.ts";

export interface LineOfCode {
content: string;
indentLevel: number;
}

/**
* Represents a block of code.
*/
export class CodeBlock {
public code: LineOfCode[] = [];

append(content: string, indentLevel = 0): void {
this.code.push(
...content.split("\n").map((line) => ({ content: line, indentLevel })),
);
}

export(indent: IndentOption = Indent.Space2): string {
return this.code
.map(({ content, indentLevel }) =>
getIndent(indent, indentLevel) + content
)
.join("\n");
}

/**
* `toString` is an alias for `CodeBlock.export`.
*/
toString = this.export.bind(this);

static join(
indentOrFirstBlock: IndentOption | CodeBlock,
...blocks: CodeBlock[]
): string {
const blockPadding = 2; // lines between each code block
const blockSeparator = "\n".repeat(blockPadding);
const indentSpecified = !(indentOrFirstBlock instanceof CodeBlock);
if (!indentSpecified) blocks = [indentOrFirstBlock, ...blocks];
return blocks
.filter((block) => block !== null)
.reduce(
(file, block, i) => {
const exportedCode = indentSpecified
? block.export(indentOrFirstBlock)
: block.export();
return file + exportedCode +
(blocks.length - 1 > i ? blockSeparator : "");
},
"",
);
}
}
Empty file.
Empty file.
1 change: 0 additions & 1 deletion lib/text_builder/code_block/mod.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export { CodeBlock } from "./code_block.ts";
export { CodeLine } from "./code_line.ts";
3 changes: 2 additions & 1 deletion lib/text_builder/mod.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
// https://github.com/EthanThatOneKid/fart/blob/c43f2333458b2cbc40d167610d87e2a2e3f89885/lib/gen/builder.ts
export { TextBuilder } from "./text_builder.ts";
export { CodeBlock } from "./code_block/mod.ts";
54 changes: 54 additions & 0 deletions lib/text_builder/text_builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { CodeBlock } from "./code_block/mod.ts";
import { Indent, IndentOption } from "../indent/mod.ts";
import { Cartridge, CartridgeEvent } from "../cartridge/mod.ts";
import { Token } from "../tokenize/mod.ts";

export class TextBuilder {
private blocks: CodeBlock[];
private currentBlock: CodeBlock;
private indentLevel: number;

constructor(private cartridge: Cartridge) {
this.blocks = [];
this.currentBlock = new CodeBlock();
this.indentLevel = 0;
}

/**
* @todo @ethanthatonekid complete this method
* @see https://github.com/EthanThatOneKid/fart/blob/c43f233345/lib/gen/builder.ts#L20
*/
// deno-lint-ignore no-unused-vars
append(event: CartridgeEvent, tokens: Token[]): void {
switch (event) {
case CartridgeEvent.FileStart: {
break;
}
case CartridgeEvent.InlineComment: {
break;
}
case CartridgeEvent.MultilineComment: {
break;
}
case CartridgeEvent.Load: {
break;
}
case CartridgeEvent.StructOpen: {
break;
}
case CartridgeEvent.SetProperty: {
break;
}
case CartridgeEvent.StructClose: {
break;
}
case CartridgeEvent.FileEnd: {
break;
}
}
}

export(indent: IndentOption = Indent.Space2): string {
return CodeBlock.join(indent, ...this.blocks);
}
}
Loading

1 comment on commit d9d9c1f

@deno-deploy
Copy link

@deno-deploy deno-deploy bot commented on d9d9c1f Nov 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failed to deploy:

failed to fetch 'https://raw.githubusercontent.com/EthanThatOneKid/fart/d9d9c1f4002c766b5d603fa8a12ce9101306e9bc/std/server/worker.ts': HTTP status client error (404 Not Found) for url (https://raw.githubusercontent.com/EthanThatOneKid/fart/d9d9c1f4002c766b5d603fa8a12ce9101306e9bc/std/server/worker.ts)

Please sign in to comment.