Skip to content
This repository has been archived by the owner on Feb 26, 2021. It is now read-only.

Commit

Permalink
Optimize SExpression Parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
NightRa committed Sep 13, 2016
1 parent ced1baa commit 6751eda
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 63 deletions.
77 changes: 46 additions & 31 deletions lib/parser/agda.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
"dependencies": {
"bluebird": "^3.4.1",
"classnames": "^2.2.5",
"lisp-to-array": "^0.2",
"lodash": "^4.13.1",
"parsimmon": "^0.9.0",
"react": "^15.3.1",
Expand Down
76 changes: 45 additions & 31 deletions src/parser/agda.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as _ from "lodash";
import { Agda } from "../types";
var lispToArray = require("lisp-to-array");

function parseAgdaResponse(raw: string): Agda.Response {

Expand Down Expand Up @@ -145,55 +144,70 @@ function parseInfoActionType(s: String): string {
////////////////////////////////////////////////////////////////////////////////
// Parsing S-Expressions
////////////////////////////////////////////////////////////////////////////////
function parse_sexp(string: string): any {
var sexp = [[]];
var word = '';
var in_str = false;

function pushLastWord(word) {
var n = parseInt(word);
if (isNaN(n)) {
pushInLast(word);
} else {
pushInLast(n);
}
}

function pushInLast(elem) {
sexp[sexp.length - 1].push(elem);
}

for (var i = 0; i < string.length; i++) {
var char = string[i];
if (char == '\'' && !in_str) {
} else if (char == '(' && !in_str) {
sexp.push([]);
} else if (char == ')' && !in_str) {
if (word != '') {
pushLastWord(word);
word = '';
}
pushInLast(sexp.pop());
} else if (char == ' ' && !in_str) {
if (word != '') {
pushLastWord(word);
word = '';
}
} else if (char == '\"') {
in_str = !in_str;
} else {
word += char;
}
}
return sexp[0];
}

function parseSExpression(s: string): any {
return postprocess(lispToArray(preprocess(s)));
return parse_sexp(preprocess(s))[0];
}

function preprocess(chunk: string): string {
// polyfill String::startsWith
if (chunk.substr(0, 6) === "((last") {
// drop wierd prefix like ((last . 1))
let index = chunk.indexOf("(agda");
let length = chunk.length
let length = chunk.length;
chunk = chunk.substring(index, length - 1);
}
if (chunk.substr(0, 13) === "cannot read: ") {
// handles Agda parse error
chunk = chunk.substring(12);
chunk = `(agda2-parse-error${chunk})`;
}
// make it friendly to 'lisp-to-array' package
chunk = chunk.replace(/'\(/g, '(__number__ ');
chunk = chunk.replace(/\("/g, '(__string__ "');
chunk = chunk.replace(/\(\)/g, '(__nil__)');

return chunk;
}

// recursive cosmetic surgery
function postprocess(node: string | string[]): any {
if (node instanceof Array) {
switch (node[0]) {
case "`": // ["`", "some string"] => "some string"
return postprocess(node[1]);
case "__number__": // ["__number__", 1, 2, 3] => [1, 2, 3]
case "__string__": // ["__string__", 1, 2, 3] => [1, 2, 3]
case "__nil__": // ["__nil__"] => []
node.shift();
return postprocess(node);
default: // keep traversing
return node.map(function(x) { return postprocess(x); });
}
} else {
if (typeof node === "string") {
// some ()s in strings were replaced with (__nil__) when preprocessing
return node.replace("(__nil__)", "()");
} else {
return node;
}
}
}

export {
parseAgdaResponse
}

0 comments on commit 6751eda

Please sign in to comment.