Skip to content

Commit

Permalink
Merge pull request #802 from goby-lang/tadpole_to_match
Browse files Browse the repository at this point in the history
Tadpole operator to `String#match?`
  • Loading branch information
st0012 committed Mar 2, 2020
2 parents 7ec45dd + 73fad60 commit 5f0d187
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 71 deletions.
3 changes: 0 additions & 3 deletions compiler/lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ func (l *Lexer) NextToken() token.Token {
if l.peekChar() == '=' {
l.readChar()
tok = token.CreateOperator("==", l.line)
} else if l.peekChar() == '~' {
l.readChar()
tok = token.CreateOperator("=~", l.line)
} else {
tok = token.CreateOperator("=", l.line)
}
Expand Down
27 changes: 11 additions & 16 deletions compiler/lexer/lexer_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package lexer

import (
"github.com/goby-lang/goby/compiler/token"
"testing"

"github.com/goby-lang/goby/compiler/token"
)

func TestNextToken(t *testing.T) {
Expand Down Expand Up @@ -283,7 +284,6 @@ func TestNextToken(t *testing.T) {
},
}, {
`
'a' =~ 'a';
10 <= 10;
10 >= 10;
a = 1 <=> 2;
Expand All @@ -293,27 +293,22 @@ func TestNextToken(t *testing.T) {
expectedLiteral string
expectedLine int
}{
{token.String, "a", 1},
{token.Match, "=~", 1},
{token.String, "a", 1},
{token.Int, "10", 1},
{token.LTE, "<=", 1},
{token.Int, "10", 1},
{token.Semicolon, ";", 1},

{token.Int, "10", 2},
{token.LTE, "<=", 2},
{token.GTE, ">=", 2},
{token.Int, "10", 2},
{token.Semicolon, ";", 2},

{token.Int, "10", 3},
{token.GTE, ">=", 3},
{token.Int, "10", 3},
{token.Ident, "a", 3},
{token.Assign, "=", 3},
{token.Int, "1", 3},
{token.COMP, "<=>", 3},
{token.Int, "2", 3},
{token.Semicolon, ";", 3},

{token.Ident, "a", 4},
{token.Assign, "=", 4},
{token.Int, "1", 4},
{token.COMP, "<=>", 4},
{token.Int, "2", 4},
{token.Semicolon, ";", 4},
},
}, {
`
Expand Down
1 change: 0 additions & 1 deletion compiler/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ func New(l *lexer.Lexer) *Parser {
p.registerInfix(token.Pow, p.parseInfixExpression)
p.registerInfix(token.Eq, p.parseInfixExpression)
p.registerInfix(token.NotEq, p.parseInfixExpression)
p.registerInfix(token.Match, p.parseInfixExpression)
p.registerInfix(token.LT, p.parseInfixExpression)
p.registerInfix(token.LTE, p.parseInfixExpression)
p.registerInfix(token.GT, p.parseInfixExpression)
Expand Down
1 change: 0 additions & 1 deletion compiler/parser/precedence/precedence.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const (
var LookupTable = map[token.Type]int{
token.Eq: Equals,
token.NotEq: Equals,
token.Match: Compare,
token.LT: Compare,
token.LTE: Compare,
token.GT: Compare,
Expand Down
12 changes: 5 additions & 7 deletions compiler/token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,11 @@ const (
OrEq = "||="
Modulo = "%"

Match = "=~"
LT = "<"
LTE = "<="
GT = ">"
GTE = ">="
COMP = "<=>"
LT = "<"
LTE = "<="
GT = ">"
GTE = ">="
COMP = "<=>"

Comma = ","
Semicolon = ";"
Expand Down Expand Up @@ -124,7 +123,6 @@ var operators = map[string]Type{
"||=": OrEq,
"%": Modulo,

"=~": Match,
"<": LT,
"<=": LTE,
">": GT,
Expand Down
1 change: 0 additions & 1 deletion compiler/token/token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ func TestCreateOperatorIdentTrue(t *testing.T) {
"||=": OrEq,
"%": Modulo,

"=~": Match,
"<": LT,
"<=": LTE,
">": GT,
Expand Down
2 changes: 0 additions & 2 deletions native/ripper/ripper.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,6 @@ func convertLex(t token.Type) string {
s = "lt"
case token.LTE:
s = "lte"
case token.Match:
s = "match"
case token.Minus:
s = "minus"
case token.MinusEq:
Expand Down
68 changes: 34 additions & 34 deletions vm/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,40 +197,6 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{

},
},
{
// Matches the receiver with a Regexp, and returns the number of matched strings.
//
// ```ruby
// "pizza" =~ Regex.new("zz") # => 2
// "pizza" =~ Regex.new("OH!") # => nil
// ```
//
// @param regexp [Regexp]
// @return [Integer]
Name: "=~",
Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
if len(args) != 1 {
return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
}

re, ok := args[0].(*RegexpObject)
if !ok {
return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.RegexpClass, args[0].Class().Name)
}

text := receiver.(*StringObject).value

match, _ := re.regexp.FindStringMatch(text)
if match == nil {
return NULL
}

position := match.Groups()[0].Captures[0].Index

return t.vm.InitIntegerObject(position)

},
},
{
// Returns a Integer.
// Returns -1 if the first string is less than the second string returns -1, returns 0 if equal to, or returns 1 if greater than.
Expand Down Expand Up @@ -1008,6 +974,40 @@ var builtinStringInstanceMethods = []*BuiltinMethodObject{

},
},
{
// Matches the receiver with a Regexp, and returns the number of matched strings.
//
// ```ruby
// "pizza".match? Regex.new("zz") # => 2
// "pizza".match? Regex.new("OH!") # => nil
// ```
//
// @param regexp [Regexp]
// @return [Integer]
Name: "match?",
Fn: func(receiver Object, sourceLine int, t *Thread, args []Object, blockFrame *normalCallFrame) Object {
if len(args) != 1 {
return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgument, 1, len(args))
}

re, ok := args[0].(*RegexpObject)
if !ok {
return t.vm.InitErrorObject(errors.TypeError, sourceLine, errors.WrongArgumentTypeFormat, classes.RegexpClass, args[0].Class().Name)
}

text := receiver.(*StringObject).value

match, _ := re.regexp.FindStringMatch(text)
if match == nil {
return NULL
}

position := match.Groups()[0].Captures[0].Index

return t.vm.InitIntegerObject(position)

},
},
{
// Returns a copy of str with the all occurrences of pattern substituted for the second argument.
// The pattern is typically a String or Regexp; if given as a String, any
Expand Down
12 changes: 6 additions & 6 deletions vm/string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,13 @@ func TestStringComparisonFail(t *testing.T) {
}
}

func TestStringMatchOperator(t *testing.T) {
func TestMatchMethod(t *testing.T) {
tests := []struct {
input string
expected interface{}
}{
{`"abc" =~ Regexp.new("bc")`, 1},
{`"abc" =~ Regexp.new("d")`, nil},
{`"abc".match? Regexp.new("bc")`, 1},
{`"abc".match? Regexp.new("d")`, nil},
}

for i, tt := range tests {
Expand All @@ -170,10 +170,10 @@ func TestStringMatchOperator(t *testing.T) {
}
}

func TestStringMatchOperatorFail(t *testing.T) {
func TestMatchMethodFail(t *testing.T) {
testsFail := []errorTestCase{
{`"abc" =~ *[1, 2]`, "ArgumentError: Expect 1 argument(s). got: 2", 1},
{`"abc" =~ 'a'`, "TypeError: Expect argument to be Regexp. got: String", 1},
{`"abc".match?(*[1, 2])`, "ArgumentError: Expect 1 argument(s). got: 2", 1},
{`"abc".match?('a')`, "TypeError: Expect argument to be Regexp. got: String", 1},
}
for i, tt := range testsFail {
v := initTestVM()
Expand Down

0 comments on commit 5f0d187

Please sign in to comment.