removed YES/NO/ON/OFF from rewriter/parser

This commit is contained in:
satyr
2010-10-08 00:56:01 +09:00
parent 9447796d8e
commit 4f486bc444
7 changed files with 260 additions and 284 deletions

View File

@@ -68,14 +68,8 @@
return new Literal(true); return new Literal(true);
}), o("FALSE", function() { }), o("FALSE", function() {
return new Literal(false); return new Literal(false);
}), o("YES", function() { }), o("NULL", function() {
return new Literal(true); return new Literal('null');
}), o("NO", function() {
return new Literal(false);
}), o("ON", function() {
return new Literal(true);
}), o("OFF", function() {
return new Literal(false);
}) })
], ],
Assign: [ Assign: [
@@ -178,9 +172,7 @@
return new Value($1); return new Value($1);
}), o("Range", function() { }), o("Range", function() {
return new Value($1); return new Value($1);
}), o("This"), o("NULL", function() { }), o("This")
return new Value(new Literal('null'));
})
], ],
Accessor: [ Accessor: [
o("PROPERTY_ACCESS Identifier", function() { o("PROPERTY_ACCESS Identifier", function() {

View File

@@ -577,13 +577,17 @@
return Lexer; return Lexer;
})(); })();
JS_KEYWORDS = ['if', 'else', 'true', 'false', 'new', 'return', 'try', 'catch', 'finally', 'throw', 'break', 'continue', 'for', 'in', 'while', 'delete', 'instanceof', 'typeof', 'switch', 'super', 'extends', 'class', 'this', 'null', 'debugger']; JS_KEYWORDS = ['if', 'else', 'true', 'false', 'new', 'return', 'try', 'catch', 'finally', 'throw', 'break', 'continue', 'for', 'in', 'while', 'delete', 'instanceof', 'typeof', 'switch', 'super', 'extends', 'class', 'this', 'null', 'debugger'];
COFFEE_KEYWORDS = ['then', 'unless', 'until', 'loop', 'yes', 'no', 'on', 'off', 'of', 'by', 'when']; COFFEE_KEYWORDS = ['then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
for (op in (COFFEE_ALIASES = { for (op in (COFFEE_ALIASES = {
and: '&&', and: '&&',
or: '||', or: '||',
is: '==', is: '==',
isnt: '!=', isnt: '!=',
not: '!' not: '!',
yes: 'TRUE',
no: 'FALSE',
on: 'TRUE',
off: 'FALSE'
})) { })) {
COFFEE_KEYWORDS.push(op); COFFEE_KEYWORDS.push(op);
} }

File diff suppressed because one or more lines are too long

View File

@@ -146,27 +146,28 @@
return this.tokens.splice(i, 0, ['}', '}', token[2]]); return this.tokens.splice(i, 0, ['}', '}', token[2]]);
}; };
return this.scanTokens(function(token, i, tokens) { return this.scanTokens(function(token, i, tokens) {
var idx, last, tag, tok; var idx, tag, tok;
if (include(EXPRESSION_START, tag = token[0])) { if (include(EXPRESSION_START, tag = token[0])) {
stack.push(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag); stack.push(tag === 'INDENT' && this.tag(i - 1) === '{' ? '{' : tag);
return 1;
} }
if (include(EXPRESSION_END, tag)) { if (include(EXPRESSION_END, tag)) {
stack.pop(); stack.pop();
return 1;
} }
last = stack[stack.length - 1]; if (!(tag === ':' && stack[stack.length - 1] !== '{')) {
if (tag === ':' && !(last && last[0] === '{')) { return 1;
stack.push('{');
idx = this.tag(i - 2) === '@' ? i - 2 : i - 1;
if (this.tag(idx - 2) === 'HERECOMMENT') {
idx -= 2;
}
tok = ['{', '{', token[2]];
tok.generated = true;
tokens.splice(idx, 0, tok);
this.detectEnd(i + 2, condition, action);
return 2;
} }
return 1; stack.push('{');
idx = this.tag(i - 2) === '@' ? i - 2 : i - 1;
if (this.tag(idx - 2) === 'HERECOMMENT') {
idx -= 2;
}
tok = ['{', '{', token[2]];
tok.generated = true;
tokens.splice(idx, 0, tok);
this.detectEnd(i + 2, condition, action);
return 2;
}); });
}; };
exports.Rewriter.prototype.addImplicitParentheses = function() { exports.Rewriter.prototype.addImplicitParentheses = function() {
@@ -178,18 +179,14 @@
return this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]); return this.tokens.splice(idx, 0, ['CALL_END', ')', token[2]]);
}; };
return this.scanTokens(function(token, i, tokens) { return this.scanTokens(function(token, i, tokens) {
var _ref, callObject, condition, idx, next, prev, seenSingle, tag; var callObject, next, prev, seenSingle, tag;
tag = token[0]; tag = token[0];
if (tag === 'CLASS') { if (tag === 'CLASS') {
classLine = true; classLine = true;
} }
prev = tokens[i - 1]; prev = tokens[i - 1];
next = tokens[i + 1]; next = tokens[i + 1];
idx = 1;
callObject = !classLine && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && include(IMPLICIT_FUNC, prev[0]); callObject = !classLine && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && include(IMPLICIT_FUNC, prev[0]);
if (callObject) {
idx = 2;
}
seenSingle = false; seenSingle = false;
if (include(LINEBREAKS, tag)) { if (include(LINEBREAKS, tag)) {
classLine = false; classLine = false;
@@ -197,29 +194,28 @@
if (prev && !prev.spaced && tag === '?') { if (prev && !prev.spaced && tag === '?') {
token.call = true; token.call = true;
} }
if (callObject || prev && prev.spaced && (prev.call || include(IMPLICIT_FUNC, prev[0])) && include(IMPLICIT_CALL, tag) && !(tag === 'UNARY' && ('IN' === (_ref = this.tag(i + 1)) || 'OF' === _ref || 'INSTANCEOF' === _ref))) { if (!(callObject || ((prev != null) ? prev.spaced : undefined) && (prev.call || include(IMPLICIT_FUNC, prev[0])) && include(IMPLICIT_CALL, tag))) {
tokens.splice(i, 0, ['CALL_START', '(', token[2]]); return 1;
condition = function(token, i) {
var post;
if (!seenSingle && token.fromThen) {
return true;
}
tag = token[0];
if (('IF' === tag || 'ELSE' === tag || 'UNLESS' === tag || '->' === tag || '=>' === tag)) {
seenSingle = true;
}
if (tag === 'PROPERTY_ACCESS' && this.tag(i - 1) === 'OUTDENT') {
return true;
}
return !token.generated && this.tag(i - 1) !== ',' && include(IMPLICIT_END, tag) && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && !include(IMPLICIT_BLOCK, this.tag(i - 1)) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
};
this.detectEnd(i + idx, condition, action);
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
return 2;
} }
return 1; tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
this.detectEnd(i + (callObject ? 2 : 1), function(token, i) {
var post;
if (!seenSingle && token.fromThen) {
return true;
}
tag = token[0];
if (('IF' === tag || 'ELSE' === tag || 'UNLESS' === tag || '->' === tag || '=>' === tag)) {
seenSingle = true;
}
if (tag === 'PROPERTY_ACCESS' && this.tag(i - 1) === 'OUTDENT') {
return true;
}
return !token.generated && this.tag(i - 1) !== ',' && include(IMPLICIT_END, tag) && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && !include(IMPLICIT_BLOCK, this.tag(i - 1)) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
}, action);
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
}
return 2;
}); });
}; };
exports.Rewriter.prototype.addImplicitIndentation = function() { exports.Rewriter.prototype.addImplicitIndentation = function() {
@@ -369,7 +365,7 @@
} }
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END); EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS']; IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'NULL', 'UNARY', 'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '@', '->', '=>', '[', '(', '{']; IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'NULL', 'UNARY', 'TRUE', 'FALSE', '@', '->', '=>', '[', '(', '{'];
IMPLICIT_BLOCK = ['->', '=>', '{', '[', ',']; IMPLICIT_BLOCK = ['->', '=>', '{', '[', ','];
IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'TERMINATOR', 'INDENT']; IMPLICIT_END = ['POST_IF', 'POST_UNLESS', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'TERMINATOR', 'INDENT'];
SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN']; SINGLE_LINERS = ['ELSE', '->', '=>', 'TRY', 'FINALLY', 'THEN'];

