Skip to content

Commit

Permalink
more more, including &&=, ||=
Browse files Browse the repository at this point in the history
  • Loading branch information
jashkenas committed Dec 14, 2009
1 parent 91ac495 commit 896440d
Show file tree
Hide file tree
Showing 8 changed files with 844 additions and 4,032 deletions.
7 changes: 5 additions & 2 deletions code.jaa
@@ -1,6 +1,5 @@
# TODO: switch/case statements
# new Function()
# Regexes
# Better block delimiters

# Functions:
square: x => x * x.
Expand Down Expand Up @@ -50,6 +49,10 @@ race: =>
if tired then return sleep().
race().

# Conditional operators:
good ||= evil
wine &&= cheese




138 changes: 66 additions & 72 deletions documents.jaa
@@ -1,78 +1,72 @@
# 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')
# if text then 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(),
# datum => _.any(datum.get('instances'),
# instance => instance.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') + '"'.
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')
if text then 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()
datum => _.any(datum.get('instances')
instance => instance.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: =>
if this.countSelected() <= 1 then return window.open(this.selected()[0].get('pdf_url')).
dc.app.download('/download/' + this.selectedIds().join('/') + '/document_pdfs.zip').

downloadSelectedFullText: =>
if this.countSelected() <= 1 then return window.open(this.selected()[0].get('full_text_url')).
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')
if fire then _.defer(_(this.fire).bind(this, this.SELECTION_CHANGED, this))..

})

# # 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()
# 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()
31 changes: 21 additions & 10 deletions grammar.y
Expand Up @@ -8,8 +8,8 @@ token STRING
token REGEX
token TRUE FALSE NULL
token IDENTIFIER PROPERTY_ACCESS
token CODE
token RETURN
token CODE PARAM
token NEW RETURN

prechigh
nonassoc UMINUS NOT '!'
Expand Down Expand Up @@ -128,27 +128,36 @@ rule
| 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 ||= &&=
| Expression '||=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
| Expression '&&=' Expression { result = OpNode.new(val[1], val[0], val[2]) }
;
# Method definition
Code:
"=>" Expressions "." { result = CodeNode.new([], val[1]) }
| ParamList
"=>" Expressions "." { result = CodeNode.new(val[0], val[2]) }
ParamList "=>" Expression { result = CodeNode.new(val[0], val[2]) }
| ParamList "=>" Expressions "." { result = CodeNode.new(val[0], val[2]) }
;
ParamList:
/* nothing */ { result = [] }
| IDENTIFIER { result = val }
| ParamList "," IDENTIFIER { result = val[0] << val[2] }
| PARAM { result = val }
| ParamList "," PARAM { result = val[0] << val[2] }
;
Variable:
IDENTIFIER { result = VariableNode.new(val) }
| Variable PROPERTY_ACCESS
IDENTIFIER { result = val[0] << val[2] }
| Variable Accessor { result = val[0] << val[1] }
| Call Accessor { result = VariableNode.new(val[0], [val[1]]) }
;
Accessor:
PROPERTY_ACCESS IDENTIFIER { result = AccessorNode.new(val[1]) }
| Index { result = val[0] }
;
Index:
"[" Literal "]" { result = IndexNode.new(val[1]) }
;
Object:
Expand All @@ -169,6 +178,7 @@ rule
# A method call.
Call:
Variable "(" ArgList ")" { result = CallNode.new(val[0], val[2]) }
| NEW Variable "(" ArgList ")" { result = CallNode.new(val[1], val[3], true) }
;
# An Array.
Expand All @@ -181,6 +191,7 @@ rule
/* nothing */ { result = [] }
| Expression { result = val }
| ArgList "," Expression { result = val[0] << val[2] }
| ArgList Terminator Expression { result = val[0] << val[2] }
;
If:
Expand Down
19 changes: 16 additions & 3 deletions lexer.rb
Expand Up @@ -3,11 +3,11 @@ class Lexer
KEYWORDS = ["if", "else", "then",
"true", "false", "null",
"and", "or", "is", "aint", "not",
"return"]
"new", "return"]

IDENTIFIER = /\A([a-zA-Z$_]\w*)/
NUMBER = /\A([0-9]+(\.[0-9]+)?)/
STRING = /\A["'](.*?)["']/
STRING = /\A("(.*?)"|'(.*?)')/
OPERATOR = /\A([+\*&|\/\-%=<>]+)/
WHITESPACE = /\A([ \t\r]+)/
NEWLINE = /\A([\r\n]+)/
Expand Down Expand Up @@ -61,7 +61,7 @@ def number_token
def string_token
return false unless string = @chunk[STRING, 1]
@tokens << [:STRING, string]
@i += string.length + 2
@i += string.length
end

def regex_token
Expand Down Expand Up @@ -91,9 +91,22 @@ def literal_token
return @i += value.length
end
value = @chunk[OPERATOR, 1]
tag_parameters if value && value.match(CODE)
value ||= @chunk[0,1]
@tokens << [value, value]
@i += value.length
end

# The main source of ambiguity in our grammar was Parameter lists (as opposed
# to argument lists in method calls). Tag parameter identifiers to avoid this.
def tag_parameters
index = 0
loop do
tok = @tokens[index -= 1]
next if tok[0] == ','
return if tok[0] != :IDENTIFIER
tok[0] = :PARAM
end
end

end

0 comments on commit 896440d

Please sign in to comment.