refactored operator parsing

This commit is contained in:
satyr
2010-10-26 03:56:02 +09:00
parent 0d6d221568
commit ad79e142ca
8 changed files with 44 additions and 73 deletions

View File

@@ -237,10 +237,10 @@ grammar =
# The general group of accessors into an object, by property, by prototype
# or by array index or slice.
Accessor: [
o 'PROPERTY_ACCESS Identifier', -> new Accessor $2
o 'PROTOTYPE_ACCESS Identifier', -> new Accessor $2, 'prototype'
o '. Identifier', -> new Accessor $2
o ':: Identifier', -> new Accessor $2, 'prototype'
o '::', -> new Accessor new Literal 'prototype'
o 'SOAK_ACCESS Identifier', -> new Accessor $2, 'soak'
o '?. Identifier', -> new Accessor $2, 'soak'
o 'Index'
]
@@ -557,6 +557,7 @@ grammar =
#
# (2 + 3) * 4
operators = [
['left', '.', '?.', '::']
['left', 'CALL_START', 'CALL_END']
['nonassoc', '++', '--']
['left', '?']
@@ -567,7 +568,6 @@ operators = [
['left', 'RELATION']
['left', 'COMPARE']
['left', 'LOGIC']
['left', '.']
['nonassoc', 'INDENT', 'OUTDENT']
['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN']
['right', 'WHEN', 'LEADING_WHEN', 'FORIN', 'FOROF', 'FROM', 'TO', 'BY',

View File

@@ -86,7 +86,8 @@ exports.Lexer = class Lexer
@seenFrom = no
@token 'TO', id
return id.length
forcedIdentifier = colon or @tagAccessor()
forcedIdentifier = colon or
(prev = last @tokens) and not prev.spaced and prev[0] in ['.', '?.', '@', '::']
tag = 'IDENTIFIER'
if id in JS_KEYWORDS or
not forcedIdentifier and id in COFFEE_KEYWORDS
@@ -134,7 +135,6 @@ exports.Lexer = class Lexer
numberToken: ->
return 0 unless match = NUMBER.exec @chunk
number = match[0]
return 0 if @tag() is '.' and number.charAt(0) is '.'
@token 'NUMBER', number
number.length
@@ -240,8 +240,7 @@ exports.Lexer = class Lexer
@line += count indent, '\n'
prev = last @tokens, 1
size = indent.length - 1 - indent.lastIndexOf '\n'
nextCharacter = NEXT_CHARACTER.exec(@chunk)[1]
noNewlines = (nextCharacter in ['.', ','] and not NEXT_ELLIPSIS.test(@chunk)) or @unfinished()
noNewlines = @unfinished()
if size - @indebt is @indent
if noNewlines then @suppressNewlines() else @newlineToken()
return indent.length
@@ -343,23 +342,6 @@ exports.Lexer = class Lexer
# Token Manipulators
# ------------------
# As we consume a new `IDENTIFIER`, look at the previous token to determine
# if it's a special kind of accessor. Return `true` if any type of accessor
# is the previous token.
tagAccessor: ->
return false if not (prev = last @tokens) or prev.spaced
if prev[1] is '::'
@tag 0, 'PROTOTYPE_ACCESS'
else if prev[1] is '.' and @value(1) isnt '.'
if @tag(1) is '?'
@tag 0, 'SOAK_ACCESS'
@tokens.splice -2, 1
else
@tag 0, 'PROPERTY_ACCESS'
else
return prev[0] is '@'
true
# Sanitize a heredoc or herecomment by
# erasing all external indentation on the left-hand side.
sanitizeHeredoc: (doc, options) ->
@@ -490,7 +472,8 @@ exports.Lexer = class Lexer
# Are we in the midst of an unfinished expression?
unfinished: ->
(prev = last @tokens, 1) and prev[0] isnt '.' and
LINE_CONTINUER.test(@chunk) or
(prev = last @tokens, 1) and prev[0] isnt '.' and
(value = @value()) and not value.reserved and
NO_NEWLINE.test(value) and not CODE.test(value) and not ASSIGNED.test(@chunk)
@@ -551,7 +534,16 @@ IDENTIFIER = /// ^
///
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?/i
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[ \t]*)?\1/
OPERATOR = /// ^ (?: -[-=>]? | \+[+=]? | \.{3} | [*&|/%=<>^:!?]+ ) ///
OPERATOR = /// ^
(?: [-=]> # function
| [-+*/%<>&|^!?=]= # compound assign / compare
| >>>=? # zero-fill right shift
| ([-+:])\1 # doubles
| ([&|<>])\2=? # logic / shift
| \?\. # soak access
| \.{3} # splat
)
///
WHITESPACE = /^[ \t]+/
COMMENT = /^###([^#][\s\S]*?)(?:###[ \t]*\n|(?:###)?$)|^(?:\s*#(?!##[^#]).*)+/
CODE = /^[-=]>/
@@ -580,8 +572,7 @@ HEREGEX_OMIT = /\s+(?:#.*)?/g
MULTILINER = /\n/g
HEREDOC_INDENT = /\n+([ \t]*)/g
ASSIGNED = /^\s*@?[$A-Za-z_][$\w]*[ \t]*?[:=][^:=>]/
NEXT_CHARACTER = /^\s*(\S?)/
NEXT_ELLIPSIS = /^\s*\.{3}/
LINE_CONTINUER = /// ^ \s* (?: , | \??\.(?!\.) | :: ) ///
LEADING_SPACES = /^\s+/
TRAILING_SPACES = /\s+$/
NO_NEWLINE = /// ^

View File

@@ -178,7 +178,7 @@ class exports.Rewriter
return yes if not seenSingle and token.fromThen
[tag] = token
seenSingle = yes if tag in ['IF', 'ELSE', 'UNLESS', '->', '=>']
return yes if tag is 'PROPERTY_ACCESS' and @tag(i - 1) is 'OUTDENT'
return yes if tag in ['.', '?.', '::'] and @tag(i - 1) is 'OUTDENT'
not token.generated and @tag(i - 1) isnt ',' and tag in IMPLICIT_END and
(tag isnt 'INDENT' or
(@tag(i - 2) isnt 'CLASS' and @tag(i - 1) not in IMPLICIT_BLOCK and