Skip to content
This repository has been archived by the owner on Dec 20, 2018. It is now read-only.

Commit

Permalink
Add 'short arrow(->)' support for function
Browse files Browse the repository at this point in the history
  • Loading branch information
haifenghuang committed Dec 19, 2017
1 parent e50da54 commit adfa986
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 0 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,26 @@ fn sub(x,y=2) {
println(sub(10)) //output : 8
```
You could also create a function using the `short arrow` syntax:
```swift
let x = () -> 5 + 5
println(x()) //result: 10
let y = (x) -> x * 5
println(y(2)) //result: 10
let z = (x,y) -> x * y + 5
println(z(3,4)) //result :17
let add = fn (x, factor) {
x + factor(x)
}
result = add(5, (x) -> x * 2)
println(result) //result : 15
```
Monkey do not support multiple return values, But there are many ways to do it.
Below suggest a way of doing it:
Expand Down
20 changes: 20 additions & 0 deletions README_cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,26 @@ fn sub(x,y=2) {
println(sub(10)) //结果 : 8
```
你还可以使用`短箭头(short arraw)`语法来创建一个匿名函数:
```swift
let x = () -> 5 + 5
println(x()) //结果: 10
let y = (x) -> x * 5
println(y(2)) //结果: 10
let z = (x,y) -> x * y + 5
println(z(3,4)) //结果 :17
let add = fn (x, factor) {
x + factor(x)
}
result = add(5, (x) -> x * 2)
println(result) //结果 : 15
```
Monkey不支持多个返回值, 但有很多方法可以达到目的.
下面是其中的一种实现方式:
Expand Down
3 changes: 3 additions & 0 deletions src/monkey/lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ func (l *Lexer) NextToken() token.Token {
} else if l.peek() == '=' {
tok = token.Token{Type: token.MINUS_A, Literal: string(l.ch) + string(l.peek())}
l.readNext()
} else if l.peek() == '>' {
tok = token.Token{Type: token.THINARROW, Literal: string(l.ch) + string(l.peek())}
l.readNext()
} else {
tok = newToken(token.MINUS, l.ch)
}
Expand Down
50 changes: 50 additions & 0 deletions src/monkey/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const (
LOWEST
PIPE
ASSIGN
THINARROW
CONDOR
CONDAND
EQUALS
Expand Down Expand Up @@ -79,6 +80,7 @@ var precedences = map[token.TokenType]int{
token.LBRACKET: INDEX,
token.INCREMENT: INCREMENT,
token.DECREMENT: INCREMENT,
token.THINARROW: THINARROW,
}

type Parser struct {
Expand Down Expand Up @@ -189,6 +191,7 @@ func New(l *lexer.Lexer, wd string) *Parser {
p.registerInfix(token.INCREMENT, p.parsePostfixExpression)
p.registerInfix(token.DECREMENT, p.parsePostfixExpression)
p.registerInfix(token.PIPE, p.parsePipeExpression)
p.registerInfix(token.THINARROW, p.parseThinArrowFunction)
p.nextToken()
p.nextToken()

Expand Down Expand Up @@ -315,6 +318,13 @@ func (p *Parser) parseGroupedExpression() ast.Expression {
return ret
}

// NOTE: if previous token is toke.LPAREN, and the current
// token is token.RPAREN, that is an empty parentheses(e.g. '() -> 5'),
// we need to return earlier.
if curToken.Type == token.LPAREN && p.curTokenIs(token.RPAREN) {
return nil
}

exp := p.parseExpression(LOWEST)

if p.peekTokenIs(token.COMMA) {
Expand Down Expand Up @@ -1651,6 +1661,46 @@ func (p *Parser) parsePipeExpression(left ast.Expression) ast.Expression {
return expression
}

// EXPRESSION -> EXPRESSION
//(x, y) -> x + y + 5 left expression is *TupleLiteral
//(x) -> x + 5 left expression is *Identifier
//() -> 5 + 5 left expression is nil
func (p *Parser) parseThinArrowFunction(left ast.Expression) ast.Expression {
fn := &ast.FunctionLiteral{Token: p.curToken, Variadic: false}
switch exprType := left.(type) {
case nil:
//no argument.
case *ast.Identifier:
// single argument.
fn.Parameters = append(fn.Parameters, exprType)
case *ast.TupleLiteral:
// a list of arguments(maybe one element tuple, or multiple elements tuple).
for _, v := range exprType.Members {
switch param := v.(type) {
case *ast.Identifier:
fn.Parameters = append(fn.Parameters, param)
default:
msg := fmt.Sprintf("Syntax Error: %v - Arrow function expects a list of identifiers as arguments", p.curToken.Pos)
p.errors = append(p.errors, msg)
return nil
}
}
default:
msg := fmt.Sprintf("Syntax Error: %v - Arrow function expects identifiers as arguments", p.curToken.Pos)
p.errors = append(p.errors, msg)
return nil
}

p.nextToken()
fn.Body = &ast.BlockStatement{
Statements: []ast.Statement{
p.parseExpressionStatement(),
},
}

return fn
}

func (p *Parser) noPrefixParseFnError(t token.TokenType) {
msg := fmt.Sprintf("Syntax Error: %v - no prefix parse functions for '%s' found", p.curToken.Pos, t)
p.errors = append(p.errors, msg)
Expand Down
3 changes: 3 additions & 0 deletions src/monkey/token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const (
DOTDOT // .. (PARTIAL IMPLEMENTED, ONLY SUPPORT INTEGER/SingleString RANGE, AND ONLY USED IN 'FOR X IN A..B {}' )
ELLIPSIS //... Function Variadic parameters
PIPE // |>
THINARROW // ->
FATARROW // =>

INCREMENT // ++
Expand Down Expand Up @@ -228,6 +229,8 @@ func (tt TokenType) String() string {
return "..."
case PIPE:
return "|>"
case THINARROW:
return "->"
case FATARROW:
return "=>"
case INCREMENT:
Expand Down

0 comments on commit adfa986

Please sign in to comment.