Skip to content

Commit

Permalink
Merge d7cd43e into bf51d5b
Browse files Browse the repository at this point in the history
  • Loading branch information
mbovel committed Jul 25, 2019
2 parents bf51d5b + d7cd43e commit dd5c996
Show file tree
Hide file tree
Showing 20 changed files with 423 additions and 442 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Hashmark parser
[![npm version](https://badge.fury.io/js/%40hashmark%2Fparser.svg)](https://www.npmjs.com/package/@hashmark/parser)
[![Build Status](https://travis-ci.org/hashmark-lang/hashmark-parser.svg?branch=master)](https://travis-ci.org/hashmark-lang/hashmark-parser)
[![Coverage Status](https://coveralls.io/repos/github/hashmark-lang/hashmark-parser/badge.svg?branch=master)](https://coveralls.io/github/hashmark-lang/hashmark-parser?branch=master)
[![Build Status](https://travis-ci.org/hashml/hashml.svg?branch=master)](https://travis-ci.org/hashml/hashml)
[![Coverage Status](https://coveralls.io/repos/github/hashml/hashml/badge.svg?branch=master)](https://coveralls.io/github/hashml/hashml?branch=master)

## Installation
```
Expand Down
94 changes: 54 additions & 40 deletions benchmark/parseBenchmark.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,59 @@
/* tslint:disable:no-console */
import { Event, Suite } from "benchmark";
import * as Benchmark from "benchmark";
import { BlockElement, BlockParser } from "../src";
import { AstHandler } from "../src/ast/AstHandler";
import { toJSON } from "../src/output/json";
import { parse } from "../src/parser/Parser";

(function run() {
const input = generateBenchmarkInput();
console.log("Size of test input: " + formatBytes(input.length));
const jsonAst = JSON.stringify(toJSON(parse(input)));
new Benchmark.Suite("compare")
.add("Parse Hashmark", () => {
parse(input);
})
.add("Parse JSON", () => {
JSON.parse(jsonAst);
})
.add("String.matchAll", () => {
for (const token of input.matchAll(
/(?:((?:\r\n|\n|\r|^)(\t*)[\t ]*(?:#([^ \[\r\n]+)(?: |$))?)|(#([^ \[]+)(\[)?)|(]\[)|(\[)|(\\(.)))/g
));
})
.add("Iterate through chars", () => {
const SHARP = "#";
const OPENING_BRACKET = "[";
const end = input.length;
for (let i = 0; i < end; ++i) {
switch (input.charAt(i)) {
case SHARP:
break;
case OPENING_BRACKET:
break;
}
}
})
// add listeners
.on("cycle", (event: Event) => {
console.log(String(event.target));
})
.on("complete", function(this: Benchmark[]) {
console.log(
"JSON/Hashmark ratio: " + (this[1].stats.mean / this[0].stats.mean).toFixed(2)
);
})
// run async
.run({ async: true });
})();

const handler = new AstHandler();
const parser = new BlockParser(handler);

function parse(input: string): BlockElement {
handler.reset();
parser.parse(input);
return handler.getResult();
}

const N_CHILDREN = 10;
const MAX_DEPTH = 3;
Expand Down Expand Up @@ -29,41 +81,3 @@ function formatBytes(bytes: number, decimals = 2) {

return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
}

const input = generateBenchmarkInput();
console.log("Size of test input: " + formatBytes(input.length));
const jsonAst = JSON.stringify(toJSON(parse(input)));
new Suite("compare")
.add("Parse Hashmark", () => {
parse(input);
})
.add("Parse JSON", () => {
JSON.parse(jsonAst);
})
.add("String.matchAll", () => {
for (const token of input.matchAll(
/(?:((?:\r\n|\n|\r|^)(\t*)[\t ]*(?:#([^ \[\r\n]+)(?: |$))?)|(#([^ \[]+)(\[)?)|(]\[)|(\[)|(\\(.)))/g
));
})
.add("Iterate through chars", () => {
const SHARP = "#";
const OPENING_BRACKET = "[";
const end = input.length;
for (let i = 0; i < end; ++i) {
switch (input.charAt(i)) {
case SHARP:
break;
case OPENING_BRACKET:
break;
}
}
})
// add listeners
.on("cycle", (event: Event) => {
console.log(String(event.target));
})
.on("complete", function() {
console.log("JSON/Hashmark ratio: " + (this[1].stats.mean / this[0].stats.mean).toFixed(2));
})
// run async
.run({ async: true });
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
],
"repository": {
"type": "git",
"url": "https://github.com/hashmark-lang/hashmark-parser.git"
"url": "https://github.com/hashml/hashml.git"
},
"publishConfig": {
"access": "public"
Expand Down
110 changes: 60 additions & 50 deletions src/ast/AstHandler.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,85 @@
import { BlockHandler } from "../parser/BlockHandler";
import { InlineHandler, Sugar } from "../parser/InlineHandler";
import { InlineHandler, Sugar, SugarsByStart } from "../parser/InlineHandler";
import { InlineParser } from "../parser/InlineParser";
import { InputPosition } from "../parser/InputPosition";
import { last } from "../utils";
import { BlockElement, InlineElement, InlineGroup } from "./ast";

export class AstHandler
implements BlockHandler<BlockElement>, InlineHandler<InlineGroup, InlineElement> {
protected readonly inlineParser = new InlineParser<InlineGroup, InlineElement>(this);
export class AstHandler implements BlockHandler, InlineHandler {
protected readonly inlineParser = new InlineParser(this);
protected readonly blockStack: BlockElement[] = [];
protected readonly inlineGroupStack: InlineGroup[] = [];
protected readonly inlineElementStack: InlineElement[] = [];

rootBlock() {
const data = { tag: "root", children: [], head: [], line: 1, tagStart: 1, tagEnd: 1 };
return { data, rawBody: false };
constructor() {
this.reset();
}

openBlock(
parent: BlockElement,
tag: string | undefined,
headContent: string,
line: number,
tagStart: number,
tagEnd: number,
headStart: number
) {
const head = this.parseHead(tag, headContent, line, headStart);
const data = { tag, head, children: [], line, tagStart, tagEnd };
parent.children.push(data);
return { data, rawBody: false };
reset(): void {
this.blockStack.length = 0;
this.blockStack.push({
tag: "root",
pos: { line: 1, column: 1, length: 0 },
head: [],
children: []
});
}

getResult(): BlockElement {
return this.blockStack[0];
}

protected parseHead(
parentTag: string | undefined,
content: string,
line: number,
column: number
) {
return this.inlineParser.parse(content, line, column, undefined);
openBlock(tag: string | undefined, pos: InputPosition): boolean {
const node = { tag, pos: { ...pos }, head: [], children: [] };
last(this.blockStack).children.push(node);
this.blockStack.push(node);
this.inlineGroupStack.length = 0;
this.inlineElementStack.length = 0;
this.inlineGroupStack.push(node.head);
return true;
}

rawLine(parent: BlockElement, content: string): void {
parent.children.push({
closeBlock(): void {
this.blockStack.pop();
}

head(content: string, pos: InputPosition): void {
this.inlineParser.parse(content, new Map(), pos);
}

rawLine(content: string, pos: InputPosition): void {
last(this.blockStack).children.push({
tag: "_raw_line",
pos: { ...pos },
head: [content],
children: [],
line: -1,
tagStart: -1,
tagEnd: -1
children: []
});
}

rootInlineTag() {
return { data: [], sugars: new Map(), raw: false };
openInlineTag(tag: string, pos: InputPosition): InlineElement {
const element = { tag, pos: { ...pos }, args: [] };
this.inlineElementStack.push(element);
last(this.inlineGroupStack).push(element);
return element;
}

openInlineTag(
parent: Array<string | InlineElement>,
tag: string,
line: number,
tagStart: number,
tagEnd: number
): InlineElement {
const element = { tag, args: [], line, tagStart, tagEnd };
parent.push(element);
return element;
closeInlineTag(): void {
this.inlineElementStack.pop();
}

openArgument(index: number, pos: InputPosition): false | SugarsByStart {
const arg: InlineGroup = [];
this.inlineGroupStack.push(arg);
last(this.inlineElementStack).args.push(arg);
return new Map();
}

openArgument(parent: InlineElement, index: number, line: number, start: number) {
const data: InlineGroup = [];
parent.args.push(data);
return { data, sugars: new Map(), raw: false };
closeArgument(): void {
this.inlineGroupStack.pop();
}

pushText(parent: InlineGroup, content: string) {
pushText(content: string): void {
const parent = last(this.inlineGroupStack);
const lastIndex = parent.length - 1;
if (lastIndex < 0 || typeof parent[lastIndex] !== "string") {
parent.push(content);
Expand Down
10 changes: 4 additions & 6 deletions src/ast/ast.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { InputPosition } from "../parser/InputPosition";

export type InlineGroup = Array<string | InlineElement>;

export interface BlockElement {
tag?: string;
head: InlineGroup;
children: BlockElement[];
line: number;
tagStart: number;
tagEnd: number;
pos: InputPosition;
}

export interface InlineElement {
tag: string;
args: InlineGroup[];
line: number;
tagStart: number;
tagEnd: number;
pos: InputPosition;
}

0 comments on commit dd5c996

Please sign in to comment.