Created
December 23, 2024 19:24
-
-
Save jacoobes/dfd524dff2ab314a6b44e9384072bf50 to your computer and use it in GitHub Desktop.
Incomplete but browser compatible edn parsr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class EDNParser { | |
constructor(ednString) { | |
this.edn = ednString; | |
this.index = 0; | |
} | |
parse() { | |
this.skipWhitespace(); | |
const element = this.readElement(); | |
this.skipWhitespace(); | |
if (this.index < this.edn.length) { | |
throw new Error("Unexpected data after valid EDN element."); | |
} | |
return element; | |
} | |
readElement() { | |
this.skipWhitespace(); | |
const char = this.peek(); | |
if (char === undefined) return null; | |
switch (char) { | |
case '"': return this.readString(); | |
case '{': return this.readMap(); | |
case '[': return this.readVector(); | |
case '(': return this.readList(); | |
case '#': return this.readTaggedOrSet(); | |
case ':': return this.readKeyword(); | |
case ';': this.skipComment(); return this.readElement(); | |
default: | |
if (/\d|-|\+/.test(char)) return this.readNumber(); | |
if (/\\/.test(char)) return this.readCharacter(); | |
return this.readSymbol(); | |
} | |
} | |
readString() { | |
this.expect('"'); | |
let str = ""; | |
while (this.peek() !== '"') { | |
if (this.peek() === "\\") { | |
this.index++; | |
const escapeChar = this.edn[this.index]; | |
const escapeMap = { t: "\t", r: "\r", n: "\n", '\\': "\\", '"': '"' }; | |
str += escapeMap[escapeChar] || escapeChar; | |
} else { | |
str += this.edn[this.index]; | |
} | |
this.index++; | |
} | |
this.expect('"'); | |
return str; | |
} | |
readCharacter() { | |
this.expect("\\"); | |
const char = this.edn.slice(this.index).match(/^[^\s]+/); | |
if (!char) throw new Error("Invalid character."); | |
this.index += char[0].length; | |
const charMap = { newline: "\n", return: "\r", space: " ", tab: "\t" }; | |
return charMap[char[0]] || char[0]; | |
} | |
readSymbol() { | |
const match = this.edn.slice(this.index).match(/^[^\s\(\)\[\]\{\}"#:;]+/); | |
if (!match) throw new Error("Invalid symbol."); | |
this.index += match[0].length; | |
return match[0]; | |
} | |
readKeyword() { | |
this.expect(":"); | |
const match = this.edn.slice(this.index).match(/^[^\s\(\)\[\]\{\}"#:;]+/); | |
if (!match) throw new Error("Invalid keyword."); | |
this.index += match[0].length; | |
return `:${match[0]}`; | |
} | |
readNumber() { | |
const match = this.edn.slice(this.index).match(/^-?\d+(\.\d+)?([eE][+-]?\d+)?[M]?/); | |
if (!match) throw new Error("Invalid number."); | |
this.index += match[0].length; | |
return parseFloat(match[0]); | |
} | |
readList() { | |
this.expect("("); | |
const list = []; | |
while (this.peek() !== ")") { | |
list.push(this.readElement()); | |
} | |
this.expect(")"); | |
return list; | |
} | |
readVector() { | |
this.expect("["); | |
const vector = []; | |
while (this.peek() !== "]") { | |
vector.push(this.readElement()); | |
} | |
this.expect("]"); | |
return vector; | |
} | |
readMap() { | |
this.expect("{"); | |
const map = {}; | |
while (this.peek() !== "}") { | |
const key = this.readElement(); | |
const value = this.readElement(); | |
map[key] = value; | |
} | |
this.expect("}"); | |
return map; | |
} | |
readTaggedOrSet() { | |
this.expect("#"); | |
if (this.peek() === "{") return this.readSet(); | |
const tag = this.readSymbol(); | |
const element = this.readElement(); | |
return { tag, element }; | |
} | |
readSet() { | |
this.expect("{"); | |
const set = new Set(); | |
while (this.peek() !== "}") { | |
set.add(this.readElement()); | |
} | |
this.expect("}"); | |
return set; | |
} | |
skipComment() { | |
while (this.peek() && this.peek() !== "\n") { | |
this.index++; | |
} | |
this.index++; // Skip the newline | |
} | |
skipWhitespace() { | |
while (/\s|,/.test(this.peek())) this.index++; | |
} | |
peek() { | |
return this.edn[this.index]; | |
} | |
expect(char) { | |
if (this.edn[this.index] !== char) { | |
throw new Error(`Expected '${char}' but found '${this.edn[this.index]}'.`); | |
} | |
this.index++; | |
} | |
} | |
// Example usage: | |
const ednStr = `{:name "John", :age 0, :hobbies ["reading" "cycling"]}`; | |
const parser = new EDNParser(ednStr); | |
console.log(parser.parse()); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
output =