Skip to content

Commit

Permalink
Treat !/not expressions as a method call on receiver
Browse files Browse the repository at this point in the history
  • Loading branch information
adambeynon committed Dec 6, 2013
1 parent 71bc4a6 commit 71c0f56
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 20 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Expand Up @@ -23,7 +23,9 @@
* Add `time.rb` to stdlib and moved `Time.parse()` and `Time.iso8601()`
methods there.

* Fix bug to allow `!` as def name.
* `!` is now treated as a unary method call on the object. Opal now parsed
`!` as a def method name, and implements the method on `BasicObject`,
`NilClass` and `Boolean`.

* Moved `native.rb` to stdlib. Native support must now be explicitly required
into Opal. `Native` is also now a module, instead of a top level class.
Expand Down
12 changes: 6 additions & 6 deletions lib/opal/parser/grammar.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions lib/opal/parser/grammar.y
Expand Up @@ -182,11 +182,11 @@ rule
}
| kNOT expr
{
result = new_not(val[0], val[1])
result = new_unary_call(['!', []], val[1])
}
| tBANG command_call
{
result = new_not(val[0], val[1])
result = new_unary_call(val[0], val[1])
}
| arg

Expand Down Expand Up @@ -529,7 +529,7 @@ rule
}
| arg tNEQ arg
{
result = new_not(val[1], new_binary_call(
result = new_unary_call(['!', []], new_binary_call(
val[0], ['==', []], val[2]))
}
| arg tMATCH arg
Expand All @@ -543,7 +543,7 @@ rule
}
| tBANG arg
{
result = new_not(val[0], val[1])
result = new_unary_call(val[0], val[1])
}
| tTILDE arg
{
Expand Down Expand Up @@ -772,11 +772,11 @@ rule
}
| kNOT tLPAREN2 expr tRPAREN
{
result = new_not(val[0], val[2])
result = new_unary_call(['!', []], val[2])
}
| kNOT tLPAREN2 tRPAREN
{
result = new_not(val[0], nil)
result = new_unary_call(['!', []], new_nil(val[0]))
}
| operation brace_block
{
Expand Down
4 changes: 4 additions & 0 deletions opal/corelib/basic_object.rb
Expand Up @@ -30,6 +30,10 @@ def __send__(symbol, *args, &block)
}
end

def !
false
end

alias eql? ==
alias equal? ==

Expand Down
4 changes: 4 additions & 0 deletions opal/corelib/boolean.rb
Expand Up @@ -5,6 +5,10 @@ class << self
undef_method :new
end

def !
`self != true`
end

def &(other)
`(self == true) ? (other !== false && other !== nil) : false`
end
Expand Down
4 changes: 4 additions & 0 deletions opal/corelib/nil_class.rb
@@ -1,4 +1,8 @@
class NilClass
def !
true
end

def &(other)
false
end
Expand Down
14 changes: 7 additions & 7 deletions spec/cli/parser/not_spec.rb
@@ -1,22 +1,22 @@
require File.expand_path('../../spec_helper', __FILE__)

describe "The not keyword" do
it "returns s(:not) with the single argument" do
parsed("not self").should == [:not, [:self]]
parsed("not 42").should == [:not, [:int, 42]]
it "returns a call sexp" do
parsed("not self").should == [:call, [:self], '!'.to_sym, [:arglist]]
parsed("not 42").should == [:call, [:int, 42], '!'.to_sym, [:arglist]]
end
end

describe "The '!' expression" do
it "returns s(:not) with the single argument" do
parsed("!self").should == [:not, [:self]]
parsed("!42").should == [:not, [:int, 42]]
it "returns a call sexp" do
parsed("!self").should == [:call, [:self], '!'.to_sym, [:arglist]]
parsed("!42").should == [:call, [:int, 42], '!'.to_sym, [:arglist]]
end
end

describe "The '!=' expression" do
it "rewrites as !(lhs == rhs)" do
parsed("1 != 2").should == [:not, [:call, [:int, 1], :==, [:arglist, [:int, 2]]]]
parsed("1 != 2").should == [:call, [:call, [:int, 1], :==, [:arglist, [:int, 2]]], '!'.to_sym, [:arglist]]
end
end

Expand Down
6 changes: 6 additions & 0 deletions spec/opal/filters/bugs/language.rb
Expand Up @@ -149,6 +149,12 @@

fails "The defined? keyword for a scoped constant returns nil when an undefined constant is scoped to a defined constant"
fails "The defined? keyword for a top-level scoped constant returns nil when an undefined constant is scoped to a defined constant"
fails "The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset instance variable"
fails "The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset global variable"
fails "The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset instance variable"
fails "The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset global variable"
fails "The defined? keyword for an expression with logical connectives returns nil for an expression with 'not' and an unset class variable"
fails "The defined? keyword for an expression with logical connectives returns nil for an expression with '!' and an unset class variable"

fails "An ensure block inside a begin block is executed even when a symbol is thrown in it's corresponding begin block"
fails "An ensure block inside a method is executed even when a symbol is thrown in the method"
Expand Down

0 comments on commit 71c0f56

Please sign in to comment.