View File

@@ -132,10 +132,7 @@ grammar =
o "REGEX", -> new Literal $1 o "REGEX", -> new Literal $1
o "TRUE", -> new Literal true o "TRUE", -> new Literal true
o "FALSE", -> new Literal false o "FALSE", -> new Literal false
o "YES", -> new Literal true o "NULL", -> new Literal 'null'
o "NO", -> new Literal false
o "ON", -> new Literal true
o "OFF", -> new Literal false
] ]
# Assignment of a variable, property, or index to a value. # Assignment of a variable, property, or index to a value.
@@ -238,7 +235,6 @@ grammar =
o "Parenthetical", -> new Value $1 o "Parenthetical", -> new Value $1
o "Range", -> new Value $1 o "Range", -> new Value $1
o "This" o "This"
o "NULL", -> new Value new Literal 'null'
] ]
# The general group of accessors into an object, by property, by prototype # The general group of accessors into an object, by property, by prototype

View File

@@ -518,17 +518,17 @@ JS_KEYWORDS = [
] ]
# CoffeeScript-only keywords. # CoffeeScript-only keywords.
COFFEE_KEYWORDS = [ COFFEE_KEYWORDS = ['then', 'unless', 'until', 'loop', 'of', 'by', 'when']
'then', 'unless', 'until', 'loop'
'yes', 'no', 'on', 'off'
'of', 'by', 'when'
]
COFFEE_KEYWORDS.push op for all op of COFFEE_ALIASES = COFFEE_KEYWORDS.push op for all op of COFFEE_ALIASES =
and : '&&' and : '&&'
or : '||' or : '||'
is : '==' is : '=='
isnt : '!=' isnt : '!='
not : '!' not : '!'
yes : 'TRUE'
no : 'FALSE'
on : 'TRUE'
off : 'FALSE'
COFFEE_ALIASES['==='] = '==' COFFEE_ALIASES['==='] = '=='
# The list of keywords that are reserved by JavaScript, but not used, or are # The list of keywords that are reserved by JavaScript, but not used, or are

