mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
got about as far as I think I can with operator nodes for now, without zach's optimizations
This commit is contained in:
parent
9339058fc3
commit
76dac9c09c
5 changed files with 223 additions and 122 deletions
|
@ -1,5 +1,5 @@
|
||||||
(function(){
|
(function(){
|
||||||
var AccessorNode, ArrayNode, AssignNode, CallNode, ClosureNode, CodeNode, CommentNode, Expressions, ExtendsNode, IndexNode, LiteralNode, Node, ObjectNode, OpNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThisNode, ValueNode, WhileNode, any, compact, del, dup, flatten, inherit, merge, statement;
|
var AccessorNode, ArrayNode, AssignNode, CallNode, ClosureNode, CodeNode, CommentNode, Expressions, ExtendsNode, IDENTIFIER, IndexNode, LiteralNode, Node, ObjectNode, OpNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThisNode, ValueNode, WhileNode, any, compact, del, dup, flatten, inherit, merge, statement;
|
||||||
var __hasProp = Object.prototype.hasOwnProperty;
|
var __hasProp = Object.prototype.hasOwnProperty;
|
||||||
process.mixin(require('./scope'));
|
process.mixin(require('./scope'));
|
||||||
// The abstract base class for all CoffeeScript nodes.
|
// The abstract base class for all CoffeeScript nodes.
|
||||||
|
@ -151,6 +151,8 @@
|
||||||
// Tabs are two spaces for pretty printing.
|
// Tabs are two spaces for pretty printing.
|
||||||
TAB = ' ';
|
TAB = ' ';
|
||||||
TRAILING_WHITESPACE = /\s+$/g;
|
TRAILING_WHITESPACE = /\s+$/g;
|
||||||
|
// Keep the identifier regex in sync with the Lexer.
|
||||||
|
IDENTIFIER = /^[a-zA-Z$_](\w|\$)*$/;
|
||||||
// Flatten nested arrays recursively.
|
// Flatten nested arrays recursively.
|
||||||
flatten = function flatten(list) {
|
flatten = function flatten(list) {
|
||||||
var __a, __b, item, memo;
|
var __a, __b, item, memo;
|
||||||
|
@ -842,8 +844,6 @@
|
||||||
});
|
});
|
||||||
// Setting the value of a local variable, or the value of an object property.
|
// Setting the value of a local variable, or the value of an object property.
|
||||||
AssignNode = (exports.AssignNode = inherit(Node, {
|
AssignNode = (exports.AssignNode = inherit(Node, {
|
||||||
// Keep the identifier regex in sync with the Lexer.
|
|
||||||
IDENTIFIER: /^([a-zA-Z$_](\w|\$)*)/,
|
|
||||||
PROTO_ASSIGN: /^(\S+)\.prototype/,
|
PROTO_ASSIGN: /^(\S+)\.prototype/,
|
||||||
LEADING_DOT: /^\.(prototype\.)?/,
|
LEADING_DOT: /^\.(prototype\.)?/,
|
||||||
constructor: function constructor(variable, value, context) {
|
constructor: function constructor(variable, value, context) {
|
||||||
|
@ -875,7 +875,7 @@
|
||||||
match = name.match(this.PROTO_ASSIGN);
|
match = name.match(this.PROTO_ASSIGN);
|
||||||
proto = match && match[1];
|
proto = match && match[1];
|
||||||
if (this.value instanceof CodeNode) {
|
if (this.value instanceof CodeNode) {
|
||||||
if (last.match(this.IDENTIFIER)) {
|
if (last.match(IDENTIFIER)) {
|
||||||
this.value.name = last;
|
this.value.name = last;
|
||||||
}
|
}
|
||||||
if (proto) {
|
if (proto) {
|
||||||
|
@ -1058,9 +1058,60 @@
|
||||||
return this.CHAINABLE.indexOf(this.operator) >= 0;
|
return this.CHAINABLE.indexOf(this.operator) >= 0;
|
||||||
},
|
},
|
||||||
compile_node: function compile_node(o) {
|
compile_node: function compile_node(o) {
|
||||||
if (this.is_chainable() && (this.first.unwrap() instanceof OpNode) && this.first.unwrap().is_chainable()) {
|
if (this.is_chainable() && this.first.unwrap() instanceof OpNode && this.first.unwrap().is_chainable()) {
|
||||||
return this.compile_chain(o);
|
return this.compile_chain(o);
|
||||||
}
|
}
|
||||||
|
if (this.ASSIGNMENT.indexOf(this.operator) >= 0) {
|
||||||
|
return this.compile_assignment(o);
|
||||||
|
}
|
||||||
|
if (this.is_unary()) {
|
||||||
|
return this.compile_unary(o);
|
||||||
|
}
|
||||||
|
if (this.operator === '?') {
|
||||||
|
return this.compile_existence(o);
|
||||||
|
}
|
||||||
|
return this.first.compile(o) + ' ' + this.operator + ' ' + this.second.compile(o);
|
||||||
|
},
|
||||||
|
// Mimic Python's chained comparisons. See:
|
||||||
|
// http://docs.python.org/reference/expressions.html#notin
|
||||||
|
compile_chain: function compile_chain(o) {
|
||||||
|
var __a, shared;
|
||||||
|
shared = this.first.unwrap().second;
|
||||||
|
if (shared instanceof CallNode) {
|
||||||
|
__a = shared.compile_reference(o);
|
||||||
|
this.first.second = __a[0];
|
||||||
|
shared = __a[1];
|
||||||
|
}
|
||||||
|
return '(' + this.first.compile(o) + ') && (' + shared.compile(o) + ' ' + this.operator + ' ' + this.second.compile(o) + ')';
|
||||||
|
},
|
||||||
|
compile_assignment: function compile_assignment(o) {
|
||||||
|
var __a, first, second;
|
||||||
|
__a = [this.first.compile(o), this.second.compile(o)];
|
||||||
|
first = __a[0];
|
||||||
|
second = __a[1];
|
||||||
|
if (this.first.unwrap.match(IDENTIFIER)) {
|
||||||
|
o.scope.find(first);
|
||||||
|
}
|
||||||
|
if (this.operator === '?=') {
|
||||||
|
return first + ' = ' + ExistenceNode.compile_test(o, this.first) + ' ? ' + first + ' : ' + second;
|
||||||
|
}
|
||||||
|
return first + ' = ' + first + ' ' + this.operator.substr(0, 2) + ' ' + second;
|
||||||
|
},
|
||||||
|
compile_existence: function compile_existence(o) {
|
||||||
|
var __a, first, second;
|
||||||
|
__a = [this.first.compile(o), this.second.compile(o)];
|
||||||
|
first = __a[0];
|
||||||
|
second = __a[1];
|
||||||
|
return ExistenceNode.compile_test(o, this.first) + ' ? ' + first + ' : ' + second;
|
||||||
|
},
|
||||||
|
compile_unary: function compile_unary(o) {
|
||||||
|
var parts, space;
|
||||||
|
space = this.PREFIX_OPERATORS.indexOf(this.operator) >= 0 ? ' ' : '';
|
||||||
|
parts = [this.operator, space, this.first.compile(o)];
|
||||||
|
if (this.flip) {
|
||||||
|
parts = parts.reverse();
|
||||||
|
}
|
||||||
|
return parts.join('');
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
})();
|
})();
|
|
@ -783,9 +783,8 @@ module CoffeeScript
|
||||||
def compile_assignment(o)
|
def compile_assignment(o)
|
||||||
first, second = @first.compile(o), @second.compile(o)
|
first, second = @first.compile(o), @second.compile(o)
|
||||||
o[:scope].find(first) if @first.unwrap.is_a?(Value)
|
o[:scope].find(first) if @first.unwrap.is_a?(Value)
|
||||||
sym = @operator[0..1]
|
|
||||||
return "#{first} = #{ExistenceNode.compile_test(o, @first)} ? #{first} : #{second}" if @operator == '?='
|
return "#{first} = #{ExistenceNode.compile_test(o, @first)} ? #{first} : #{second}" if @operator == '?='
|
||||||
"#{first} = #{first} #{sym} #{second}"
|
"#{first} = #{first} #{@operator[0..1]} #{second}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def compile_existence(o)
|
def compile_existence(o)
|
||||||
|
|
|
@ -7,17 +7,17 @@
|
||||||
// Detect functions: [
|
// Detect functions: [
|
||||||
unwrap = /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;
|
unwrap = /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;
|
||||||
// Quickie DSL for Jison access.
|
// Quickie DSL for Jison access.
|
||||||
o = function o(pattern_string, func) {
|
o = function o(pattern_string, func, options) {
|
||||||
var match;
|
var match;
|
||||||
if (func) {
|
if (func) {
|
||||||
func = (match = (func + "").match(unwrap)) ? match[1] : '(' + func + '())';
|
func = (match = (func + "").match(unwrap)) ? match[1] : '(' + func + '())';
|
||||||
return [pattern_string, '$$ = ' + func + ';'];
|
return [pattern_string, '$$ = ' + func + ';', options];
|
||||||
} else {
|
} else {
|
||||||
return [pattern_string, '$$ = $1;'];
|
return [pattern_string, '$$ = $1;', options];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Precedence ===========================================================
|
// Precedence ===========================================================
|
||||||
operators = [["left", '?'], ["right", 'NOT', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["right", '==', '!=', 'IS', 'ISNT'], ["left", '&&', '||', 'AND', 'OR'], ["right", '-=', '+=', '/=', '*=', '%='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY'], ["right", 'THROW', 'FOR', 'NEW', 'SUPER'], ["left", 'EXTENDS'], ["left", '||=', '&&=', '?='], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'IF', 'ELSE', 'WHILE']];
|
operators = [["left", '?'], ["right", 'UMINUS', 'UPLUS', 'NOT', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["right", '==', '!=', 'IS', 'ISNT'], ["left", '&&', '||', 'AND', 'OR'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY'], ["right", 'THROW', 'FOR', 'NEW', 'SUPER'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'IF', 'ELSE', 'WHILE']];
|
||||||
// Grammar ==============================================================
|
// Grammar ==============================================================
|
||||||
grammar = {
|
grammar = {
|
||||||
// All parsing will end in this rule, being the trunk of the AST.
|
// All parsing will end in this rule, being the trunk of the AST.
|
||||||
|
@ -106,67 +106,92 @@
|
||||||
return new CommentNode(yytext);
|
return new CommentNode(yytext);
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
//
|
// Arithmetic and logical operators
|
||||||
// # Arithmetic and logical operators
|
// For Ruby's Operator precedence, see: [
|
||||||
// # For Ruby's Operator precedence, see: [
|
// https://www.cs.auckland.ac.nz/references/ruby/ProgrammingRuby/language.html
|
||||||
// # https://www.cs.auckland.ac.nz/references/ruby/ProgrammingRuby/language.html
|
Operation: [o("! Expression", function() {
|
||||||
// Operation: [
|
return new OpNode('!', $2);
|
||||||
// o "! Expression", -> new OpNode($1, $2)
|
}), o("!! Expression", function() {
|
||||||
// o "!! Expression", -> new OpNode($1, $2)
|
return new OpNode('!!', $2);
|
||||||
// o "- Expression", -> new OpNode($1, $2)
|
}), o("- Expression", (function() {
|
||||||
// o "+ Expression", -> new OpNode($1, $2)
|
return new OpNode('-', $2);
|
||||||
// o "NOT Expression", -> new OpNode($1, $2)
|
}), {
|
||||||
// o "~ Expression", -> new OpNode($1, $2)
|
prec: 'UMINUS'
|
||||||
// o "-- Expression", -> new OpNode($1, $2)
|
}), o("+ Expression", (function() {
|
||||||
// o "++ Expression", -> new OpNode($1, $2)
|
return new OpNode('+', $2);
|
||||||
// o "DELETE Expression", -> new OpNode($1, $2)
|
}), {
|
||||||
// o "TYPEOF Expression", -> new OpNode($1, $2)
|
prec: 'UPLUS'
|
||||||
// o "Expression --", -> new OpNode($2, $1, null, true)
|
}), o("NOT Expression", function() {
|
||||||
// o "Expression ++", -> new OpNode($2, $1, null, true)
|
return new OpNode('not', $2);
|
||||||
//
|
}), o("~ Expression", function() {
|
||||||
// o "Expression * Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('~', $2);
|
||||||
// o "Expression / Expression", -> new OpNode($2, $1, $3)
|
}), o("-- Expression", function() {
|
||||||
// o "Expression % Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('--', $2);
|
||||||
//
|
}), o("++ Expression", function() {
|
||||||
// o "Expression + Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('++', $2);
|
||||||
// o "Expression - Expression", -> new OpNode($2, $1, $3)
|
}), o("DELETE Expression", function() {
|
||||||
//
|
return new OpNode('delete', $2);
|
||||||
// o "Expression << Expression", -> new OpNode($2, $1, $3)
|
}), o("TYPEOF Expression", function() {
|
||||||
// o "Expression >> Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('typeof', $2);
|
||||||
// o "Expression >>> Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression --", function() {
|
||||||
//
|
return new OpNode('--', $1, null, true);
|
||||||
// o "Expression & Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression ++", function() {
|
||||||
// o "Expression | Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('++', $1, null, true);
|
||||||
// o "Expression ^ Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression * Expression", function() {
|
||||||
//
|
return new OpNode('*', $1, $3);
|
||||||
// o "Expression <= Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression / Expression", function() {
|
||||||
// o "Expression < Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('/', $1, $3);
|
||||||
// o "Expression > Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression % Expression", function() {
|
||||||
// o "Expression >= Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('%', $1, $3);
|
||||||
//
|
}), o("Expression + Expression", function() {
|
||||||
// o "Expression == Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('+', $1, $3);
|
||||||
// o "Expression != Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression - Expression", function() {
|
||||||
// o "Expression IS Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('-', $1, $3);
|
||||||
// o "Expression ISNT Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression << Expression", function() {
|
||||||
//
|
return new OpNode('<<', $1, $3);
|
||||||
// o "Expression && Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression >> Expression", function() {
|
||||||
// o "Expression || Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('>>', $1, $3);
|
||||||
// o "Expression AND Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression >>> Expression", function() {
|
||||||
// o "Expression OR Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('>>>', $1, $3);
|
||||||
// o "Expression ? Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression & Expression", function() {
|
||||||
//
|
return new OpNode('&', $1, $3);
|
||||||
// o "Expression -= Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression | Expression", function() {
|
||||||
// o "Expression += Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('|', $1, $3);
|
||||||
// o "Expression /= Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression ^ Expression", function() {
|
||||||
// o "Expression *= Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('^', $1, $3);
|
||||||
// o "Expression %= Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression <= Expression", function() {
|
||||||
// o "Expression ||= Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('<=', $1, $3);
|
||||||
// o "Expression &&= Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression < Expression", function() {
|
||||||
// o "Expression ?= Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('<', $1, $3);
|
||||||
//
|
}), o("Expression > Expression", function() {
|
||||||
// o "Expression INSTANCEOF Expression", -> new OpNode($2, $1, $3)
|
return new OpNode('>', $1, $3);
|
||||||
// o "Expression IN Expression", -> new OpNode($2, $1, $3)
|
}), o("Expression >= Expression", function() {
|
||||||
// ]
|
return new OpNode('>=', $1, $3);
|
||||||
|
}), o("Expression == Expression", function() {
|
||||||
|
return new OpNode('==', $1, $3);
|
||||||
|
}),
|
||||||
|
// o "Expression != Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression IS Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression ISNT Expression", -> new OpNode($2, $1, $3)
|
||||||
|
//
|
||||||
|
// o "Expression && Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression || Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression AND Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression OR Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression ? Expression", -> new OpNode($2, $1, $3)
|
||||||
|
//
|
||||||
|
// o "Expression -= Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression += Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression /= Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression *= Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression %= Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression ||= Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression &&= Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression ?= Expression", -> new OpNode($2, $1, $3)
|
||||||
|
//
|
||||||
|
// o "Expression INSTANCEOF Expression", -> new OpNode($2, $1, $3)
|
||||||
|
// o "Expression IN Expression", -> new OpNode($2, $1, $3)
|
||||||
|
],
|
||||||
// The existence operator.
|
// The existence operator.
|
||||||
Existence: [o("Expression ?", function() {
|
Existence: [o("Expression ?", function() {
|
||||||
return new ExistenceNode($1);
|
return new ExistenceNode($1);
|
||||||
|
|
|
@ -44,6 +44,9 @@ exports.Expressions.wrap : (values) -> @values: values
|
||||||
TAB: ' '
|
TAB: ' '
|
||||||
TRAILING_WHITESPACE: /\s+$/g
|
TRAILING_WHITESPACE: /\s+$/g
|
||||||
|
|
||||||
|
# Keep the identifier regex in sync with the Lexer.
|
||||||
|
IDENTIFIER: /^[a-zA-Z$_](\w|\$)*$/
|
||||||
|
|
||||||
# Flatten nested arrays recursively.
|
# Flatten nested arrays recursively.
|
||||||
flatten: (list) ->
|
flatten: (list) ->
|
||||||
memo: []
|
memo: []
|
||||||
|
@ -587,8 +590,6 @@ ClosureNode: exports.ClosureNode: {
|
||||||
# Setting the value of a local variable, or the value of an object property.
|
# Setting the value of a local variable, or the value of an object property.
|
||||||
AssignNode: exports.AssignNode: inherit Node, {
|
AssignNode: exports.AssignNode: inherit Node, {
|
||||||
|
|
||||||
# Keep the identifier regex in sync with the Lexer.
|
|
||||||
IDENTIFIER: /^([a-zA-Z$_](\w|\$)*)/
|
|
||||||
PROTO_ASSIGN: /^(\S+)\.prototype/
|
PROTO_ASSIGN: /^(\S+)\.prototype/
|
||||||
LEADING_DOT: /^\.(prototype\.)?/
|
LEADING_DOT: /^\.(prototype\.)?/
|
||||||
|
|
||||||
|
@ -616,7 +617,7 @@ AssignNode: exports.AssignNode: inherit Node, {
|
||||||
match: name.match(@PROTO_ASSIGN)
|
match: name.match(@PROTO_ASSIGN)
|
||||||
proto: match and match[1]
|
proto: match and match[1]
|
||||||
if @value instanceof CodeNode
|
if @value instanceof CodeNode
|
||||||
@value.name: last if last.match(@IDENTIFIER)
|
@value.name: last if last.match(IDENTIFIER)
|
||||||
@value.proto: proto if proto
|
@value.proto: proto if proto
|
||||||
return name + ': ' + @value.compile(o) if @context is 'object'
|
return name + ': ' + @value.compile(o) if @context is 'object'
|
||||||
o.scope.find(name) unless @is_value() and @variable.has_properties()
|
o.scope.find(name) unless @is_value() and @variable.has_properties()
|
||||||
|
@ -773,8 +774,34 @@ OpNode: exports.OpNode: inherit Node, {
|
||||||
@CHAINABLE.indexOf(@operator) >= 0
|
@CHAINABLE.indexOf(@operator) >= 0
|
||||||
|
|
||||||
compile_node: (o) ->
|
compile_node: (o) ->
|
||||||
return @compile_chain(o) if @is_chainable() and (@first.unwrap() instanceof OpNode) and @first.unwrap().is_chainable()
|
return @compile_chain(o) if @is_chainable() and @first.unwrap() instanceof OpNode and @first.unwrap().is_chainable()
|
||||||
|
return @compile_assignment(o) if @ASSIGNMENT.indexOf(@operator) >= 0
|
||||||
|
return @compile_unary(o) if @is_unary()
|
||||||
|
return @compile_existence(o) if @operator is '?'
|
||||||
|
@first.compile(o) + ' ' + @operator + ' ' + @second.compile(o)
|
||||||
|
|
||||||
|
# Mimic Python's chained comparisons. See:
|
||||||
|
# http://docs.python.org/reference/expressions.html#notin
|
||||||
|
compile_chain: (o) ->
|
||||||
|
shared: @first.unwrap().second
|
||||||
|
[@first.second, shared]: shared.compile_reference(o) if shared instanceof CallNode
|
||||||
|
'(' + @first.compile(o) + ') && (' + shared.compile(o) + ' ' + @operator + ' ' + @second.compile(o) + ')'
|
||||||
|
|
||||||
|
compile_assignment: (o) ->
|
||||||
|
[first, second]: [@first.compile(o), @second.compile(o)]
|
||||||
|
o.scope.find(first) if @first.unwrap.match(IDENTIFIER)
|
||||||
|
return first + ' = ' + ExistenceNode.compile_test(o, @first) + ' ? ' + first + ' : ' + second if @operator is '?='
|
||||||
|
first + ' = ' + first + ' ' + @operator.substr(0, 2) + ' ' + second
|
||||||
|
|
||||||
|
compile_existence: (o) ->
|
||||||
|
[first, second]: [@first.compile(o), @second.compile(o)]
|
||||||
|
ExistenceNode.compile_test(o, @first) + ' ? ' + first + ' : ' + second
|
||||||
|
|
||||||
|
compile_unary: (o) ->
|
||||||
|
space: if @PREFIX_OPERATORS.indexOf(@operator) >= 0 then ' ' else ''
|
||||||
|
parts: [@operator, space, @first.compile(o)]
|
||||||
|
parts: parts.reverse() if @flip
|
||||||
|
parts.join('')
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,18 +7,18 @@ process.mixin require './nodes'
|
||||||
unwrap: /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/
|
unwrap: /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/
|
||||||
|
|
||||||
# Quickie DSL for Jison access.
|
# Quickie DSL for Jison access.
|
||||||
o: (pattern_string, func) ->
|
o: (pattern_string, func, options) ->
|
||||||
if func
|
if func
|
||||||
func: if match: (func + "").match(unwrap) then match[1] else '(' + func + '())'
|
func: if match: (func + "").match(unwrap) then match[1] else '(' + func + '())'
|
||||||
[pattern_string, '$$ = ' + func + ';']
|
[pattern_string, '$$ = ' + func + ';', options]
|
||||||
else
|
else
|
||||||
[pattern_string, '$$ = $1;']
|
[pattern_string, '$$ = $1;', options]
|
||||||
|
|
||||||
# Precedence ===========================================================
|
# Precedence ===========================================================
|
||||||
|
|
||||||
operators: [
|
operators: [
|
||||||
["left", '?']
|
["left", '?']
|
||||||
["right", 'NOT', '!', '!!', '~', '++', '--']
|
["right", 'UMINUS', 'UPLUS', 'NOT', '!', '!!', '~', '++', '--']
|
||||||
["left", '*', '/', '%']
|
["left", '*', '/', '%']
|
||||||
["left", '+', '-']
|
["left", '+', '-']
|
||||||
["left", '<<', '>>', '>>>']
|
["left", '<<', '>>', '>>>']
|
||||||
|
@ -27,14 +27,13 @@ operators: [
|
||||||
["right", 'DELETE', 'INSTANCEOF', 'TYPEOF']
|
["right", 'DELETE', 'INSTANCEOF', 'TYPEOF']
|
||||||
["right", '==', '!=', 'IS', 'ISNT']
|
["right", '==', '!=', 'IS', 'ISNT']
|
||||||
["left", '&&', '||', 'AND', 'OR']
|
["left", '&&', '||', 'AND', 'OR']
|
||||||
["right", '-=', '+=', '/=', '*=', '%=']
|
["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=']
|
||||||
["left", '.']
|
["left", '.']
|
||||||
["right", 'INDENT']
|
["right", 'INDENT']
|
||||||
["left", 'OUTDENT']
|
["left", 'OUTDENT']
|
||||||
["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY']
|
["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY']
|
||||||
["right", 'THROW', 'FOR', 'NEW', 'SUPER']
|
["right", 'THROW', 'FOR', 'NEW', 'SUPER']
|
||||||
["left", 'EXTENDS']
|
["left", 'EXTENDS']
|
||||||
["left", '||=', '&&=', '?=']
|
|
||||||
["right", 'ASSIGN', 'RETURN']
|
["right", 'ASSIGN', 'RETURN']
|
||||||
["right", '->', '=>', 'UNLESS', 'IF', 'ELSE', 'WHILE']
|
["right", '->', '=>', 'UNLESS', 'IF', 'ELSE', 'WHILE']
|
||||||
]
|
]
|
||||||
|
@ -133,45 +132,45 @@ grammar: {
|
||||||
Comment: [
|
Comment: [
|
||||||
o "COMMENT", -> new CommentNode(yytext)
|
o "COMMENT", -> new CommentNode(yytext)
|
||||||
]
|
]
|
||||||
#
|
|
||||||
# # Arithmetic and logical operators
|
# Arithmetic and logical operators
|
||||||
# # For Ruby's Operator precedence, see: [
|
# For Ruby's Operator precedence, see: [
|
||||||
# # https://www.cs.auckland.ac.nz/references/ruby/ProgrammingRuby/language.html
|
# https://www.cs.auckland.ac.nz/references/ruby/ProgrammingRuby/language.html
|
||||||
# Operation: [
|
Operation: [
|
||||||
# o "! Expression", -> new OpNode($1, $2)
|
o "! Expression", -> new OpNode('!', $2)
|
||||||
# o "!! Expression", -> new OpNode($1, $2)
|
o "!! Expression", -> new OpNode('!!', $2)
|
||||||
# o "- Expression", -> new OpNode($1, $2)
|
o "- Expression", (-> new OpNode('-', $2)), {prec: 'UMINUS'}
|
||||||
# o "+ Expression", -> new OpNode($1, $2)
|
o "+ Expression", (-> new OpNode('+', $2)), {prec: 'UPLUS'}
|
||||||
# o "NOT Expression", -> new OpNode($1, $2)
|
o "NOT Expression", -> new OpNode('not', $2)
|
||||||
# o "~ Expression", -> new OpNode($1, $2)
|
o "~ Expression", -> new OpNode('~', $2)
|
||||||
# o "-- Expression", -> new OpNode($1, $2)
|
o "-- Expression", -> new OpNode('--', $2)
|
||||||
# o "++ Expression", -> new OpNode($1, $2)
|
o "++ Expression", -> new OpNode('++', $2)
|
||||||
# o "DELETE Expression", -> new OpNode($1, $2)
|
o "DELETE Expression", -> new OpNode('delete', $2)
|
||||||
# o "TYPEOF Expression", -> new OpNode($1, $2)
|
o "TYPEOF Expression", -> new OpNode('typeof', $2)
|
||||||
# o "Expression --", -> new OpNode($2, $1, null, true)
|
o "Expression --", -> new OpNode('--', $1, null, true)
|
||||||
# o "Expression ++", -> new OpNode($2, $1, null, true)
|
o "Expression ++", -> new OpNode('++', $1, null, true)
|
||||||
#
|
|
||||||
# o "Expression * Expression", -> new OpNode($2, $1, $3)
|
o "Expression * Expression", -> new OpNode('*', $1, $3)
|
||||||
# o "Expression / Expression", -> new OpNode($2, $1, $3)
|
o "Expression / Expression", -> new OpNode('/', $1, $3)
|
||||||
# o "Expression % Expression", -> new OpNode($2, $1, $3)
|
o "Expression % Expression", -> new OpNode('%', $1, $3)
|
||||||
#
|
|
||||||
# o "Expression + Expression", -> new OpNode($2, $1, $3)
|
o "Expression + Expression", -> new OpNode('+', $1, $3)
|
||||||
# o "Expression - Expression", -> new OpNode($2, $1, $3)
|
o "Expression - Expression", -> new OpNode('-', $1, $3)
|
||||||
#
|
|
||||||
# o "Expression << Expression", -> new OpNode($2, $1, $3)
|
o "Expression << Expression", -> new OpNode('<<', $1, $3)
|
||||||
# o "Expression >> Expression", -> new OpNode($2, $1, $3)
|
o "Expression >> Expression", -> new OpNode('>>', $1, $3)
|
||||||
# o "Expression >>> Expression", -> new OpNode($2, $1, $3)
|
o "Expression >>> Expression", -> new OpNode('>>>', $1, $3)
|
||||||
#
|
|
||||||
# o "Expression & Expression", -> new OpNode($2, $1, $3)
|
o "Expression & Expression", -> new OpNode('&', $1, $3)
|
||||||
# o "Expression | Expression", -> new OpNode($2, $1, $3)
|
o "Expression | Expression", -> new OpNode('|', $1, $3)
|
||||||
# o "Expression ^ Expression", -> new OpNode($2, $1, $3)
|
o "Expression ^ Expression", -> new OpNode('^', $1, $3)
|
||||||
#
|
|
||||||
# o "Expression <= Expression", -> new OpNode($2, $1, $3)
|
o "Expression <= Expression", -> new OpNode('<=', $1, $3)
|
||||||
# o "Expression < Expression", -> new OpNode($2, $1, $3)
|
o "Expression < Expression", -> new OpNode('<', $1, $3)
|
||||||
# o "Expression > Expression", -> new OpNode($2, $1, $3)
|
o "Expression > Expression", -> new OpNode('>', $1, $3)
|
||||||
# o "Expression >= Expression", -> new OpNode($2, $1, $3)
|
o "Expression >= Expression", -> new OpNode('>=', $1, $3)
|
||||||
#
|
|
||||||
# o "Expression == Expression", -> new OpNode($2, $1, $3)
|
o "Expression == Expression", -> new OpNode('==', $1, $3)
|
||||||
# o "Expression != Expression", -> new OpNode($2, $1, $3)
|
# o "Expression != Expression", -> new OpNode($2, $1, $3)
|
||||||
# o "Expression IS Expression", -> new OpNode($2, $1, $3)
|
# o "Expression IS Expression", -> new OpNode($2, $1, $3)
|
||||||
# o "Expression ISNT Expression", -> new OpNode($2, $1, $3)
|
# o "Expression ISNT Expression", -> new OpNode($2, $1, $3)
|
||||||
|
@ -193,7 +192,7 @@ grammar: {
|
||||||
#
|
#
|
||||||
# o "Expression INSTANCEOF Expression", -> new OpNode($2, $1, $3)
|
# o "Expression INSTANCEOF Expression", -> new OpNode($2, $1, $3)
|
||||||
# o "Expression IN Expression", -> new OpNode($2, $1, $3)
|
# o "Expression IN Expression", -> new OpNode($2, $1, $3)
|
||||||
# ]
|
]
|
||||||
|
|
||||||
# The existence operator.
|
# The existence operator.
|
||||||
Existence: [
|
Existence: [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue