Skip to content

Instantly share code, notes, and snippets.

@wallabra
Created June 30, 2017 12:09
Show Gist options
  • Save wallabra/b4412db7b99595f9b34286fa16059ed2 to your computer and use it in GitHub Desktop.
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)
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