mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-02-19 03:44:23 -05:00
added children macro to Node, using it so that all nodes now have a 'children' method -- used for safe references to 'this' within closure wrappers
This commit is contained in:
@@ -16,6 +16,7 @@ token ARGUMENTS
|
|||||||
token NEWLINE
|
token NEWLINE
|
||||||
token COMMENT
|
token COMMENT
|
||||||
token JS
|
token JS
|
||||||
|
token THIS
|
||||||
token INDENT OUTDENT
|
token INDENT OUTDENT
|
||||||
|
|
||||||
# Declare order of operations.
|
# Declare order of operations.
|
||||||
@@ -102,12 +103,12 @@ rule
|
|||||||
| BREAK { result = LiteralNode.new(val[0]) }
|
| BREAK { result = LiteralNode.new(val[0]) }
|
||||||
| CONTINUE { result = LiteralNode.new(val[0]) }
|
| CONTINUE { result = LiteralNode.new(val[0]) }
|
||||||
| ARGUMENTS { result = LiteralNode.new(val[0]) }
|
| ARGUMENTS { result = LiteralNode.new(val[0]) }
|
||||||
| TRUE { result = LiteralNode.new(true) }
|
| TRUE { result = LiteralNode.new(Value.new(true)) }
|
||||||
| FALSE { result = LiteralNode.new(false) }
|
| FALSE { result = LiteralNode.new(Value.new(false)) }
|
||||||
| YES { result = LiteralNode.new(true) }
|
| YES { result = LiteralNode.new(Value.new(true)) }
|
||||||
| NO { result = LiteralNode.new(false) }
|
| NO { result = LiteralNode.new(Value.new(false)) }
|
||||||
| ON { result = LiteralNode.new(true) }
|
| ON { result = LiteralNode.new(Value.new(true)) }
|
||||||
| OFF { result = LiteralNode.new(false) }
|
| OFF { result = LiteralNode.new(Value.new(false)) }
|
||||||
;
|
;
|
||||||
|
|
||||||
# Assignment to a variable (or index).
|
# Assignment to a variable (or index).
|
||||||
@@ -235,6 +236,7 @@ rule
|
|||||||
| Range { result = ValueNode.new(val[0]) }
|
| Range { result = ValueNode.new(val[0]) }
|
||||||
| Value Accessor { result = val[0] << val[1] }
|
| Value Accessor { result = val[0] << val[1] }
|
||||||
| Invocation Accessor { result = ValueNode.new(val[0], [val[1]]) }
|
| Invocation Accessor { result = ValueNode.new(val[0], [val[1]]) }
|
||||||
|
| THIS { result = ValueNode.new(ThisNode.new) }
|
||||||
;
|
;
|
||||||
|
|
||||||
# Accessing into an object or array, through dot or index notation.
|
# Accessing into an object or array, through dot or index notation.
|
||||||
|
|||||||
@@ -13,10 +13,11 @@ module CoffeeScript
|
|||||||
"try", "catch", "finally", "throw",
|
"try", "catch", "finally", "throw",
|
||||||
"break", "continue",
|
"break", "continue",
|
||||||
"for", "in", "of", "by", "where", "while",
|
"for", "in", "of", "by", "where", "while",
|
||||||
|
"delete", "instanceof", "typeof",
|
||||||
"switch", "when",
|
"switch", "when",
|
||||||
"super", "extends",
|
"super", "extends",
|
||||||
"arguments",
|
"arguments",
|
||||||
"delete", "instanceof", "typeof"]
|
"this"]
|
||||||
|
|
||||||
# Token matching regexes.
|
# Token matching regexes.
|
||||||
IDENTIFIER = /\A([a-zA-Z$_](\w|\$)*)/
|
IDENTIFIER = /\A([a-zA-Z$_](\w|\$)*)/
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ module CoffeeScript
|
|||||||
class_eval "def statement_only?; true; end"
|
class_eval "def statement_only?; true; end"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Provide a quick implementation of a children method.
|
||||||
|
def self.children(*attributes)
|
||||||
|
attr_reader *attributes
|
||||||
|
attrs = attributes.map {|a| "[@#{a}]" }.join(', ')
|
||||||
|
class_eval "def children; [#{attrs}].flatten.compact; end"
|
||||||
|
end
|
||||||
|
|
||||||
def write(code)
|
def write(code)
|
||||||
puts "#{self.class.to_s}:\n#{@options.inspect}\n#{code}\n\n" if ENV['VERBOSE']
|
puts "#{self.class.to_s}:\n#{@options.inspect}\n#{code}\n\n" if ENV['VERBOSE']
|
||||||
code
|
code
|
||||||
@@ -42,9 +49,11 @@ module CoffeeScript
|
|||||||
end
|
end
|
||||||
|
|
||||||
def compile_closure(o={})
|
def compile_closure(o={})
|
||||||
indent = o[:indent]
|
indent = o[:indent]
|
||||||
@indent = (o[:indent] = idt(1))
|
@indent = (o[:indent] = idt(1))
|
||||||
"(function() {\n#{compile_node(o.merge(:return => true))}\n#{indent}})()"
|
pass_this = !o[:closure] && contains? {|node| node.is_a?(ThisNode) }
|
||||||
|
param = pass_this ? '__this' : ''
|
||||||
|
"(function(#{param}) {\n#{compile_node(o.merge(:return => true, :closure => true))}\n#{indent}})(#{pass_this ? 'this' : ''})"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Quick short method for the current indentation level, plus tabbing in.
|
# Quick short method for the current indentation level, plus tabbing in.
|
||||||
@@ -52,6 +61,20 @@ module CoffeeScript
|
|||||||
@indent + (TAB * tabs)
|
@indent + (TAB * tabs)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Does this node, or any of it's children, contain a node of a certain kind?
|
||||||
|
def contains?(&block)
|
||||||
|
children.each do |node|
|
||||||
|
return true if yield(node)
|
||||||
|
node.is_a?(Node) && node.contains?(&block)
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# All Nodes must implement a "children" method that returns child nodes.
|
||||||
|
def children
|
||||||
|
raise NotImplementedError, "#{self.class} is missing a 'children' method"
|
||||||
|
end
|
||||||
|
|
||||||
# Default implementations of the common node methods.
|
# Default implementations of the common node methods.
|
||||||
def unwrap; self; end
|
def unwrap; self; end
|
||||||
def statement?; false; end
|
def statement?; false; end
|
||||||
@@ -62,7 +85,7 @@ module CoffeeScript
|
|||||||
# A collection of nodes, each one representing an expression.
|
# A collection of nodes, each one representing an expression.
|
||||||
class Expressions < Node
|
class Expressions < Node
|
||||||
statement
|
statement
|
||||||
attr_reader :expressions
|
children :expressions
|
||||||
|
|
||||||
TRAILING_WHITESPACE = /\s+$/
|
TRAILING_WHITESPACE = /\s+$/
|
||||||
UPPERCASE = /[A-Z]/
|
UPPERCASE = /[A-Z]/
|
||||||
@@ -156,6 +179,7 @@ module CoffeeScript
|
|||||||
# Literals are static values that have a Ruby representation, eg.: a string, a number,
|
# Literals are static values that have a Ruby representation, eg.: a string, a number,
|
||||||
# true, false, nil, etc.
|
# true, false, nil, etc.
|
||||||
class LiteralNode < Node
|
class LiteralNode < Node
|
||||||
|
children :value
|
||||||
|
|
||||||
# Values of a literal node that much be treated as a statement -- no
|
# Values of a literal node that much be treated as a statement -- no
|
||||||
# sense returning or assigning them.
|
# sense returning or assigning them.
|
||||||
@@ -165,8 +189,6 @@ module CoffeeScript
|
|||||||
# it to an array.
|
# it to an array.
|
||||||
ARG_ARRAY = 'Array.prototype.slice.call(arguments, 0)'
|
ARG_ARRAY = 'Array.prototype.slice.call(arguments, 0)'
|
||||||
|
|
||||||
attr_reader :value
|
|
||||||
|
|
||||||
# Wrap up a compiler-generated string as a LiteralNode.
|
# Wrap up a compiler-generated string as a LiteralNode.
|
||||||
def self.wrap(string)
|
def self.wrap(string)
|
||||||
self.new(Value.new(string))
|
self.new(Value.new(string))
|
||||||
@@ -192,8 +214,7 @@ module CoffeeScript
|
|||||||
# Return an expression, or wrap it in a closure and return it.
|
# Return an expression, or wrap it in a closure and return it.
|
||||||
class ReturnNode < Node
|
class ReturnNode < Node
|
||||||
statement_only
|
statement_only
|
||||||
|
children :expression
|
||||||
attr_reader :expression
|
|
||||||
|
|
||||||
def initialize(expression)
|
def initialize(expression)
|
||||||
@expression = expression
|
@expression = expression
|
||||||
@@ -225,7 +246,7 @@ module CoffeeScript
|
|||||||
# Node for a function invocation. Takes care of converting super() calls into
|
# Node for a function invocation. Takes care of converting super() calls into
|
||||||
# calls against the prototype's function of the same name.
|
# calls against the prototype's function of the same name.
|
||||||
class CallNode < Node
|
class CallNode < Node
|
||||||
attr_reader :variable, :arguments
|
children :variable, :arguments
|
||||||
|
|
||||||
def initialize(variable, arguments=[])
|
def initialize(variable, arguments=[])
|
||||||
@variable, @arguments = variable, arguments
|
@variable, @arguments = variable, arguments
|
||||||
@@ -285,8 +306,8 @@ module CoffeeScript
|
|||||||
# Node to extend an object's prototype with an ancestor object.
|
# Node to extend an object's prototype with an ancestor object.
|
||||||
# After goog.inherits from the Closure Library.
|
# After goog.inherits from the Closure Library.
|
||||||
class ExtendsNode < Node
|
class ExtendsNode < Node
|
||||||
|
children :sub_object, :super_object
|
||||||
statement
|
statement
|
||||||
attr_reader :sub_object, :super_object
|
|
||||||
|
|
||||||
def initialize(sub_object, super_object)
|
def initialize(sub_object, super_object)
|
||||||
@sub_object, @super_object = sub_object, super_object
|
@sub_object, @super_object = sub_object, super_object
|
||||||
@@ -307,7 +328,8 @@ module CoffeeScript
|
|||||||
|
|
||||||
# A value, indexed or dotted into, or vanilla.
|
# A value, indexed or dotted into, or vanilla.
|
||||||
class ValueNode < Node
|
class ValueNode < Node
|
||||||
attr_reader :base, :properties, :last, :source
|
children :base, :properties
|
||||||
|
attr_reader :last, :source
|
||||||
|
|
||||||
def initialize(base, properties=[])
|
def initialize(base, properties=[])
|
||||||
@base, @properties = base, properties
|
@base, @properties = base, properties
|
||||||
@@ -352,7 +374,7 @@ module CoffeeScript
|
|||||||
# A dotted accessor into a part of a value, or the :: shorthand for
|
# A dotted accessor into a part of a value, or the :: shorthand for
|
||||||
# an accessor into the object's prototype.
|
# an accessor into the object's prototype.
|
||||||
class AccessorNode < Node
|
class AccessorNode < Node
|
||||||
attr_reader :name
|
children :name
|
||||||
|
|
||||||
def initialize(name, prototype=false)
|
def initialize(name, prototype=false)
|
||||||
@name, @prototype = name, prototype
|
@name, @prototype = name, prototype
|
||||||
@@ -366,7 +388,7 @@ module CoffeeScript
|
|||||||
|
|
||||||
# An indexed accessor into a part of an array or object.
|
# An indexed accessor into a part of an array or object.
|
||||||
class IndexNode < Node
|
class IndexNode < Node
|
||||||
attr_reader :index
|
children :index
|
||||||
|
|
||||||
def initialize(index)
|
def initialize(index)
|
||||||
@index = index
|
@index = index
|
||||||
@@ -377,10 +399,20 @@ module CoffeeScript
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A node to represent a reference to "this". Needs to be transformed into a
|
||||||
|
# reference to the correct value of "this", when used within a closure wrapper.
|
||||||
|
class ThisNode < Node
|
||||||
|
|
||||||
|
def compile_node(o)
|
||||||
|
write(o[:closure] ? "__this" : "this")
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
# A range literal. Ranges can be used to extract portions (slices) of arrays,
|
# A range literal. Ranges can be used to extract portions (slices) of arrays,
|
||||||
# or to specify a range for array comprehensions.
|
# or to specify a range for array comprehensions.
|
||||||
class RangeNode < Node
|
class RangeNode < Node
|
||||||
attr_reader :from, :to
|
children :from, :to
|
||||||
|
|
||||||
def initialize(from, to, exclusive=false)
|
def initialize(from, to, exclusive=false)
|
||||||
@from, @to, @exclusive = from, to, exclusive
|
@from, @to, @exclusive = from, to, exclusive
|
||||||
@@ -423,7 +455,7 @@ module CoffeeScript
|
|||||||
# specifies the index of the end of the slice (just like the first parameter)
|
# specifies the index of the end of the slice (just like the first parameter)
|
||||||
# is the index of the beginning.
|
# is the index of the beginning.
|
||||||
class SliceNode < Node
|
class SliceNode < Node
|
||||||
attr_reader :range
|
children :range
|
||||||
|
|
||||||
def initialize(range)
|
def initialize(range)
|
||||||
@range = range
|
@range = range
|
||||||
@@ -439,11 +471,11 @@ module CoffeeScript
|
|||||||
|
|
||||||
# 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.
|
||||||
class AssignNode < Node
|
class AssignNode < Node
|
||||||
|
children :variable, :value
|
||||||
|
|
||||||
PROTO_ASSIGN = /\A(\S+)\.prototype/
|
PROTO_ASSIGN = /\A(\S+)\.prototype/
|
||||||
LEADING_DOT = /\A\.(prototype\.)?/
|
LEADING_DOT = /\A\.(prototype\.)?/
|
||||||
|
|
||||||
attr_reader :variable, :value, :context
|
|
||||||
|
|
||||||
def initialize(variable, value, context=nil)
|
def initialize(variable, value, context=nil)
|
||||||
@variable, @value, @context = variable, value, context
|
@variable, @value, @context = variable, value, context
|
||||||
end
|
end
|
||||||
@@ -505,6 +537,9 @@ module CoffeeScript
|
|||||||
# Simple Arithmetic and logical operations. Performs some conversion from
|
# Simple Arithmetic and logical operations. Performs some conversion from
|
||||||
# CoffeeScript operations into their JavaScript equivalents.
|
# CoffeeScript operations into their JavaScript equivalents.
|
||||||
class OpNode < Node
|
class OpNode < Node
|
||||||
|
children :first, :second
|
||||||
|
attr_reader :operator
|
||||||
|
|
||||||
CONVERSIONS = {
|
CONVERSIONS = {
|
||||||
:== => "===",
|
:== => "===",
|
||||||
:'!=' => "!==",
|
:'!=' => "!==",
|
||||||
@@ -517,8 +552,6 @@ module CoffeeScript
|
|||||||
CONDITIONALS = [:'||=', :'&&=']
|
CONDITIONALS = [:'||=', :'&&=']
|
||||||
PREFIX_OPERATORS = [:typeof, :delete]
|
PREFIX_OPERATORS = [:typeof, :delete]
|
||||||
|
|
||||||
attr_reader :operator, :first, :second
|
|
||||||
|
|
||||||
def initialize(operator, first, second=nil, flip=false)
|
def initialize(operator, first, second=nil, flip=false)
|
||||||
@first, @second, @flip = first, second, flip
|
@first, @second, @flip = first, second, flip
|
||||||
@operator = CONVERSIONS[operator.to_sym] || operator
|
@operator = CONVERSIONS[operator.to_sym] || operator
|
||||||
@@ -550,7 +583,8 @@ module CoffeeScript
|
|||||||
|
|
||||||
# A function definition. The only node that creates a new Scope.
|
# A function definition. The only node that creates a new Scope.
|
||||||
class CodeNode < Node
|
class CodeNode < Node
|
||||||
attr_reader :params, :body, :bound
|
children :params, :body
|
||||||
|
attr_reader :bound
|
||||||
|
|
||||||
def initialize(params, body, tag=nil)
|
def initialize(params, body, tag=nil)
|
||||||
@params = params
|
@params = params
|
||||||
@@ -566,6 +600,7 @@ module CoffeeScript
|
|||||||
o[:indent] = idt(@bound ? 2 : 1)
|
o[:indent] = idt(@bound ? 2 : 1)
|
||||||
o.delete(:no_wrap)
|
o.delete(:no_wrap)
|
||||||
o.delete(:globals)
|
o.delete(:globals)
|
||||||
|
o.delete(:closure)
|
||||||
name = o.delete(:immediate_assign)
|
name = o.delete(:immediate_assign)
|
||||||
if @params.last.is_a?(SplatNode)
|
if @params.last.is_a?(SplatNode)
|
||||||
splat = @params.pop
|
splat = @params.pop
|
||||||
@@ -584,8 +619,8 @@ module CoffeeScript
|
|||||||
# A splat, either as a parameter to a function, an argument to a call,
|
# A splat, either as a parameter to a function, an argument to a call,
|
||||||
# or in a destructuring assignment.
|
# or in a destructuring assignment.
|
||||||
class SplatNode < Node
|
class SplatNode < Node
|
||||||
|
children :name
|
||||||
attr_accessor :index
|
attr_accessor :index
|
||||||
attr_reader :name
|
|
||||||
|
|
||||||
def initialize(name)
|
def initialize(name)
|
||||||
@name = name
|
@name = name
|
||||||
@@ -612,7 +647,7 @@ module CoffeeScript
|
|||||||
|
|
||||||
# An object literal.
|
# An object literal.
|
||||||
class ObjectNode < Node
|
class ObjectNode < Node
|
||||||
attr_reader :properties
|
children :properties
|
||||||
alias_method :objects, :properties
|
alias_method :objects, :properties
|
||||||
|
|
||||||
def initialize(properties = [])
|
def initialize(properties = [])
|
||||||
@@ -639,7 +674,7 @@ module CoffeeScript
|
|||||||
|
|
||||||
# An array literal.
|
# An array literal.
|
||||||
class ArrayNode < Node
|
class ArrayNode < Node
|
||||||
attr_reader :objects
|
children :objects
|
||||||
|
|
||||||
def initialize(objects=[])
|
def initialize(objects=[])
|
||||||
@objects = objects
|
@objects = objects
|
||||||
@@ -672,10 +707,9 @@ module CoffeeScript
|
|||||||
# A while loop, the only sort of low-level loop exposed by CoffeeScript. From
|
# A while loop, the only sort of low-level loop exposed by CoffeeScript. From
|
||||||
# it, all other loops can be manufactured.
|
# it, all other loops can be manufactured.
|
||||||
class WhileNode < Node
|
class WhileNode < Node
|
||||||
|
children :condition, :body
|
||||||
statement
|
statement
|
||||||
|
|
||||||
attr_reader :condition, :body
|
|
||||||
|
|
||||||
def initialize(condition, body)
|
def initialize(condition, body)
|
||||||
@condition, @body = condition, body
|
@condition, @body = condition, body
|
||||||
end
|
end
|
||||||
@@ -707,10 +741,10 @@ module CoffeeScript
|
|||||||
# of the comprehenion. Unlike Python array comprehensions, it's able to pass
|
# of the comprehenion. Unlike Python array comprehensions, it's able to pass
|
||||||
# the current index of the loop as a second parameter.
|
# the current index of the loop as a second parameter.
|
||||||
class ForNode < Node
|
class ForNode < Node
|
||||||
|
children :body, :source, :filter
|
||||||
|
attr_reader :name, :index, :step
|
||||||
statement
|
statement
|
||||||
|
|
||||||
attr_reader :body, :source, :name, :index, :filter, :step
|
|
||||||
|
|
||||||
def initialize(body, source, name, index=nil)
|
def initialize(body, source, name, index=nil)
|
||||||
@body, @name, @index = body, name, index
|
@body, @name, @index = body, name, index
|
||||||
@source = source[:source]
|
@source = source[:source]
|
||||||
@@ -780,10 +814,10 @@ module CoffeeScript
|
|||||||
|
|
||||||
# A try/catch/finally block.
|
# A try/catch/finally block.
|
||||||
class TryNode < Node
|
class TryNode < Node
|
||||||
|
children :try, :recovery, :finally
|
||||||
|
attr_reader :error
|
||||||
statement
|
statement
|
||||||
|
|
||||||
attr_reader :try, :error, :recovery, :finally
|
|
||||||
|
|
||||||
def initialize(try, error, recovery, finally=nil)
|
def initialize(try, error, recovery, finally=nil)
|
||||||
@try, @error, @recovery, @finally = try, error, recovery, finally
|
@try, @error, @recovery, @finally = try, error, recovery, finally
|
||||||
end
|
end
|
||||||
@@ -800,10 +834,9 @@ module CoffeeScript
|
|||||||
|
|
||||||
# Throw an exception.
|
# Throw an exception.
|
||||||
class ThrowNode < Node
|
class ThrowNode < Node
|
||||||
|
children :expression
|
||||||
statement_only
|
statement_only
|
||||||
|
|
||||||
attr_reader :expression
|
|
||||||
|
|
||||||
def initialize(expression)
|
def initialize(expression)
|
||||||
@expression = expression
|
@expression = expression
|
||||||
end
|
end
|
||||||
@@ -815,7 +848,7 @@ module CoffeeScript
|
|||||||
|
|
||||||
# Check an expression for existence (meaning not null or undefined).
|
# Check an expression for existence (meaning not null or undefined).
|
||||||
class ExistenceNode < Node
|
class ExistenceNode < Node
|
||||||
attr_reader :expression
|
children :expression
|
||||||
|
|
||||||
def initialize(expression)
|
def initialize(expression)
|
||||||
@expression = expression
|
@expression = expression
|
||||||
@@ -831,7 +864,7 @@ module CoffeeScript
|
|||||||
# You can't wrap parentheses around bits that get compiled into JS statements,
|
# You can't wrap parentheses around bits that get compiled into JS statements,
|
||||||
# unfortunately.
|
# unfortunately.
|
||||||
class ParentheticalNode < Node
|
class ParentheticalNode < Node
|
||||||
attr_reader :expressions
|
children :expressions
|
||||||
|
|
||||||
def initialize(expressions, line=nil)
|
def initialize(expressions, line=nil)
|
||||||
@expressions = expressions.unwrap
|
@expressions = expressions.unwrap
|
||||||
@@ -850,7 +883,7 @@ module CoffeeScript
|
|||||||
# Single-expression IfNodes are compiled into ternary operators if possible,
|
# Single-expression IfNodes are compiled into ternary operators if possible,
|
||||||
# because ternaries are first-class returnable assignable expressions.
|
# because ternaries are first-class returnable assignable expressions.
|
||||||
class IfNode < Node
|
class IfNode < Node
|
||||||
attr_reader :condition, :body, :else_body
|
children :condition, :body, :else_body
|
||||||
|
|
||||||
def initialize(condition, body, else_body=nil, tags={})
|
def initialize(condition, body, else_body=nil, tags={})
|
||||||
@condition = condition
|
@condition = condition
|
||||||
|
|||||||
@@ -45,6 +45,10 @@ module CoffeeScript
|
|||||||
def match(regex)
|
def match(regex)
|
||||||
@value.match(regex)
|
@value.match(regex)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def children
|
||||||
|
[]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
20
test/fixtures/execution/test_functions.coffee
vendored
20
test/fixtures/execution/test_functions.coffee
vendored
@@ -19,4 +19,22 @@ obj: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
obj.unbound()
|
obj.unbound()
|
||||||
obj.bound()
|
obj.bound()
|
||||||
|
|
||||||
|
|
||||||
|
# When when a closure wrapper is generated for expression conversion, make sure
|
||||||
|
# that references to "this" within the wrapper are safely converted as well.
|
||||||
|
|
||||||
|
obj: {
|
||||||
|
num: 5
|
||||||
|
func: =>
|
||||||
|
this.result: if false
|
||||||
|
10
|
||||||
|
else
|
||||||
|
"a"
|
||||||
|
"b"
|
||||||
|
this.num
|
||||||
|
}
|
||||||
|
|
||||||
|
print(obj.num is obj.func())
|
||||||
|
print(obj.num is obj.result)
|
||||||
Reference in New Issue
Block a user