Created
June 30, 2017 12:09
-
-
Save wallabra/b4412db7b99595f9b34286fa16059ed2 to your computer and use it in GitHub Desktop.
Small manual parsing library I'm doing in CoffeeScript for Node.JS (WIP)
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 Parsing | |
constructor: -> | |
parse: (text) -> | |
throw new Error("Use a subclass of ParsingBlock!") | |
class CharacterClass extends Parsing | |
constructor: (@chars, @otherChars, @whitespace) -> | |
parse: (text) => | |
res = "" | |
i = 0 | |
for l in text | |
if not @whitespace and l in [" ", "\t"] | |
return { | |
match: false | |
result: res | |
remaining: chars.slice(res.lengt + 1) | |
} | |
if l not in (@chars if i == 0 else (@otherChars if @otherChars? else @chars)) | |
break | |
res += l | |
i++ | |
if i == 0 | |
return { | |
match: false | |
result: "" | |
remaining: text | |
} | |
return { | |
match: true | |
result: res | |
remaining: chars.slice(i + 1) | |
} | |
class Keyword extends Parsing | |
constructor: (@words, @isWhitespaced) -> | |
parse: (text) => | |
for w in @words | |
if text.startsWith(w + (if @isWhitespaced then " " else "")) | |
return { | |
match: true | |
result: w + (if @isWhitespaced then " " else "") | |
remaining: text.slice(w.length + (if @isWhitespaced then 2 else 1)) | |
} | |
return { | |
match: false | |
result: "" | |
remaining: text | |
} | |
class CharsNotIn extends Parsing | |
constructor: (@chars) -> | |
parse: (text) => | |
res = "" | |
for l in text | |
if l in @chars | |
if res != "" | |
return { | |
match: false | |
result: res | |
remaining: text.slice(res.length + 1) | |
} | |
return { | |
match: true | |
result: res | |
remaining: text.slice(res.length + 1) | |
} | |
class P_And extends Parsing | |
constructor: (@parsers, @restrict) -> | |
if not @restrict? | |
@restrict = true | |
test: (text, full, results) => | |
return results.match | |
parse: (text, error, full) => | |
t = text | |
res = [] | |
if not restrict? | |
restrict = false | |
for p in @parsers | |
if p instanceof P_And | |
results = p.parse(t, ((parser, results) -> | |
if @restrict | |
throw new Error("Parsing error at char #{full.indexOf(t)}: not matching '#{parser}'!") | |
), full) | |
if not results? | |
t = results.remaining | |
else | |
results = p.parse(t) | |
if not @test(t, text, results) | |
if error? | |
error(p, results) | |
return null | |
res.push(results.result) | |
t = results.remaining | |
return { | |
result: res | |
remaining: t | |
} | |
class P_Or extends P_And | |
test: (text, full, results) => | |
return results.match | |
parse: (text, error) => | |
t = text | |
res = [] | |
if not restrict? | |
restrict = false | |
for p in @parsers | |
results = p.parse(t) | |
if @test(t, text, results) | |
return results.result | |
if error? | |
error(p, results) | |
P_Not extends P_And | |
constructor: (@parser) -> | |
parse: (text, error) => | |
rs = @parser.parse(text) | |
if not rs.match | |
return rs | |
else | |
if error? | |
error(@parser, rs) | |
return null | |
if require.main is module | |
P_And([]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment