Skip to content

Instantly share code, notes, and snippets.

@itsbth
Created January 8, 2012 21:28
Show Gist options
  • Select an option

  • Save itsbth/1579763 to your computer and use it in GitHub Desktop.

Select an option

Save itsbth/1579763 to your computer and use it in GitHub Desktop.
Uploaded by UploadToGist for Sublime Text 2
{Parser} = require 'jison'
# Stolen from coffee-script
# Since we're going to be wrapped in a function by Jison in any case, if our
# action immediately returns a value, we can optimize by removing the function
# wrapper and just returning the value directly.
unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/
# Our handy DSL for Jison grammar generation, thanks to
# [Tim Caswell](http://github.com/creationix). For every rule in the grammar,
# we pass the pattern-defining string, the action to run, and extra options,
# optionally. If no action is specified, we simply pass the value of the
# previous nonterminal.
o = (patternString, action, options) ->
patternString = patternString.replace /\s{2,}/g, ' '
return [patternString, '$$ = $1;', options] unless action
action = if match = unwrap.exec action then match[1] else "(#{action}())"
action = action.replace /\bnew /g, '$&yy.'
[patternString, "$$ = #{action};", options]
# End coffee-script loot
escape = (text) ->
text.replace /[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"
s = (regex) ->
[regex.toString().slice(1, -1), "/* om nom nom */"]
t = (name, regex=///#{escape name}///) ->
[regex.toString().slice(1, -1), "return #{JSON.stringify name};"]
grammar = lex: {}
grammar.lex.rules = [
t 'DIRECTIVE', /@.+\n/
s /\s+/
t 'NUMBER', /[0-9]+(?:\.[0-9]+)?\b/
t 'STRING', /(["'])(?:\\?.)*?\1/
t 'COMPOUND_ASSIGN', /(?:\+|\-|\*|\/)=/
t 'MATH', /\/|\*/
t 'COMPARE', /\==|!=|<|>|=<|=>/
t 'LOGIC', /&|\|/
t '+'
t '-'
t '='
t '&'
t '|'
t '!'
t '('
t ')'
t '?'
t ':'
t '{'
t '}'
t '['
t ']'
t 'IF', /if/
t 'ELSE', /else/
t 'ELSEIF', /elseif/
t 'WHILE', /while/
t 'FUNC', /[a-z][A-Za-z0-9_]+\b/
t 'VAR', /[A-Z][A-Za-z0-9_]+\b/
t 'EOF', /$/
]
for assoc in ['left', 'right', 'nonassoc']
o[assoc] = (args...) -> [assoc, args...]
grammar.operators = [
o.right ':'
o.right 'UNARY'
o.left 'MATH'
o.left '+', '-'
o.left 'COMPARE'
o.left 'LOGIC'
o.right 'COMPOUND_ASSIGN', '='
].reverse()
grammar.bnf =
Root: [
o 'DirectiveList StatementList EOF', -> new Root $1, $2
o 'StatementList EOF', -> new Root [], $1
]
DirectiveList: [
o 'DirectiveList DIRECTIVE', -> $1.push $2; $1
o 'DIRECTIVE', -> [$1]
]
StatementList: [
o 'StatementList Statement', -> $1.push $2; $1
o 'Statement', -> [$1]
]
Statement: [
o 'Expression'
o 'If'
]
Expression: [
o 'Operation'
o 'Literal', -> new Literal $1
o 'Assignable'
o 'Assignable = Expression', -> new Assignment $1, $3
o '( Expression )', -> $2
]
Operation: [
o '+ Expression', (-> new UnOp $1, $2), prec: 'UNARY'
o '- Expression', (-> new UnOp $1, $2), prec: 'UNARY'
o '! Expression', (-> new UnOp $1, $2), prec: 'UNARY'
o 'Expression + Expression', -> new BinOp $2, $1, $3
o 'Expression - Expression', -> new BinOp $2, $1, $3
o 'Expression MATH Expression', -> new BinOp $2, $1, $3
o 'Expression COMPARE Expression', -> new BinOp $2, $1, $3
o 'Expression LOGIC Expression', -> new BinOp $2, $1, $3
o 'Assignable COMPOUND_ASSIGN Expression', -> new BinOp $2, $1, $3
]
Literal: [
o 'NUMBER', -> parseFloat($1)
o 'STRING', -> $1.slice 1, -1
]
Assignable: [
o 'Assignable [ Expression ]', -> new Access $Assignable, $Expression
o 'VAR', -> new Var $1
]
If: [
o 'IF ( Expression ) { StatementList }', -> new If $Expression, $StatementList
]
While: [
o 'WHILE ( Expression ) { StatementList }', -> new While $Expression, $StatementList
]
# Return from the root node
for pattern in grammar.bnf.Root
pattern[1] = "return #{pattern[1]}"
exports.parser = new Parser(grammar)
exports.grammar = grammar
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment