Skip to content

Instantly share code, notes, and snippets.

@hdemon
Created September 17, 2015 16:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hdemon/9c63e3121ff296f95ee3 to your computer and use it in GitHub Desktop.
Save hdemon/9c63e3121ff296f95ee3 to your computer and use it in GitHub Desktop.
# Operator Type Precedence Description
# ’ ’ primary 5 Literal string
# " " primary 5 Literal string
# [ ] primary 5 Character class
# . primary 5 Any character
# (e) primary 5 Grouping
# e? unary suffix 4 Optional
# e* unary suffix 4 Zero-or-more
# e+ unary suffix 4 One-or-more
# &e unary prefix 3 And-predicate
# !e unary prefix 3 Not-predicate
# e1 e2 binary 2 Sequence
# e1 / e2 binary 1 Prioritized Choice
literal = (string) ->
(input) ->
pattern = new RegExp("^" + escapeRegExp(string))
if input.match(pattern)
remain = input.slice(string.length)
{ success: true, remain }
else
{ success: false, remain: input }
# any
#
# grouping expression
#
# optional expression
#
# zero_or_more expression
#
# one_or_more expression
#
# and_predicate expression
#
# not_predicate expression
#
sequence = (expressions) ->
index = 0
execute = (input) ->
if index == expressions.length
if input
return { success: false, remain: input }
else
return { success: true, remain: input }
parsed = expressions[index](input)
if parsed.remain
index += 1
execute(parsed.remain)
else
index = 0
{ success: true, remain: parsed.remain }
choice = (expressions) ->
index = 0
execute = (input) ->
if index == expressions.length
if input
return { success: false, remain: input }
else
return { success: true, remain: input }
parsed = expressions[index](input)
if parsed.success
index = 0
if parsed.remain
return { success: false, remain: parsed.remain }
else
return { success: true, remain: parsed.remain }
else
index += 1
execute(parsed.remain)
optional = (expression) ->
(input) ->
parsed = expression(input)
{ success: true, remain: parsed.remain }
oneOrMore = (expression) ->
execute = (input) ->
parsed = expression(input)
if parsed.success
if parsed.remain
execute(parsed.remain)
else
{ success: true, remain: parsed.remain }
else
{ success: false, remain: parsed.remain }
escapeRegExp = (string) ->
string.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")
# (ab / ac) d?
# parser = sequence([choice([literal("ab"), literal("ac")]), optional(literal("d"))])
# digit = 0/1/2/3/4/5/6/7/8/9
digitWithOutZero = choice([literal("1"), literal("2"), literal("3"), literal("4"), literal("5"), literal("6"), literal("7"), literal("8"), literal("9")])
digit = choice([literal("0"), literal("1"), literal("2"), literal("3"), literal("4"), literal("5"), literal("6"), literal("7"), literal("8"), literal("9")])
# number = digit+
integer = sequence([digit, zeroOrMore(digit)])
program = expression
# expression = number (operator number)+
atomExpression = sequence([number, oneOrMore(sequence([operator, number]))])
# expression = "(" ")"
expression = sequence([literal("("), choice([number, expression]), literal(")")])
console.log expression("(1)")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment