diff --git a/SYNTAX b/SYNTAX new file mode 100644 index 0000000000..cd788ee26d --- /dev/null +++ b/SYNTAX @@ -0,0 +1,30 @@ +Every line is an expression. Multiple expressions on a single line can be +separated by a ";" character. + +NUM: 1 + 1.0 + +STRING: "hello" + 'hello' + +OBJECT: {one : 1, two : 2} + +ARRAY: [1, 2, 3] + +CODE: a, b => a * b. + +IF: return x if x > 1 + + if (x > 1) return x + +ASSIGN: a : b + +LOGICAL: x && y + x and y + x || y + x or y + + + + + diff --git a/code.jaa b/code.jaa new file mode 100644 index 0000000000..56a10e3a39 --- /dev/null +++ b/code.jaa @@ -0,0 +1,40 @@ +# I'm a comment and I'm ok. +# Return +# Case + +square: x => x * x. + +sum: x, y => x + y. + +odd: x => x % 2 is 0. + +even: x => x % 2 aint 0. + +object_literal: {one: 1, two: 2, three: 3} + +multiline_object: { + pi: 3.14159 + list: [1, 2, 3, 4] + three: 3 + inner_obj: { + freedom: => _.freedom(). + } +} + +run_loop: => + fire_events(e => e.stopPropagation().) + listen() + wait(). + +if submarine.shields_up + full_speed_ahead() + weapons.fire_torpedos() +else + run_away(). + +eldest: if 25 > 21 then liz else marge. + + + + + diff --git a/documents.jaa b/documents.jaa new file mode 100644 index 0000000000..479dce543d --- /dev/null +++ b/documents.jaa @@ -0,0 +1,76 @@ +# Document Model +dc.model.Document: dc.Model.extend({ + + constructor : attributes => this.base(attributes). + + # For display, show either the highlighted search results, or the summary, + # if no highlights are available. + # The import process will take care of this in the future, but the inline + # version of the summary has all runs of whitespace squeezed out. + displaySummary : => + text: this.get('highlight') or this.get('summary') + text ? text.replace(/\s+/g, ' ') else '' + + # Return a list of the document's metadata. Think about caching this on the + # document by binding to Metadata, instead of on-the-fly. + metadata : => + docId : this.id + _.select(Metadata.models(), (m => + _.any(m.get('instances'), (i => + i.document_id == docId + )) + )) + + bookmark : pageNumber => + bookmark : new dc.model.Bookmark({title : this.get('title'), page_number : pageNumber, document_id : this.id}) + Bookmarks.create(bookmark) + + # Inspect. + toString : => + 'Document ' + this.id + ' "' + this.get('title') + '"' + +}) + +# Document Set +dc.model.DocumentSet : dc.model.RESTfulSet.extend({ + + resource : 'documents' + + SELECTION_CHANGED : 'documents:selection_changed' + + constructor : options => + this.base(options) + _.bindAll(this, 'downloadSelectedViewers', 'downloadSelectedPDF', 'downloadSelectedFullText') + + selected : => _.select(this.models(), m => m.get('selected')) + + selectedIds : => _.pluck(this.selected(), 'id') + + countSelected : => this.selected().length + + downloadSelectedViewers : => + dc.app.download('/download/' + this.selectedIds().join('/') + '/document_viewer.zip'); + + downloadSelectedPDF : => + return window.open(this.selected()[0].get('pdf_url')) if this.countSelected() <= 1 + dc.app.download('/download/' + this.selectedIds().join('/') + '/document_pdfs.zip') + + downloadSelectedFullText : => + return window.open(this.selected()[0].get('full_text_url')) if this.countSelected() <= 1 + dc.app.download('/download/' + this.selectedIds().join('/') + '/document_text.zip') + + # We override "_onModelEvent" to fire selection changed events when documents + # change their selected state. + _onModelEvent : e, model => + this.base(e, model) + fire : (e == dc.Model.CHANGED and model.hasChanged('selected')) + _.defer(_(this.fire).bind(this, this.SELECTION_CHANGED, this)) if fire + } + +}) + +# The main set of Documents, used by the search tab. +window.Documents : new dc.model.DocumentSet() + +# The set of documents that is used to look at a particular label. +dc.app.LabeledDocuments : new dc.model.DocumentSet() diff --git a/grammar.y b/grammar.y new file mode 100644 index 0000000000..580ca76d6f --- /dev/null +++ b/grammar.y @@ -0,0 +1,206 @@ +class Parser + +# Declare tokens produced by the lexer +token IF ELSE THEN +token NEWLINE +token NUMBER +token STRING +token TRUE FALSE NULL +token IDENTIFIER PROPERTY_ACCESS +token CODE + +prechigh + nonassoc UMINUS NOT '!' + left '*' '/' '%' + left '+' '-' + left '<=' '<' '>' '>=' + right '==' '!=' IS AINT + left '&&' '||' AND OR + right '-=' '+=' '/=' '*=' +preclow + +rule + # All rules are declared in this format: + # + # RuleName: + # OtherRule TOKEN AnotherRule { code to run when this matches } + # | OtherRule { ... } + # ; + # + # In the code section (inside the {...} on the right): + # - Assign to "result" the value returned by the rule. + # - Use val[index of expression] to reference expressions on the left. + + + # All parsing will end in this rule, being the trunk of the AST. + Root: + /* nothing */ { result = Nodes.new([]) } + | Expressions { result = val[0] } + ; + + # Any list of expressions or method body, seperated by line breaks. + Expressions: + Expression { result = Nodes.new(val) } + | Expressions Terminator Expression { result = val[0] << val[2] } + | Expressions Terminator { result = Nodes.new([val[0]]) } + | Terminator Expressions { result = Nodes.new([val[1]]) } + ; + + # All types of expressions in our language + Expression: + Literal + | Variable + | Call + | Assign + | Object + | Code + | Operation + | Array + | If + ; + + # All tokens that can terminate an expression + Terminator: + "\n" + | ";" + ; + + # All hard-coded values + Literal: + NUMBER { result = LiteralNode.new(val[0]) } + | STRING { result = LiteralNode.new(val[0]) } + | TRUE { result = LiteralNode.new(true) } + | FALSE { result = LiteralNode.new(false) } + | NULL { result = LiteralNode.new(nil) } + ; + + # Assign to a variable + Assign: + Variable ":" Expression { result = AssignNode.new(val[0], val[2]) } + ; + + # Assignment within an object literal. + AssignObj: + IDENTIFIER ":" Expression { result = AssignNode.new(val[0], val[2], :object) } + ; + + # Arithmetic and logical operators + # For Ruby's Operator precedence, see: + # https://www.cs.auckland.ac.nz/references/ruby/ProgrammingRuby/language.html + Operation: + '!' Expression { result = OpNode.new(val[0], val[1]) } + | '-' Expression = UMINUS { result = OpNode.new(val[0], val[1]) } + | NOT Expression { result = OpNode.new(val[0], val[1]) } + + + | Expression '*' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '/' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '%' Expression { result = OpNode.new(val[1], val[0], val[2]) } + + | Expression '+' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '-' Expression { result = OpNode.new(val[1], val[0], val[2]) } + + | Expression '<=' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '<' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '>' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '>=' Expression { result = OpNode.new(val[1], val[0], val[2]) } + + | Expression '==' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '!=' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression IS Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression AINT Expression { result = OpNode.new(val[1], val[0], val[2]) } + + | Expression '&&' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '||' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression AND Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression OR Expression { result = OpNode.new(val[1], val[0], val[2]) } + + # Add ternary? + + | Expression '-=' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '+=' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '/=' Expression { result = OpNode.new(val[1], val[0], val[2]) } + | Expression '*=' Expression { result = OpNode.new(val[1], val[0], val[2]) } + # Add ||= &&= + ; + + + # Method definition + Code: + "=>" Expressions "." { result = CodeNode.new([], val[1]) } + | ParamList + "=>" Expressions "." { result = CodeNode.new(val[0], val[2]) } + ; + + ParamList: + /* nothing */ { result = [] } + | IDENTIFIER { result = val } + | ParamList "," IDENTIFIER { result = val[0] << val[2] } + ; + + Variable: + IDENTIFIER { result = VariableNode.new(val) } + | Variable PROPERTY_ACCESS IDENTIFIER { result = val[0] << val[2] } + ; + + Object: + "{" "}" { result = ObjectNode.new([]) } + | "{" AssignList "}" { result = ObjectNode.new(val[1]) } + | "{" Terminator AssignList + Terminator "}" { result = ObjectNode.new(val[2]) } + ; + + AssignList: + /* nothing */ { result = []} + | AssignObj { result = val } + | AssignList "," AssignObj { result = val[0] << val[2] } + | AssignList Terminator AssignObj { result = val[0] << val[2] } + ; + + # A method call. + Call: + Variable "(" ArgList ")" { result = CallNode.new(val[0], val[2]) } + ; + + # An Array. + Array: + "[" ArgList "]" { result = ArrayNode.new(val[1]) } + ; + + # A list of arguments to a method call. + ArgList: + /* nothing */ { result = [] } + | Expression { result = val } + | ArgList "," Expression { result = val[0] << val[2] } + ; + + If: + IF Expression + THEN Expression "." { result = TernaryNode.new(val[1], val[3]) } + | IF Expression Terminator + Expressions "." { result = IfNode.new(val[1], val[3]) } + | IF Expression + THEN Expression + ELSE Expression "." { result = TernaryNode.new(val[1], val[3], val[5]) } + | IF Expression Terminator + Expressions Terminator + ELSE Expressions "." { result = IfNode.new(val[1], val[3], val[6]) } + ; + +end + +---- header + require "lexer" + require "nodes" + +---- inner + def parse(code, show_tokens=false) + # @yydebug = true + @tokens = Lexer.new.tokenize(code) + puts @tokens.inspect if show_tokens + do_parse + end + + def next_token + @tokens.shift + end \ No newline at end of file diff --git a/lexer.rb b/lexer.rb new file mode 100644 index 0000000000..b7420eb426 --- /dev/null +++ b/lexer.rb @@ -0,0 +1,90 @@ +class Lexer + + KEYWORDS = ["if", "else", "then", + "true", "false", "null", + "and", "or", "is", "aint", "not"] + + IDENTIFIER = /\A([a-zA-Z$_]\w*)/ + NUMBER = /\A([0-9]+(\.[0-9]+)?)/ + STRING = /\A["'](.*?)["']/ + OPERATOR = /\A([+\*&|\/\-%=<>]+)/ + WHITESPACE = /\A([ \t\r]+)/ + NEWLINE = /\A([\r\n]+)/ + COMMENT = /\A(#[^\r\n]*)/ + CODE = /\A(=>)/ + + # This is how to implement a very simple scanner. + # Scan one caracter at the time until you find something to parse. + def tokenize(code) + @code = code.chomp # Cleanup code by remove extra line breaks + @i = 0 # Current character position we're parsing + @tokens = [] # Collection of all parsed tokens in the form [:TOKEN_TYPE, value] + while @i < @code.length + @chunk = @code[@i..-1] + extract_next_token + end + @tokens + end + + def extract_next_token + return if identifier_token + return if number_token + return if string_token + return if remove_comment + return if whitespace_token + return literal_token + end + + # Matching if, print, method names, etc. + def identifier_token + return false unless identifier = @chunk[IDENTIFIER, 1] + # Keywords are special identifiers tagged with their own name, 'if' will result + # in an [:IF, "if"] token + tag = KEYWORDS.include?(identifier) ? identifier.upcase.to_sym : :IDENTIFIER + if tag == :IDENTIFIER && @tokens[-1] && @tokens[-1][1] == '.' + @tokens[-1] = [:PROPERTY_ACCESS, '.'] + end + @tokens << [tag, identifier] + @i += identifier.length + end + + def number_token + return false unless number = @chunk[NUMBER, 1] + float = number.include?('.') + @tokens << [:NUMBER, float ? number.to_f : number.to_i] + @i += number.length + end + + def string_token + return false unless string = @chunk[STRING, 1] + @tokens << [:STRING, string] + @i += string.length + 2 + end + + def remove_comment + return false unless comment = @chunk[COMMENT, 1] + @i += comment.length + end + + # Ignore whitespace + def whitespace_token + return false unless whitespace = @chunk[WHITESPACE, 1] + @i += whitespace.length + end + + # We treat all other single characters as a token. Eg.: ( ) , . ! + # Multi-character operators are also literal tokens, so that Racc can assign + # the proper order of operations. Multiple newlines get merged. + def literal_token + value = @chunk[NEWLINE, 1] + if value + @tokens << ["\n", "\n"] unless @tokens.last && @tokens.last[0] == "\n" + return @i += value.length + end + value = @chunk[OPERATOR, 1] + value ||= @chunk[0,1] + @tokens << [value, value] + @i += value.length + end + +end \ No newline at end of file diff --git a/lexer_test.rb b/lexer_test.rb new file mode 100644 index 0000000000..0a1334a50c --- /dev/null +++ b/lexer_test.rb @@ -0,0 +1,2 @@ +require "lexer" +p Lexer.new.tokenize(File.read('code.jaa')) diff --git a/nodes.rb b/nodes.rb new file mode 100644 index 0000000000..1d20f1e3d5 --- /dev/null +++ b/nodes.rb @@ -0,0 +1,176 @@ +# Tabs are two spaces for pretty-printing. +TAB = ' ' + +# Collection of nodes each one representing an expression. +class Nodes + attr_reader :nodes + def initialize(nodes) + @nodes = nodes + end + + def <<(node) + @nodes << node + self + end + + # Flatten redundant nested node lists until we have multiple nodes on the + # same level to work with. + def reduce + return nodes.first.reduce if nodes.length == 1 && nodes.first.is_a?(Nodes) + nodes + end + + def compile(indent='') + reduce.map { |node| + indent + node.compile(indent) + (node.is_a?(IfNode) ? '' : ';') + }.join("\n") + end +end + +# Literals are static values that have a Ruby representation, eg.: a string, a number, +# true, false, nil, etc. +class LiteralNode + def initialize(value) + @value = value + end + + def compile(indent) + @value.to_s + end +end + +# Node of a method call or local variable access, can take any of these forms: +# +# method # this form can also be a local variable +# method(argument1, argument2) +# receiver.method +# receiver.method(argument1, argument2) +# +class CallNode + def initialize(variable, arguments=[]) + @variable, @arguments = variable, arguments + end + + def compile(indent) + args = @arguments.map{|a| a.compile(indent) }.join(', ') + "#{@variable.compile(indent)}(#{args})" + end +end + +class VariableNode + def initialize(name) + @name = name + @properties = [] + end + + def <<(other) + @properties << other + self + end + + def compile(indent) + [@name, @properties].flatten.join('.') + end +end + +# Setting the value of a local variable. +class AssignNode + def initialize(variable, value, context=nil) + @variable, @value, @context = variable, value, context + end + + def compile(indent) + return "#{@variable}: #{@value.compile(indent + TAB)}" if @context == :object + "var #{@variable.compile(indent)} = #{@value.compile(indent)}" + end +end + +# Simple Arithmetic and logical operations +class OpNode + CONVERSIONS = { + "==" => "===", + "!=" => "!==", + 'and' => '&&', + 'or' => '||', + 'is' => '===', + "aint" => "!==", + 'not' => '!', + } + + def initialize(operator, first, second=nil) + @first, @second = first, second + @operator = CONVERSIONS[operator] || operator + end + + def unary? + @second.nil? + end + + def compile(indent) + "(#{@first.compile(indent)} #{@operator} #{@second.compile(indent)})" + end +end + +# Method definition. +class CodeNode + def initialize(params, body) + @params = params + @body = body + end + + def compile(indent) + nodes = @body.reduce + exprs = nodes.map {|n| n.compile(indent + TAB) } + exprs[-1] = "return #{exprs[-1]};" + exprs = exprs.map {|e| indent + TAB + e } + "function(#{@params.join(', ')}) {\n#{exprs.join(";\n")}\n#{indent}}" + end +end + +class ObjectNode + def initialize(properties = []) + @properties = properties + end + + def compile(indent) + props = @properties.map {|p| indent + TAB + p.compile(indent) }.join(",\n") + "{\n#{props}\n#{indent}}" + end +end + +class ArrayNode + def initialize(objects=[]) + @objects = objects + end + + def compile(indent) + objects = @objects.map {|o| o.compile(indent) }.join(', ') + "[#{objects}]" + end +end + +# "if-else" control structure. Look at this node if you want to implement other control +# structures like while, for, loop, etc. +class IfNode + def initialize(condition, body, else_body=nil) + @condition, @body, @else_body = condition, body, else_body + end + + def compile(indent) + if_part = "if (#{@condition.compile(indent)}) {\n#{@body.compile(indent + TAB)}\n#{indent}}" + else_part = @else_body ? " else {\n#{@else_body.compile(indent + TAB)}\n#{indent}}" : '' + if_part + else_part + end +end + +class TernaryNode + def initialize(condition, body, else_body=nil) + @condition, @body, @else_body = condition, body, else_body + end + + def compile(indent) + if_part = "#{@condition.compile(indent)} ? #{@body.compile(indent)}" + else_part = @else_body ? "#{@else_body.compile(indent)}" : 'null' + "#{if_part} : #{else_part}" + end +end \ No newline at end of file diff --git a/parser.rb b/parser.rb new file mode 100644 index 0000000000..a848065aba --- /dev/null +++ b/parser.rb @@ -0,0 +1,1090 @@ +# +# DO NOT MODIFY!!!! +# This file is automatically generated by Racc 1.4.6 +# from Racc grammer file "". +# + +require 'racc/parser.rb' + + require "lexer" + require "nodes" + +class Parser < Racc::Parser + +module_eval(<<'...end grammar.y/module_eval...', 'grammar.y', 197) + def parse(code, show_tokens=false) + # @yydebug = true + @tokens = Lexer.new.tokenize(code) + puts @tokens.inspect if show_tokens + do_parse + end + + def next_token + @tokens.shift + end +...end grammar.y/module_eval... +##### State transition tables begin ### + +racc_action_table = [ + 5, 83, 31, 35, 14, 17, 21, 24, 28, 2, + 12, 15, 82, 9, 11, 73, 5, 31, 81, 27, + 14, 17, 21, 24, 28, 2, 74, 12, 15, 9, + 11, 37, 73, 31, 71, 27, 118, 36, -52, 20, + -52, 67, 1, 68, 12, 15, 8, -65, 82, 12, + 15, 32, 113, 84, 31, 20, 12, 15, 1, 5, + 127, -65, 8, 14, 17, 21, 24, 28, 2, 76, + 12, 15, 9, 11, 121, 5, 12, 15, 27, 14, + 17, 21, 24, 28, 2, 43, 12, 15, 9, 11, + 117, 58, 60, 62, 27, 12, 15, 31, 20, 12, + 15, 1, 58, 60, 62, 8, 58, 60, 62, 64, + 66, 108, nil, nil, 20, nil, nil, 1, 5, nil, + nil, 8, 14, 17, 21, 24, 28, 2, nil, nil, + nil, 9, 11, nil, 5, nil, nil, 27, 14, 17, + 21, 24, 28, 2, nil, nil, nil, 9, 11, nil, + nil, nil, nil, 27, nil, nil, nil, 20, nil, nil, + 1, nil, nil, nil, 8, 58, 60, 62, 64, 66, + 12, 15, nil, 20, nil, -51, 1, 5, nil, nil, + 8, 14, 17, 21, 24, 28, 2, nil, nil, nil, + 9, 11, nil, 5, nil, nil, 27, 14, 17, 21, + 24, 28, 2, nil, nil, nil, 9, 11, nil, nil, + nil, nil, 27, nil, nil, nil, 20, nil, nil, 1, + nil, nil, nil, 8, 58, 60, 62, 64, 66, nil, + nil, nil, 20, nil, nil, 1, 5, nil, nil, 8, + 14, 17, 21, 24, 28, 2, nil, nil, nil, 9, + 11, nil, 5, nil, nil, 27, 14, 17, 21, 24, + 28, 2, nil, nil, nil, 9, 11, nil, nil, nil, + nil, 27, 12, 15, nil, 20, nil, nil, 1, nil, + nil, nil, 8, 58, 60, 62, 64, 66, 12, 15, + nil, 20, nil, nil, 1, 5, 124, nil, 8, 14, + 17, 21, 24, 28, 2, nil, nil, nil, 9, 11, + nil, 5, nil, nil, 27, 14, 17, 21, 24, 28, + 2, nil, nil, nil, 9, 11, nil, nil, nil, nil, + 27, nil, nil, nil, 20, nil, -51, 1, nil, nil, + nil, 8, nil, nil, nil, nil, nil, nil, nil, nil, + 20, nil, nil, 1, 5, nil, nil, 8, 14, 17, + 21, 24, 28, 2, nil, nil, nil, 9, 11, nil, + 5, nil, nil, 27, 14, 17, 21, 24, 28, 2, + nil, nil, nil, 9, 11, nil, nil, nil, nil, 27, + nil, nil, nil, 20, nil, nil, 1, nil, nil, nil, + 8, nil, nil, nil, nil, nil, nil, nil, nil, 20, + nil, nil, 1, 5, nil, nil, 8, 14, 17, 21, + 24, 28, 2, nil, nil, nil, 9, 11, nil, 5, + nil, nil, 27, 14, 17, 21, 24, 28, 2, nil, + nil, nil, 9, 11, nil, nil, nil, nil, 27, 12, + 15, nil, 20, nil, nil, 1, nil, nil, nil, 8, + nil, nil, nil, nil, nil, 12, 15, nil, 20, nil, + nil, 1, 5, nil, nil, 8, 14, 17, 21, 24, + 28, 2, nil, nil, nil, 9, 11, nil, 5, nil, + nil, 27, 14, 17, 21, 24, 28, 2, nil, nil, + nil, 9, 11, nil, nil, nil, nil, 27, nil, nil, + nil, 20, nil, nil, 1, nil, nil, nil, 8, nil, + nil, nil, nil, nil, nil, nil, nil, 20, nil, nil, + 1, 5, nil, nil, 8, 14, 17, 21, 24, 28, + 2, nil, nil, nil, 9, 11, nil, 5, nil, nil, + 27, 14, 17, 21, 24, 28, 2, nil, nil, nil, + 9, 11, nil, nil, nil, nil, 27, nil, nil, nil, + 20, nil, nil, 1, nil, nil, nil, 8, nil, nil, + nil, nil, nil, nil, nil, nil, 20, nil, nil, 1, + 5, nil, nil, 8, 14, 17, 21, 24, 28, 2, + nil, nil, nil, 9, 11, nil, 5, nil, nil, 27, + 14, 17, 21, 24, 28, 2, nil, nil, nil, 9, + 11, nil, nil, nil, nil, 27, nil, nil, nil, 20, + nil, nil, 1, nil, nil, nil, 8, nil, nil, nil, + nil, nil, nil, nil, nil, 20, nil, nil, 1, 5, + nil, nil, 8, 14, 17, 21, 24, 28, 2, nil, + nil, nil, 9, 11, nil, 5, nil, nil, 27, 14, + 17, 21, 24, 28, 2, nil, nil, nil, 9, 11, + nil, nil, nil, nil, 27, nil, nil, nil, 20, nil, + nil, 1, nil, nil, nil, 8, nil, nil, nil, nil, + nil, nil, nil, nil, 20, nil, nil, 1, 5, nil, + nil, 8, 14, 17, 21, 24, 28, 2, nil, nil, + nil, 9, 11, nil, 5, nil, nil, 27, 14, 17, + 21, 24, 28, 2, nil, nil, nil, 9, 11, nil, + nil, nil, nil, 27, nil, nil, nil, 20, nil, nil, + 1, nil, nil, nil, 8, nil, nil, nil, nil, nil, + nil, nil, nil, 20, nil, nil, 1, 5, nil, nil, + 8, 14, 17, 21, 24, 28, 2, nil, nil, nil, + 9, 11, nil, 5, nil, nil, 27, 14, 17, 21, + 24, 28, 2, nil, nil, nil, 9, 11, nil, nil, + nil, nil, 27, nil, nil, nil, 20, nil, -51, 1, + nil, nil, nil, 8, nil, nil, nil, nil, nil, nil, + nil, nil, 20, nil, nil, 1, 5, nil, nil, 8, + 14, 17, 21, 24, 28, 2, nil, nil, nil, 9, + 11, nil, 5, nil, nil, 27, 14, 17, 21, 24, + 28, 2, nil, nil, nil, 9, 11, nil, nil, nil, + nil, 27, nil, nil, nil, 20, nil, nil, 1, nil, + nil, nil, 8, nil, nil, nil, nil, nil, nil, nil, + nil, 20, nil, nil, 1, 5, nil, nil, 8, 14, + 17, 21, 24, 28, 2, nil, nil, nil, 9, 11, + nil, 5, nil, nil, 27, 14, 17, 21, 24, 28, + 2, nil, nil, nil, 9, 11, nil, nil, nil, nil, + 27, nil, nil, nil, 20, nil, nil, 1, nil, nil, + nil, 8, nil, nil, nil, nil, nil, nil, nil, nil, + 20, nil, nil, 1, 5, nil, nil, 8, 14, 17, + 21, 24, 28, 2, nil, nil, nil, 9, 11, nil, + 5, nil, nil, 27, 14, 17, 21, 24, 28, 2, + nil, nil, nil, 9, 11, nil, nil, nil, nil, 27, + nil, nil, nil, 20, nil, nil, 1, nil, nil, nil, + 8, nil, nil, nil, nil, nil, nil, nil, nil, 20, + nil, nil, 1, 5, nil, nil, 8, 14, 17, 21, + 24, 28, 2, nil, nil, nil, 9, 11, nil, 5, + nil, nil, 27, 14, 17, 21, 24, 28, 2, nil, + nil, nil, 9, 11, nil, nil, nil, nil, 27, nil, + nil, nil, 20, nil, nil, 1, nil, nil, nil, 8, + nil, nil, nil, nil, nil, nil, nil, nil, 20, nil, + nil, 1, 5, nil, nil, 8, 14, 17, 21, 24, + 28, 2, nil, nil, nil, 9, 11, nil, 5, nil, + nil, 27, 14, 17, 21, 24, 28, 2, nil, nil, + nil, 9, 11, nil, nil, nil, nil, 27, nil, nil, + nil, 20, nil, nil, 1, nil, nil, nil, 8, nil, + nil, nil, nil, nil, nil, nil, nil, 20, nil, nil, + 1, 5, nil, nil, 8, 14, 17, 21, 24, 28, + 2, nil, nil, nil, 9, 11, nil, 5, nil, nil, + 27, 14, 17, 21, 24, 28, 2, nil, nil, nil, + 9, 11, nil, nil, nil, nil, 27, nil, nil, nil, + 20, nil, nil, 1, nil, nil, nil, 8, nil, nil, + 119, nil, nil, nil, nil, nil, 20, nil, nil, 1, + nil, nil, nil, 8, 58, 60, 62, 64, 66, 47, + 49, 51, 53, 55, 56, 57, 59, 61, 63, 65, + 46, 48, 50, 52, 54, 79, nil, nil, nil, 120, + nil, nil, nil, nil, nil, nil, nil, nil, 58, 60, + 62, 64, 66, 47, 49, 51, 53, 55, 56, 57, + 59, 61, 63, 65, 46, 48, 50, 52, 54, 12, + 15, 58, 60, 62, 64, 66, 47, 49, 51, 53, + 55, 56, 57, 59, 61, 63, 65, 46, 48, 50, + 52, 54, nil, nil, nil, nil, 125, 58, 60, 62, + 64, 66, 47, 49, 51, 53, 55, 56, 57, 59, + 61, 63, 65, 46, 48, 50, 52, 54, 58, 60, + 62, 64, 66, 47, 49, 51, 53, 55, 56, 57, + 59, 61, 63, 65, 46, 48, 50, 52, 54, 58, + 60, 62, 64, 66, 47, 49, 51, 53, 55, 56, + 57, 59, 61, 63, 65, 46, 48, 50, 52, 54, + 58, 60, 62, 64, 66, 47, 49, 51, 53, 55, + 56, 57, 59, 61, 63, 65, 46, 48, 50, 52, + 54, 58, 60, 62, 64, 66, 47, 49, 51, 53, + 55, 56, 57, 59, 61, 63, 65, 46, 48, 50, + 52, 54, 58, 60, 62, 64, 66, 47, 49, 51, + 53, 55, 56, 57, 59, 61, 63, 65, 46, 48, + 50, 52, 54, 58, 60, 62, 64, 66, 47, 49, + 51, 53, 55, 56, 57, 59, 61, 63, 65, 46, + 48, 50, 52, 54, 58, 60, 62, 64, 66, 47, + 49, 51, 53, 55, 56, 57, 59, 61, 63, 65, + 46, 48, 50, 52, 54, 58, 60, 62, 64, 66, + 47, 49, 51, 53, 55, 56, 57, 59, 61, 63, + 65, 46, 48, 50, 52, 54, 58, 60, 62, 64, + 66, 47, 49, 51, 53, 55, 56, 57, 59, 61, + 63, 65, 46, 48, 50, 52, 54, 58, 60, 62, + 64, 66, 47, 49, 51, 53, 55, 56, 57, 59, + 58, 60, 62, 64, 66, 47, 49, 51, 53, 55, + 56, 57, 59, 58, 60, 62, 64, 66, 47, 49, + 51, 53, 55, 56, 57, 59, 58, 60, 62, 64, + 66, 47, 49, 51, 53, 55, 56, 57, 59, 58, + 60, 62, 64, 66, 47, 49, 51, 53, 55, 56, + 57, 59, 58, 60, 62, 64, 66, 47, 49, 51, + 53, 55, 56, 57, 59, 58, 60, 62, 64, 66, + 47, 49, 51, 53, 55, 56, 57, 59, 58, 60, + 62, 64, 66, 47, 49, 51, 53, 55, 56, 57, + 59 ] + +racc_action_check = [ + 8, 43, 112, 4, 8, 8, 8, 8, 8, 8, + 75, 75, 39, 8, 8, 75, 36, 1, 39, 8, + 36, 36, 36, 36, 36, 36, 31, 30, 30, 36, + 36, 4, 30, 73, 30, 36, 112, 4, 2, 8, + 2, 26, 8, 26, 1, 1, 8, 8, 77, 44, + 44, 1, 77, 44, 34, 36, 126, 126, 36, 124, + 126, 36, 36, 124, 124, 124, 124, 124, 124, 35, + 115, 115, 124, 124, 115, 74, 23, 23, 124, 74, + 74, 74, 74, 74, 74, 19, 107, 107, 74, 74, + 107, 104, 104, 104, 74, 124, 124, 72, 124, 70, + 70, 124, 106, 106, 106, 124, 93, 93, 93, 93, + 93, 68, nil, nil, 74, nil, nil, 74, 5, nil, + nil, 74, 5, 5, 5, 5, 5, 5, nil, nil, + nil, 5, 5, nil, 0, nil, nil, 5, 0, 0, + 0, 0, 0, 0, nil, nil, nil, 0, 0, nil, + nil, nil, nil, 0, nil, nil, nil, 5, nil, nil, + 5, nil, nil, nil, 5, 91, 91, 91, 91, 91, + 0, 0, nil, 0, nil, 0, 0, 9, nil, nil, + 0, 9, 9, 9, 9, 9, 9, nil, nil, nil, + 9, 9, nil, 11, nil, nil, 9, 11, 11, 11, + 11, 11, 11, nil, nil, nil, 11, 11, nil, nil, + nil, nil, 11, nil, nil, nil, 9, nil, nil, 9, + nil, nil, nil, 9, 89, 89, 89, 89, 89, nil, + nil, nil, 11, nil, nil, 11, 80, nil, nil, 11, + 80, 80, 80, 80, 80, 80, nil, nil, nil, 80, + 80, nil, 20, nil, nil, 80, 20, 20, 20, 20, + 20, 20, nil, nil, nil, 20, 20, nil, nil, nil, + nil, 20, 80, 80, nil, 80, nil, nil, 80, nil, + nil, nil, 80, 87, 87, 87, 87, 87, 20, 20, + nil, 20, nil, nil, 20, 122, 122, nil, 20, 122, + 122, 122, 122, 122, 122, nil, nil, nil, 122, 122, + nil, 82, nil, nil, 122, 82, 82, 82, 82, 82, + 82, nil, nil, nil, 82, 82, nil, nil, nil, nil, + 82, nil, nil, nil, 122, nil, 122, 122, nil, nil, + nil, 122, nil, nil, nil, nil, nil, nil, nil, nil, + 82, nil, nil, 82, 119, nil, nil, 82, 119, 119, + 119, 119, 119, 119, nil, nil, nil, 119, 119, nil, + 27, nil, nil, 119, 27, 27, 27, 27, 27, 27, + nil, nil, nil, 27, 27, nil, nil, nil, nil, 27, + nil, nil, nil, 119, nil, nil, 119, nil, nil, nil, + 119, nil, nil, nil, nil, nil, nil, nil, nil, 27, + nil, nil, 27, 29, nil, nil, 27, 29, 29, 29, + 29, 29, 29, nil, nil, nil, 29, 29, nil, 67, + nil, nil, 29, 67, 67, 67, 67, 67, 67, nil, + nil, nil, 67, 67, nil, nil, nil, nil, 67, 29, + 29, nil, 29, nil, nil, 29, nil, nil, nil, 29, + nil, nil, nil, nil, nil, 67, 67, nil, 67, nil, + nil, 67, 66, nil, nil, 67, 66, 66, 66, 66, + 66, 66, nil, nil, nil, 66, 66, nil, 65, nil, + nil, 66, 65, 65, 65, 65, 65, 65, nil, nil, + nil, 65, 65, nil, nil, nil, nil, 65, nil, nil, + nil, 66, nil, nil, 66, nil, nil, nil, 66, nil, + nil, nil, nil, nil, nil, nil, nil, 65, nil, nil, + 65, 64, nil, nil, 65, 64, 64, 64, 64, 64, + 64, nil, nil, nil, 64, 64, nil, 79, nil, nil, + 64, 79, 79, 79, 79, 79, 79, nil, nil, nil, + 79, 79, nil, nil, nil, nil, 79, nil, nil, nil, + 64, nil, nil, 64, nil, nil, nil, 64, nil, nil, + nil, nil, nil, nil, nil, nil, 79, nil, nil, 79, + 37, nil, nil, 79, 37, 37, 37, 37, 37, 37, + nil, nil, nil, 37, 37, nil, 63, nil, nil, 37, + 63, 63, 63, 63, 63, 63, nil, nil, nil, 63, + 63, nil, nil, nil, nil, 63, nil, nil, nil, 37, + nil, nil, 37, nil, nil, nil, 37, nil, nil, nil, + nil, nil, nil, nil, nil, 63, nil, nil, 63, 62, + nil, nil, 63, 62, 62, 62, 62, 62, 62, nil, + nil, nil, 62, 62, nil, 61, nil, nil, 62, 61, + 61, 61, 61, 61, 61, nil, nil, nil, 61, 61, + nil, nil, nil, nil, 61, nil, nil, nil, 62, nil, + nil, 62, nil, nil, nil, 62, nil, nil, nil, nil, + nil, nil, nil, nil, 61, nil, nil, 61, 60, nil, + nil, 61, 60, 60, 60, 60, 60, 60, nil, nil, + nil, 60, 60, nil, 59, nil, nil, 60, 59, 59, + 59, 59, 59, 59, nil, nil, nil, 59, 59, nil, + nil, nil, nil, 59, nil, nil, nil, 60, nil, nil, + 60, nil, nil, nil, 60, nil, nil, nil, nil, nil, + nil, nil, nil, 59, nil, nil, 59, 45, nil, nil, + 59, 45, 45, 45, 45, 45, 45, nil, nil, nil, + 45, 45, nil, 58, nil, nil, 45, 58, 58, 58, + 58, 58, 58, nil, nil, nil, 58, 58, nil, nil, + nil, nil, 58, nil, nil, nil, 45, nil, 45, 45, + nil, nil, nil, 45, nil, nil, nil, nil, nil, nil, + nil, nil, 58, nil, nil, 58, 47, nil, nil, 58, + 47, 47, 47, 47, 47, 47, nil, nil, nil, 47, + 47, nil, 48, nil, nil, 47, 48, 48, 48, 48, + 48, 48, nil, nil, nil, 48, 48, nil, nil, nil, + nil, 48, nil, nil, nil, 47, nil, nil, 47, nil, + nil, nil, 47, nil, nil, nil, nil, nil, nil, nil, + nil, 48, nil, nil, 48, 49, nil, nil, 48, 49, + 49, 49, 49, 49, 49, nil, nil, nil, 49, 49, + nil, 50, nil, nil, 49, 50, 50, 50, 50, 50, + 50, nil, nil, nil, 50, 50, nil, nil, nil, nil, + 50, nil, nil, nil, 49, nil, nil, 49, nil, nil, + nil, 49, nil, nil, nil, nil, nil, nil, nil, nil, + 50, nil, nil, 50, 51, nil, nil, 50, 51, 51, + 51, 51, 51, 51, nil, nil, nil, 51, 51, nil, + 52, nil, nil, 51, 52, 52, 52, 52, 52, 52, + nil, nil, nil, 52, 52, nil, nil, nil, nil, 52, + nil, nil, nil, 51, nil, nil, 51, nil, nil, nil, + 51, nil, nil, nil, nil, nil, nil, nil, nil, 52, + nil, nil, 52, 53, nil, nil, 52, 53, 53, 53, + 53, 53, 53, nil, nil, nil, 53, 53, nil, 54, + nil, nil, 53, 54, 54, 54, 54, 54, 54, nil, + nil, nil, 54, 54, nil, nil, nil, nil, 54, nil, + nil, nil, 53, nil, nil, 53, nil, nil, nil, 53, + nil, nil, nil, nil, nil, nil, nil, nil, 54, nil, + nil, 54, 55, nil, nil, 54, 55, 55, 55, 55, + 55, 55, nil, nil, nil, 55, 55, nil, 56, nil, + nil, 55, 56, 56, 56, 56, 56, 56, nil, nil, + nil, 56, 56, nil, nil, nil, nil, 56, nil, nil, + nil, 55, nil, nil, 55, nil, nil, nil, 55, nil, + nil, nil, nil, nil, nil, nil, nil, 56, nil, nil, + 56, 57, nil, nil, 56, 57, 57, 57, 57, 57, + 57, nil, nil, nil, 57, 57, nil, 46, nil, nil, + 57, 46, 46, 46, 46, 46, 46, nil, nil, nil, + 46, 46, nil, nil, nil, nil, 46, nil, nil, nil, + 57, nil, nil, 57, nil, nil, nil, 57, nil, nil, + 114, nil, nil, nil, nil, nil, 46, nil, nil, 46, + nil, nil, nil, 46, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 38, nil, nil, nil, 114, + nil, nil, nil, nil, nil, nil, nil, nil, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, nil, nil, nil, nil, 123, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 111, 111, 111, 111, 111, 111, 111, + 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, + 111, 111, 111, 111, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 105, 105, 105, 105, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 101, 101, 101, 101, 101, + 101, 101, 101, 101, 101, 101, 101, 101, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86 ] + +racc_action_pointer = [ + 132, 6, -3, nil, -9, 116, nil, nil, -2, 175, + nil, 191, nil, nil, nil, nil, nil, nil, nil, 85, + 250, nil, nil, 38, nil, 1355, 0, 368, nil, 411, + -11, -14, nil, nil, 43, 58, 14, 588, 1201, -31, + 1271, nil, nil, 1, 11, 765, 1135, 824, 840, 883, + 899, 942, 958, 1001, 1017, 1060, 1076, 1119, 781, 722, + 706, 663, 647, 604, 529, 486, 470, 427, 100, nil, + 61, nil, 86, 22, 73, -28, nil, 5, 1397, 545, + 234, nil, 309, nil, nil, 1250, 1551, 266, 1313, 207, + 1418, 148, 1439, 89, 1334, 1473, 1486, 1525, nil, 1460, + nil, 1538, nil, 1512, 74, 1499, 85, 48, nil, nil, + nil, 1376, -9, nil, 1167, 32, 1292, nil, nil, 352, + nil, nil, 293, 1224, 57, nil, 18, nil ] + +racc_action_default = [ + -1, -59, -54, -7, -8, -51, -9, -10, -51, -51, + -11, -51, -16, -12, -18, -17, -13, -19, -14, -72, + -51, -20, -15, -2, -21, -3, -72, -51, -22, -51, + -72, -72, -56, -60, -59, -72, -51, -51, -72, -72, + -66, -27, -25, -72, -72, -5, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -72, -26, + -6, -57, -72, -72, -51, -72, -55, -72, -23, -51, + -51, -64, -51, 128, -49, -4, -44, -33, -45, -34, + -46, -35, -47, -36, -48, -37, -38, -39, -28, -40, + -29, -41, -30, -42, -31, -43, -32, -72, -53, -62, + -61, -24, -72, -63, -72, -72, -67, -50, -58, -51, + -68, -69, -5, -72, -51, -70, -72, -71 ] + +racc_goto_table = [ + 34, 109, 110, 23, 38, 30, 39, 40, 41, 19, + 42, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, 45, 44, nil, nil, 69, nil, nil, 72, + nil, nil, 70, nil, 77, 40, 78, 80, 75, nil, + nil, 109, nil, 45, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, nil, nil, nil, 45, + 107, nil, nil, 111, 112, nil, nil, nil, 114, nil, + nil, 116, nil, 115, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, 45, nil, nil, nil, + nil, nil, nil, nil, 122, nil, nil, nil, 123, nil, + nil, 85, nil, nil, nil, 45, nil, 126 ] + +racc_goto_check = [ + 4, 14, 14, 2, 3, 16, 17, 3, 3, 1, + 3, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, 4, 2, nil, nil, 3, nil, nil, 4, + nil, nil, 2, nil, 17, 3, 3, 4, 16, nil, + nil, 14, nil, 4, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, nil, nil, nil, 4, + 2, nil, nil, 3, 4, nil, nil, nil, 3, nil, + nil, 3, nil, 2, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, 4, nil, nil, nil, + nil, nil, nil, nil, 4, nil, nil, nil, 3, nil, + nil, 3, nil, nil, nil, 4, nil, 2 ] + +racc_goto_pointer = [ + nil, 9, 3, -1, -1, nil, nil, nil, nil, nil, + nil, nil, nil, nil, -71, nil, 4, -2 ] + +racc_goto_default = [ + nil, nil, nil, 25, 29, 3, 4, 6, 7, 10, + 13, 16, 18, 22, 33, 26, nil, nil ] + +racc_reduce_table = [ + 0, 0, :racc_error, + 0, 51, :_reduce_1, + 1, 51, :_reduce_2, + 1, 52, :_reduce_3, + 3, 52, :_reduce_4, + 2, 52, :_reduce_5, + 2, 52, :_reduce_6, + 1, 53, :_reduce_none, + 1, 53, :_reduce_none, + 1, 53, :_reduce_none, + 1, 53, :_reduce_none, + 1, 53, :_reduce_none, + 1, 53, :_reduce_none, + 1, 53, :_reduce_none, + 1, 53, :_reduce_none, + 1, 53, :_reduce_none, + 1, 54, :_reduce_none, + 1, 54, :_reduce_none, + 1, 55, :_reduce_18, + 1, 55, :_reduce_19, + 1, 55, :_reduce_20, + 1, 55, :_reduce_21, + 1, 55, :_reduce_22, + 3, 58, :_reduce_23, + 3, 64, :_reduce_24, + 2, 61, :_reduce_25, + 2, 61, :_reduce_26, + 2, 61, :_reduce_27, + 3, 61, :_reduce_28, + 3, 61, :_reduce_29, + 3, 61, :_reduce_30, + 3, 61, :_reduce_31, + 3, 61, :_reduce_32, + 3, 61, :_reduce_33, + 3, 61, :_reduce_34, + 3, 61, :_reduce_35, + 3, 61, :_reduce_36, + 3, 61, :_reduce_37, + 3, 61, :_reduce_38, + 3, 61, :_reduce_39, + 3, 61, :_reduce_40, + 3, 61, :_reduce_41, + 3, 61, :_reduce_42, + 3, 61, :_reduce_43, + 3, 61, :_reduce_44, + 3, 61, :_reduce_45, + 3, 61, :_reduce_46, + 3, 61, :_reduce_47, + 3, 61, :_reduce_48, + 3, 60, :_reduce_49, + 4, 60, :_reduce_50, + 0, 65, :_reduce_51, + 1, 65, :_reduce_52, + 3, 65, :_reduce_53, + 1, 56, :_reduce_54, + 3, 56, :_reduce_55, + 2, 59, :_reduce_56, + 3, 59, :_reduce_57, + 5, 59, :_reduce_58, + 0, 66, :_reduce_59, + 1, 66, :_reduce_60, + 3, 66, :_reduce_61, + 3, 66, :_reduce_62, + 4, 57, :_reduce_63, + 3, 62, :_reduce_64, + 0, 67, :_reduce_65, + 1, 67, :_reduce_66, + 3, 67, :_reduce_67, + 5, 63, :_reduce_68, + 5, 63, :_reduce_69, + 7, 63, :_reduce_70, + 8, 63, :_reduce_71 ] + +racc_reduce_n = 72 + +racc_shift_n = 128 + +racc_token_table = { + false => 0, + :error => 1, + :IF => 2, + :ELSE => 3, + :THEN => 4, + :NEWLINE => 5, + :NUMBER => 6, + :STRING => 7, + :TRUE => 8, + :FALSE => 9, + :NULL => 10, + :IDENTIFIER => 11, + :PROPERTY_ACCESS => 12, + :CODE => 13, + :UMINUS => 14, + :NOT => 15, + "!" => 16, + "*" => 17, + "/" => 18, + "%" => 19, + "+" => 20, + "-" => 21, + "<=" => 22, + "<" => 23, + ">" => 24, + ">=" => 25, + "==" => 26, + "!=" => 27, + :IS => 28, + :AINT => 29, + "&&" => 30, + "||" => 31, + :AND => 32, + :OR => 33, + "-=" => 34, + "+=" => 35, + "/=" => 36, + "*=" => 37, + "\n" => 38, + ";" => 39, + ":" => 40, + "=>" => 41, + "." => 42, + "," => 43, + "{" => 44, + "}" => 45, + "(" => 46, + ")" => 47, + "[" => 48, + "]" => 49 } + +racc_nt_base = 50 + +racc_use_result_var = true + +Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + +Racc_token_to_s_table = [ + "$end", + "error", + "IF", + "ELSE", + "THEN", + "NEWLINE", + "NUMBER", + "STRING", + "TRUE", + "FALSE", + "NULL", + "IDENTIFIER", + "PROPERTY_ACCESS", + "CODE", + "UMINUS", + "NOT", + "\"!\"", + "\"*\"", + "\"/\"", + "\"%\"", + "\"+\"", + "\"-\"", + "\"<=\"", + "\"<\"", + "\">\"", + "\">=\"", + "\"==\"", + "\"!=\"", + "IS", + "AINT", + "\"&&\"", + "\"||\"", + "AND", + "OR", + "\"-=\"", + "\"+=\"", + "\"/=\"", + "\"*=\"", + "\"\\n\"", + "\";\"", + "\":\"", + "\"=>\"", + "\".\"", + "\",\"", + "\"{\"", + "\"}\"", + "\"(\"", + "\")\"", + "\"[\"", + "\"]\"", + "$start", + "Root", + "Expressions", + "Expression", + "Terminator", + "Literal", + "Variable", + "Call", + "Assign", + "Object", + "Code", + "Operation", + "Array", + "If", + "AssignObj", + "ParamList", + "AssignList", + "ArgList" ] + +Racc_debug_parser = false + +##### State transition tables end ##### + +# reduce 0 omitted + +module_eval(<<'.,.,', 'grammar.y', 36) + def _reduce_1(val, _values, result) + result = Nodes.new([]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 37) + def _reduce_2(val, _values, result) + result = val[0] + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 42) + def _reduce_3(val, _values, result) + result = Nodes.new(val) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 43) + def _reduce_4(val, _values, result) + result = val[0] << val[2] + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 44) + def _reduce_5(val, _values, result) + result = Nodes.new([val[0]]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 45) + def _reduce_6(val, _values, result) + result = Nodes.new([val[1]]) + result + end +.,., + +# reduce 7 omitted + +# reduce 8 omitted + +# reduce 9 omitted + +# reduce 10 omitted + +# reduce 11 omitted + +# reduce 12 omitted + +# reduce 13 omitted + +# reduce 14 omitted + +# reduce 15 omitted + +# reduce 16 omitted + +# reduce 17 omitted + +module_eval(<<'.,.,', 'grammar.y', 69) + def _reduce_18(val, _values, result) + result = LiteralNode.new(val[0]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 70) + def _reduce_19(val, _values, result) + result = LiteralNode.new(val[0]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 71) + def _reduce_20(val, _values, result) + result = LiteralNode.new(true) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 72) + def _reduce_21(val, _values, result) + result = LiteralNode.new(false) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 73) + def _reduce_22(val, _values, result) + result = LiteralNode.new(nil) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 78) + def _reduce_23(val, _values, result) + result = AssignNode.new(val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 83) + def _reduce_24(val, _values, result) + result = AssignNode.new(val[0], val[2], :object) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 90) + def _reduce_25(val, _values, result) + result = OpNode.new(val[0], val[1]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 91) + def _reduce_26(val, _values, result) + result = OpNode.new(val[0], val[1]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 92) + def _reduce_27(val, _values, result) + result = OpNode.new(val[0], val[1]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 95) + def _reduce_28(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 96) + def _reduce_29(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 97) + def _reduce_30(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 99) + def _reduce_31(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 100) + def _reduce_32(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 102) + def _reduce_33(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 103) + def _reduce_34(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 104) + def _reduce_35(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 105) + def _reduce_36(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 107) + def _reduce_37(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 108) + def _reduce_38(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 109) + def _reduce_39(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 110) + def _reduce_40(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 112) + def _reduce_41(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 113) + def _reduce_42(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 114) + def _reduce_43(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 115) + def _reduce_44(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 119) + def _reduce_45(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 120) + def _reduce_46(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 121) + def _reduce_47(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 122) + def _reduce_48(val, _values, result) + result = OpNode.new(val[1], val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 129) + def _reduce_49(val, _values, result) + result = CodeNode.new([], val[1]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 131) + def _reduce_50(val, _values, result) + result = CodeNode.new(val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 135) + def _reduce_51(val, _values, result) + result = [] + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 136) + def _reduce_52(val, _values, result) + result = val + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 137) + def _reduce_53(val, _values, result) + result = val[0] << val[2] + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 141) + def _reduce_54(val, _values, result) + result = VariableNode.new(val) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 142) + def _reduce_55(val, _values, result) + result = val[0] << val[2] + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 146) + def _reduce_56(val, _values, result) + result = ObjectNode.new([]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 147) + def _reduce_57(val, _values, result) + result = ObjectNode.new(val[1]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 149) + def _reduce_58(val, _values, result) + result = ObjectNode.new(val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 153) + def _reduce_59(val, _values, result) + result = [] + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 154) + def _reduce_60(val, _values, result) + result = val + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 155) + def _reduce_61(val, _values, result) + result = val[0] << val[2] + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 156) + def _reduce_62(val, _values, result) + result = val[0] << val[2] + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 161) + def _reduce_63(val, _values, result) + result = CallNode.new(val[0], val[2]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 166) + def _reduce_64(val, _values, result) + result = ArrayNode.new(val[1]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 171) + def _reduce_65(val, _values, result) + result = [] + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 172) + def _reduce_66(val, _values, result) + result = val + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 173) + def _reduce_67(val, _values, result) + result = val[0] << val[2] + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 178) + def _reduce_68(val, _values, result) + result = TernaryNode.new(val[1], val[3]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 180) + def _reduce_69(val, _values, result) + result = IfNode.new(val[1], val[3]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 183) + def _reduce_70(val, _values, result) + result = TernaryNode.new(val[1], val[3], val[5]) + result + end +.,., + +module_eval(<<'.,.,', 'grammar.y', 186) + def _reduce_71(val, _values, result) + result = IfNode.new(val[1], val[3], val[6]) + result + end +.,., + +def _reduce_none(val, _values, result) + val[0] +end + +end # class Parser diff --git a/parser_test.rb b/parser_test.rb new file mode 100644 index 0000000000..c383224963 --- /dev/null +++ b/parser_test.rb @@ -0,0 +1,19 @@ +# Recompile the Parser. +# With debugging and verbose: -v -g +`racc -o parser.rb grammar.y` + +# Parse and print "code.jaa". +require "parser.rb" +js = Parser.new.parse(File.read('code.jaa')).compile +puts "\n\n" +puts js + +# Pipe compiled JS through JSLint. +puts "\n\n" +require 'open3' +stdin, stdout, stderr = Open3.popen3('/Users/jashkenas/Library/Application\ Support/TextMate/Bundles/JavaScript\ Tools.tmbundle/Support/bin/jsl -nologo -stdin') +stdin.write(js) +stdin.close +puts stdout.read +stdout.close +stderr.close \ No newline at end of file diff --git a/underscore.jaa b/underscore.jaa new file mode 100644 index 0000000000..e27e271fb0 --- /dev/null +++ b/underscore.jaa @@ -0,0 +1,610 @@ +# Underscore.js +# (c) 2009 Jeremy Ashkenas, DocumentCloud Inc. +# Underscore is freely distributable under the terms of the MIT license. +# Portions of Underscore are inspired by or borrowed from Prototype.js, +# Oliver Steele's Functional, and John Resig's Micro-Templating. +# For all details and documentation: +# http://documentcloud.github.com/underscore/ + +=> + + # ------------------------- Baseline setup --------------------------------- + + # Establish the root object, "window" in the browser, or "global" on the server. + root = this + + # Save the previous value of the "_" variable. + previousUnderscore = root._ + + # If Underscore is called as a function, it returns a wrapped object that + # can be used OO-style. This wrapper holds altered versions of all the + # underscore functions. Wrapped objects may be chained. + wrapper = (obj => this._wrapped = obj) + + # Establish the object that gets thrown to break out of a loop iteration. + breaker = typeof StopIteration !== 'undefined' ? StopIteration : '__break__' + + # Create a safe reference to the Underscore object for reference below. + _ = root._ = obj => new wrapper(obj) + + # Export the Underscore object for CommonJS. + exports._ = _ if typeof exports !== 'undefined' + + # Create quick reference variables for speed access to core prototypes. + slice = Array.prototype.slice + unshift = Array.prototype.unshift + toString = Object.prototype.toString + hasOwnProperty = Object.prototype.hasOwnProperty + propertyIsEnumerable = Object.prototype.propertyIsEnumerable + + # Current version. + _.VERSION = '0.5.1' + + # ------------------------ Collection Functions: --------------------------- + + # The cornerstone, an each implementation. + # Handles objects implementing forEach, arrays, and raw objects. + _.each = obj, iterator, context => + index = 0 + try + return obj.forEach(iterator, context) if obj.forEach + canLoop = _.isArray(obj) or _.isArguments(obj) + return for (i=0, l=obj.length; i + return obj.map(iterator, context) if (obj and _.isFunction(obj.map)) + results = [] + _.each(obj, (value, index, list => + results.push(iterator.call(context, value, index, list)) + )) + results + + # Reduce builds up a single result from a list of values. Also known as + # inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible. + _.reduce = obj, memo, iterator, context => + return obj.reduce(_.bind(iterator, context), memo) if (obj and _.isFunction(obj.reduce)) + _.each(obj, (value, index, list => + memo = iterator.call(context, memo, value, index, list) + )) + memo + + # The right-associative version of reduce, also known as foldr. Uses + # JavaScript 1.8's version of reduceRight, if available. + _.reduceRight = function(obj, memo, iterator, context) { + if (obj && _.isFunction(obj.reduceRight)) return obj.reduceRight(_.bind(iterator, context), memo); + var reversed = _.clone(_.toArray(obj)).reverse(); + _.each(reversed, function(value, index) { + memo = iterator.call(context, memo, value, index, obj); + }); + return memo; + }; + + # Return the first value which passes a truth test. + _.detect = function(obj, iterator, context) { + var result; + _.each(obj, function(value, index, list) { + if (iterator.call(context, value, index, list)) { + result = value; + _.breakLoop(); + } + }); + return result; + }; + + # Return all the elements that pass a truth test. Use JavaScript 1.6's + # filter(), if it exists. + _.select = function(obj, iterator, context) { + if (obj && _.isFunction(obj.filter)) return obj.filter(iterator, context); + var results = []; + _.each(obj, function(value, index, list) { + iterator.call(context, value, index, list) && results.push(value); + }); + return results; + }; + + # Return all the elements for which a truth test fails. + _.reject = function(obj, iterator, context) { + var results = []; + _.each(obj, function(value, index, list) { + !iterator.call(context, value, index, list) && results.push(value); + }); + return results; + }; + + # Determine whether all of the elements match a truth test. Delegate to + # JavaScript 1.6's every(), if it is present. + _.all = function(obj, iterator, context) { + iterator = iterator || _.identity; + if (obj && _.isFunction(obj.every)) return obj.every(iterator, context); + var result = true; + _.each(obj, function(value, index, list) { + if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop(); + }); + return result; + }; + + # Determine if at least one element in the object matches a truth test. Use + # JavaScript 1.6's some(), if it exists. + _.any = function(obj, iterator, context) { + iterator = iterator || _.identity; + if (obj && _.isFunction(obj.some)) return obj.some(iterator, context); + var result = false; + _.each(obj, function(value, index, list) { + if (result = iterator.call(context, value, index, list)) _.breakLoop(); + }); + return result; + }; + + # Determine if a given value is included in the array or object, + # based on '==='. + _.include = function(obj, target) { + if (_.isArray(obj)) return _.indexOf(obj, target) != -1; + var found = false; + _.each(obj, function(value) { + if (found = value === target) _.breakLoop(); + }); + return found; + }; + + # Invoke a method with arguments on every item in a collection. + _.invoke = function(obj, method) { + var args = _.rest(arguments, 2); + return _.map(obj, function(value) { + return (method ? value[method] : value).apply(value, args); + }); + }; + + # Convenience version of a common use case of map: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, function(value){ return value[key]; }); + }; + + # Return the maximum item or (item-based computation). + _.max = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); + var result = {computed : -Infinity}; + _.each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed >= result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + # Return the minimum element (or element-based computation). + _.min = function(obj, iterator, context) { + if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); + var result = {computed : Infinity}; + _.each(obj, function(value, index, list) { + var computed = iterator ? iterator.call(context, value, index, list) : value; + computed < result.computed && (result = {value : value, computed : computed}); + }); + return result.value; + }; + + # Sort the object's values by a criteria produced by an iterator. + _.sortBy = function(obj, iterator, context) { + return _.pluck(_.map(obj, function(value, index, list) { + return { + value : value, + criteria : iterator.call(context, value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }), 'value'); + }; + + # Use a comparator function to figure out at what index an object should + # be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iterator) { + iterator = iterator || _.identity; + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >> 1; + iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; + } + return low; + }; + + # Convert anything iterable into a real, live array. + _.toArray = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + if (_.isArray(iterable)) return iterable; + if (_.isArguments(iterable)) return slice.call(iterable); + return _.map(iterable, function(val){ return val; }); + }; + + # Return the number of elements in an object. + _.size = function(obj) { + return _.toArray(obj).length; + }; + + /*-------------------------- Array Functions: ------------------------------*/ + + # Get the first element of an array. Passing "n" will return the first N + # values in the array. Aliased as "head". The "guard" check allows it to work + # with _.map. + _.first = function(array, n, guard) { + return n && !guard ? slice.call(array, 0, n) : array[0]; + }; + + # Returns everything but the first entry of the array. Aliased as "tail". + # Especially useful on the arguments object. Passing an "index" will return + # the rest of the values in the array from that index onward. The "guard" + //check allows it to work with _.map. + _.rest = function(array, index, guard) { + return slice.call(array, _.isUndefined(index) || guard ? 1 : index); + }; + + # Get the last element of an array. + _.last = function(array) { + return array[array.length - 1]; + }; + + # Trim out all falsy values from an array. + _.compact = function(array) { + return _.select(array, function(value){ return !!value; }); + }; + + # Return a completely flattened version of an array. + _.flatten = function(array) { + return _.reduce(array, [], function(memo, value) { + if (_.isArray(value)) return memo.concat(_.flatten(value)); + memo.push(value); + return memo; + }); + }; + + # Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + var values = _.rest(arguments); + return _.select(array, function(value){ return !_.include(values, value); }); + }; + + # Produce a duplicate-free version of the array. If the array has already + # been sorted, you have the option of using a faster algorithm. + _.uniq = function(array, isSorted) { + return _.reduce(array, [], function(memo, el, i) { + if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo.push(el); + return memo; + }); + }; + + # Produce an array that contains every item shared between all the + # passed-in arrays. + _.intersect = function(array) { + var rest = _.rest(arguments); + return _.select(_.uniq(array), function(item) { + return _.all(rest, function(other) { + return _.indexOf(other, item) >= 0; + }); + }); + }; + + # Zip together multiple lists into a single array -- elements that share + # an index go together. + _.zip = function() { + var args = _.toArray(arguments); + var length = _.max(_.pluck(args, 'length')); + var results = new Array(length); + for (var i=0; i 0 ? i - stop : stop - i) >= 0) return range; + range[idx++] = i; + } + }; + + /* ----------------------- Function Functions: -----------------------------*/ + + # Create a function bound to a given object (assigning 'this', and arguments, + # optionally). Binding with arguments is also known as 'curry'. + _.bind = function(func, obj) { + var args = _.rest(arguments, 2); + return function() { + return func.apply(obj || root, args.concat(_.toArray(arguments))); + }; + }; + + # Bind all of an object's methods to that object. Useful for ensuring that + # all callbacks defined on an object belong to it. + _.bindAll = function(obj) { + var funcs = _.rest(arguments); + if (funcs.length == 0) funcs = _.functions(obj); + _.each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); + return obj; + }; + + # Delays a function for the given number of milliseconds, and then calls + # it with the arguments supplied. + _.delay = function(func, wait) { + var args = _.rest(arguments, 2); + return setTimeout(function(){ return func.apply(func, args); }, wait); + }; + + # Defers a function, scheduling it to run after the current call stack has + # cleared. + _.defer = function(func) { + return _.delay.apply(_, [func, 1].concat(_.rest(arguments))); + }; + + # Returns the first function passed as an argument to the second, + # allowing you to adjust arguments, run code before and after, and + # conditionally execute the original function. + _.wrap = function(func, wrapper) { + return function() { + var args = [func].concat(_.toArray(arguments)); + return wrapper.apply(wrapper, args); + }; + }; + + # Returns a function that is the composition of a list of functions, each + # consuming the return value of the function that follows. + _.compose = function() { + var funcs = _.toArray(arguments); + return function() { + var args = _.toArray(arguments); + for (var i=funcs.length-1; i >= 0; i--) { + args = [funcs[i].apply(this, args)]; + } + return args[0]; + }; + }; + + /* ------------------------- Object Functions: ---------------------------- */ + + # Retrieve the names of an object's properties. + _.keys = function(obj) { + if(_.isArray(obj)) return _.range(0, obj.length); + var keys = []; + for (var key in obj) if (hasOwnProperty.call(obj, key)) keys.push(key); + return keys; + }; + + # Retrieve the values of an object's properties. + _.values = function(obj) { + return _.map(obj, _.identity); + }; + + # Return a sorted list of the function names available in Underscore. + _.functions = function(obj) { + return _.select(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort(); + }; + + # Extend a given object with all of the properties in a source object. + _.extend = function(destination, source) { + for (var property in source) destination[property] = source[property]; + return destination; + }; + + # Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (_.isArray(obj)) return obj.slice(0); + return _.extend({}, obj); + }; + + # Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + # Check object identity. + if (a === b) return true; + # Different types? + var atype = typeof(a), btype = typeof(b); + if (atype != btype) return false; + # Basic equality test (watch out for coercions). + if (a == b) return true; + # One is falsy and the other truthy. + if ((!a && b) || (a && !b)) return false; + # One of them implements an isEqual()? + if (a.isEqual) return a.isEqual(b); + # Check dates' integer values. + if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime(); + # Both are NaN? + if (_.isNaN(a) && _.isNaN(b)) return true; + # Compare regular expressions. + if (_.isRegExp(a) && _.isRegExp(b)) + return a.source === b.source && + a.global === b.global && + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline; + # If a is not an object by this point, we can't handle it. + if (atype !== 'object') return false; + # Check for different array lengths before comparing contents. + if (a.length && (a.length !== b.length)) return false; + # Nothing else worked, deep compare the contents. + var aKeys = _.keys(a), bKeys = _.keys(b); + # Different object sizes? + if (aKeys.length != bKeys.length) return false; + # Recursive comparison of contents. + for (var key in a) if (!_.isEqual(a[key], b[key])) return false; + return true; + }; + + # Is a given array or object empty? + _.isEmpty = function(obj) { + return _.keys(obj).length == 0; + }; + + # Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType == 1); + }; + + # Is a given variable an arguments object? + _.isArguments = function(obj) { + return obj && _.isNumber(obj.length) && !_.isArray(obj) && !propertyIsEnumerable.call(obj, 'length'); + }; + + # Is the given value NaN -- this one is interesting. NaN != NaN, and + # isNaN(undefined) == true, so we make sure it's a number first. + _.isNaN = function(obj) { + return _.isNumber(obj) && isNaN(obj); + }; + + # Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + # Is a given variable undefined? + _.isUndefined = function(obj) { + return typeof obj == 'undefined'; + }; + + # Invokes interceptor with the obj, and then returns obj. + # The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + } + + # Define the isArray, isDate, isFunction, isNumber, isRegExp, and isString + # functions based on their toString identifiers. + var types = ['Array', 'Date', 'Function', 'Number', 'RegExp', 'String']; + for (var i=0, l=types.length; i)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "',$1,'") + .split("\t").join("');") + .split("%>").join("p.push('") + .split("\r").join("\\'") + + "');}return p.join('');"); + return data ? fn(data) : fn; + }; + + /*------------------------------- Aliases ----------------------------------*/ + + _.forEach = _.each; + _.foldl = _.inject = _.reduce; + _.foldr = _.reduceRight; + _.filter = _.select; + _.every = _.all; + _.some = _.any; + _.head = _.first; + _.tail = _.rest; + _.methods = _.functions; + + /*------------------------ Setup the OOP Wrapper: --------------------------*/ + + # Helper function to continue chaining intermediate results. + var result = function(obj, chain) { + return chain ? _(obj).chain() : obj; + }; + + # Add all of the Underscore functions to the wrapper object. + _.each(_.functions(_), function(name) { + var method = _[name]; + wrapper.prototype[name] = function() { + unshift.call(arguments, this._wrapped); + return result(method.apply(_, arguments), this._chain); + }; + }); + + # Add all mutator Array functions to the wrapper. + _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = Array.prototype[name]; + wrapper.prototype[name] = function() { + method.apply(this._wrapped, arguments); + return result(this._wrapped, this._chain); + }; + }); + + # Add all accessor Array functions to the wrapper. + _.each(['concat', 'join', 'slice'], function(name) { + var method = Array.prototype[name]; + wrapper.prototype[name] = function() { + return result(method.apply(this._wrapped, arguments), this._chain); + }; + }); + + # Start chaining a wrapped Underscore object. + wrapper.prototype.chain = function() { + this._chain = true; + return this; + }; + + # Extracts the result from a wrapped and chained object. + wrapper.prototype.value = function() { + return this._wrapped; + }; + +()