View File

@@ -132,20 +132,20 @@ class exports.Rewriter
action = (token, i) -> @tokens.splice i, 0, ['}', '}', token[2]] action = (token, i) -> @tokens.splice i, 0, ['}', '}', token[2]]
@scanTokens (token, i, tokens) -> @scanTokens (token, i, tokens) ->
if include EXPRESSION_START, tag = token[0] if include EXPRESSION_START, tag = token[0]
stack.push(if tag is 'INDENT' and @tag(i - 1) is '{' then '{' else tag) stack.push if tag is 'INDENT' and @tag(i - 1) is '{' then '{' else tag
return 1
if include EXPRESSION_END, tag if include EXPRESSION_END, tag
stack.pop() stack.pop()
last = stack[stack.length - 1] return 1
if tag is ':' and not (last and last[0] is '{') return 1 unless tag is ':' and stack[stack.length - 1] isnt '{'
stack.push '{' stack.push '{'
idx = if @tag(i - 2) is '@' then i - 2 else i - 1 idx = if @tag(i - 2) is '@' then i - 2 else i - 1
idx -= 2 if @tag(idx - 2) is 'HERECOMMENT' idx -= 2 if @tag(idx - 2) is 'HERECOMMENT'
tok = ['{', '{', token[2]] tok = ['{', '{', token[2]]
tok.generated = yes tok.generated = yes
tokens.splice idx, 0, tok tokens.splice idx, 0, tok
@detectEnd i + 2, condition, action @detectEnd i + 2, condition, action
return 2 2
1
# Methods may be optionally called without parentheses, for simple cases. # Methods may be optionally called without parentheses, for simple cases.
# Insert the implicit parentheses here, so that the parser doesn't have to # Insert the implicit parentheses here, so that the parser doesn't have to
@@ -160,31 +160,28 @@ class exports.Rewriter
classLine = yes if tag is 'CLASS' classLine = yes if tag is 'CLASS'
prev = tokens[i - 1] prev = tokens[i - 1]
next = tokens[i + 1] next = tokens[i + 1]
idx = 1
callObject = not classLine and tag is 'INDENT' and callObject = not classLine and tag is 'INDENT' and
next and next.generated and next[0] is '{' and next and next.generated and next[0] is '{' and
prev and include(IMPLICIT_FUNC, prev[0]) prev and include(IMPLICIT_FUNC, prev[0])
idx = 2 if callObject
seenSingle = no seenSingle = no
classLine = no if include LINEBREAKS, tag classLine = no if include LINEBREAKS, tag
token.call = yes if prev and not prev.spaced and tag is '?' token.call = yes if prev and not prev.spaced and tag is '?'
if callObject or return 1 unless callObject or
prev and prev.spaced and (prev.call or include(IMPLICIT_FUNC, prev[0])) and include(IMPLICIT_CALL, tag) and prev?.spaced and (prev.call or include(IMPLICIT_FUNC, prev[0])) and
not (tag is 'UNARY' and @tag(i + 1) in ['IN', 'OF', 'INSTANCEOF']) include(IMPLICIT_CALL, tag)
tokens.splice i, 0, ['CALL_START', '(', token[2]] tokens.splice i, 0, ['CALL_START', '(', token[2]]
condition = (token, i) -> @detectEnd i + (if callObject then 2 else 1), (token, i) ->
return yes if not seenSingle and token.fromThen return yes if not seenSingle and token.fromThen
[tag] = token [tag] = token
seenSingle = yes if tag in ['IF', 'ELSE', 'UNLESS', '->', '=>'] 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 is 'PROPERTY_ACCESS' and @tag(i - 1) is 'OUTDENT'
not token.generated and @tag(i - 1) isnt ',' and include(IMPLICIT_END, tag) and not token.generated and @tag(i - 1) isnt ',' and include(IMPLICIT_END, tag) and
(tag isnt 'INDENT' or (tag isnt 'INDENT' or
(@tag(i - 2) isnt 'CLASS' and not include(IMPLICIT_BLOCK, @tag(i - 1)) and (@tag(i - 2) isnt 'CLASS' and not include(IMPLICIT_BLOCK, @tag(i - 1)) and
not ((post = @tokens[i + 1]) and post.generated and post[0] is '{'))) not ((post = @tokens[i + 1]) and post.generated and post[0] is '{')))
@detectEnd i + idx, condition, action , action
prev[0] = 'FUNC_EXIST' if prev[0] is '?' prev[0] = 'FUNC_EXIST' if prev[0] is '?'
return 2 2
1
# Because our grammar is LALR(1), it can't handle some single-line # Because our grammar is LALR(1), it can't handle some single-line
# expressions that lack ending delimiters. The **Rewriter** adds the implicit # expressions that lack ending delimiters. The **Rewriter** adds the implicit
@@ -331,8 +328,7 @@ IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@
# If preceded by an `IMPLICIT_FUNC`, indicates a function invocation. # If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL = [ IMPLICIT_CALL = [
'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS' 'IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS'
'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'NULL', 'UNARY' 'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'NULL', 'UNARY', 'TRUE', 'FALSE'
'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF'
'@', '->', '=>', '[', '(', '{' '@', '->', '=>', '[', '(', '{'
] ]