Repository: skx/monkey (go)

Issue:
Implement the range operator
Related to #61, we should port the range operator from the evalfilter `1..10` returns an array of the values 1, 2 .. 9, 10.

Pull request:
62 range
This pull-request closes #62, by adding support for the range operator (`..`), which creates an array containing the consecutive integers specified as the end-points.


Patch:
diff --git a/README.md b/README.md
index ee3d524..c4a32db 100644
--- a/README.md
+++ b/README.md
@@ -75,7 +75,7 @@ The interpreter in _this_ repository has been significantly extended from the st
 * Added support for regular expressions, both literally and via `match`
   * `if ( name ~= /steve/i ) { puts( "Hello Steve\n"); } `
 * Added support for [ternary expressions](#261-ternary-expressions).
-
+* Added support for creating arrays of consecutive integers via the range operator (`1..10`).
 
 ## 1. Installation
 
@@ -212,6 +212,10 @@ With the definition we included that produces this output:
      Array index 2 contains array
      Array index 3 contains another
 
+As a helper you may define an array of consecutive integers via the range operator (`..`):
+
+     let a = 1..10;
+
 
 ### 2.3.2 Hashes
 
diff --git a/data/stdlib.mon b/data/stdlib.mon
index ebe4f73..54bbce9 100644
--- a/data/stdlib.mon
+++ b/data/stdlib.mon
@@ -297,6 +297,7 @@ function array.min() {
 }
 
 assert( "( [1,2,3].min() == 1 )" );
+assert( "( 1..10.min() == 1 )" );
 assert( "( [-1,-2,-3].min() == -3 )" );
 assert( "( [].min() == 0 )", "minimum of an empty array is zero" );
 
@@ -340,6 +341,7 @@ function array.max() {
    return max;
 }
 
+assert( "( 1..15.max() == 15 )" );
 assert( "( [1,2,3].max() == 3 )" );
 assert( "( [-1,-2,-3].max() == -1 )" );
 assert( "( [].max() == 0 )", "maximum of an empty array is zero" );
diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go
index 9b34a44..e114441 100644
--- a/evaluator/evaluator.go
+++ b/evaluator/evaluator.go
@@ -412,6 +412,16 @@ func evalIntegerInfixExpression(operator string, left, right object.Object) obje
 		return nativeBoolToBooleanObject(leftVal == rightVal)
 	case "!=":
 		return nativeBoolToBooleanObject(leftVal != rightVal)
+	case "..":
+		len := int(rightVal-leftVal) + 1
+		array := make([]object.Object, len, len)
+		i := 0
+		for i < len {
+			array[i] = &object.Integer{Value: leftVal}
+			leftVal++
+			i++
+		}
+		return &object.Array{Elements: array}
 	default:
 		return newError("unknown operator: %s %s %s",
 			left.Type(), operator, right.Type())
diff --git a/lexer/lexer.go b/lexer/lexer.go
index 201c513..082c49e 100644
--- a/lexer/lexer.go
+++ b/lexer/lexer.go
@@ -117,7 +117,13 @@ func (l *Lexer) NextToken() token.Token {
 	case rune(','):
 		tok = newToken(token.COMMA, l.ch)
 	case rune('.'):
-		tok = newToken(token.PERIOD, l.ch)
+		if l.peekChar() == rune('.') {
+			ch := l.ch
+			l.readChar()
+			tok = token.Token{Type: token.DOTDOT, Literal: string(ch) + string(l.ch)}
+		} else {
+			tok = newToken(token.PERIOD, l.ch)
+		}
 	case rune('+'):
 		if l.peekChar() == rune('+') {
 			ch := l.ch
diff --git a/parser/parser.go b/parser/parser.go
index 9a69000..a58e427 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -35,13 +35,16 @@ const (
 	MOD          // %
 	PREFIX       // -X or !X
 	CALL         // myFunction(X)
+	DOTDOT       // ..
 	INDEX        // array[index], map[key]
+	HIGHEST
 )
 
 // each token precedence
 var precedences = map[token.Type]int{
 	token.QUESTION:     TERNARY,
 	token.ASSIGN:       ASSIGN,
+	token.DOTDOT:       DOTDOT,
 	token.EQ:           EQUALS,
 	token.NOT_EQ:       EQUALS,
 	token.LT:           LESSGREATER,
@@ -123,8 +126,8 @@ func New(l *lexer.Lexer) *Parser {
 	p.registerPrefix(token.FOR, p.parseForLoopExpression)
 	p.registerPrefix(token.FUNCTION, p.parseFunctionLiteral)
 	p.registerPrefix(token.IDENT, p.parseIdentifier)
-	p.registerPrefix(token.ILLEGAL, p.parsingBroken)
 	p.registerPrefix(token.IF, p.parseIfExpression)
+	p.registerPrefix(token.ILLEGAL, p.parsingBroken)
 	p.registerPrefix(token.INT, p.parseIntegerLiteral)
 	p.registerPrefix(token.LBRACE, p.parseHashLiteral)
 	p.registerPrefix(token.LBRACKET, p.parseArrayLiteral)
@@ -142,6 +145,7 @@ func New(l *lexer.Lexer) *Parser {
 	p.registerInfix(token.ASTERISK, p.parseInfixExpression)
 	p.registerInfix(token.ASTERISK_EQUALS, p.parseAssignExpression)
 	p.registerInfix(token.CONTAINS, p.parseInfixExpression)
+	p.registerInfix(token.DOTDOT, p.parseInfixExpression)
 	p.registerInfix(token.EQ, p.parseInfixExpression)
 	p.registerInfix(token.GT, p.parseInfixExpression)
 	p.registerInfix(token.GT_EQUALS, p.parseInfixExpression)
diff --git a/static.go b/static.go
index 8ec9163..c4aa9fe 100644
--- a/static.go
+++ b/static.go
@@ -37,8 +37,8 @@ var RESOURCES = map[string]EmbeddedResource{
 
 	"data/stdlib.mon": {
 		Filename: "data/stdlib.mon",
-		Contents: "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",
-		Length:   19823,
+		Contents: "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",
+		Length:   19892,
 	},
 }
 
diff --git a/token/token.go b/token/token.go
index 275b0d6..4601e44 100644
--- a/token/token.go
+++ b/token/token.go
@@ -60,6 +60,7 @@ const (
 	RBRACKET        = "]"
 	COLON           = ":"
 	PERIOD          = "."
+	DOTDOT          = ".."
 	CONTAINS        = "~="
 	NOT_CONTAINS    = "!~"
 	QUESTION        = "?"


Test patch:
diff --git a/lexer/lexer_test.go b/lexer/lexer_test.go
index 185b747..d274418 100644
--- a/lexer/lexer_test.go
+++ b/lexer/lexer_test.go
@@ -7,7 +7,7 @@ import (
 )
 
 func TestNextToken1(t *testing.T) {
-	input := "%=+(){},;?|| &&`/bin/ls`++--***="
+	input := "%=+(){},;?|| &&`/bin/ls`++--***=.."
 
 	tests := []struct {
 		expectedType    token.Type
@@ -30,6 +30,7 @@ func TestNextToken1(t *testing.T) {
 		{token.MINUS_MINUS, "--"},
 		{token.POW, "**"},
 		{token.ASTERISK_EQUALS, "*="},
+		{token.DOTDOT, ".."},
 		{token.EOF, ""},
 	}
 	l := New(input)
@@ -626,3 +627,31 @@ a = 3/4;
 		}
 	}
 }
+
+// TestDotDot is designed to ensure we get a ".." not an integer value.
+func TestDotDot(t *testing.T) {
+	input := `a = 1..10;`
+
+	tests := []struct {
+		expectedType    token.Type
+		expectedLiteral string
+	}{
+		{token.IDENT, "a"},
+		{token.ASSIGN, "="},
+		{token.INT, "1"},
+		{token.DOTDOT, ".."},
+		{token.INT, "10"},
+		{token.SEMICOLON, ";"},
+		{token.EOF, ""},
+	}
+	l := New(input)
+	for i, tt := range tests {
+		tok := l.NextToken()
+		if tok.Type != tt.expectedType {
+			t.Fatalf("tests[%d] - tokentype wrong, expected=%q, got=%q", i, tt.expectedType, tok.Type)
+		}
+		if tok.Literal != tt.expectedLiteral {
+			t.Fatalf("tests[%d] - Literal wrong, expected=%q, got=%q", i, tt.expectedLiteral, tok.Literal)
+		}
+	}
+}