Skip to content

Instantly share code, notes, and snippets.

@marijnh
Created November 11, 2010 16:19
Show Gist options
  • Save marijnh/672710 to your computer and use it in GitHub Desktop.
Save marijnh/672710 to your computer and use it in GitHub Desktop.
Elementary CodeMirror Lisp parser (specialized for AllegroGraph Prolog queries)
// Parses a small subset of Common Lisp as used in AGraph Prolog queries.
LispParser = Editor.Parser = (function() {
function wordRegexp(words) {
return new RegExp("^(?:" + words.join("|") + ")$", "i");
}
var specialForms = wordRegexp(["select", "select-distinct", "select0-distinct", "select0", "<-", "<--"]);
var symbolChars = /[^\s\u00a0\(\)#!<]/;
var tokenizeLisp = (function() {
function normal(source, setState) {
var ch = source.next();
if (/[\(\)!\^]/.test(ch)) {
return "punctuation";
}
else if (ch == "/" && source.equals("/")) {
while (!source.endOfLine()) source.next();
return "comment";
}
else if (ch == "!" && source.equals("<")) {
source.nextWhile(matcher(/[^\s\u00a0>]/));
if (source.equals(">")) source.next();
return "uri";
}
else if (ch == "\"") {
setState(inString);
return null;
}
else {
source.nextWhile(matcher(symbolChars));
if (ch == "?") return "var";
var word = source.get();
if (specialForms.test(word))
return {style: "special", content: word};
else
return {style: "symbol", content: word};
}
}
function inString(source, setState) {
var escaped = false;
while (!source.endOfLine()) {
var ch = source.next();
if (ch == "\"" && !escaped) {
setState(normal);
break;
}
escaped = ch == "\\";
}
return "string";
};
return function(source, startState) {
return tokenizer(source, startState || normal);
};
})();
function indentLisp(context) {
return function() {return context.indent;};
}
function parseLisp(source) {
var tokens = tokenizeLisp(source);
var context = {indent: 0, prev: null, typed: null}, col = 0;
function pushContext() {
context = {prev: context, indent: col, typed: false};
}
function popContext() {
if (context.prev) context = context.prev;
}
var iter = {
next: function() {
var token = tokens.next(), type = token.style, content = token.content;
if (content == "\n") {
token.indentation = indentLisp(context);
col = 0;
}
else {
col += token.value.length;
}
if (content == "(")
pushContext();
else if (content == ")")
popContext();
else if (context.typed == false) {
if (type == "special") {
context.typed = true;
context.indent = context.indent + 1;
}
else if (type != "newline" && type != "comment" && type != "whitespace") {
context.typed = true;
context.indent = col;
}
}
return token;
},
copy: function() {
var _context = context, _col = col, _tokenState = tokens.state;
return function(source) {
tokens = tokenizeLisp(source, _tokenState);
context = _context;
col = _col;
return iter;
};
}
};
return iter;
}
return {make: parseLisp};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment