Skip to content

Commit

Permalink
Closes #9 - Lambdas
Browse files Browse the repository at this point in the history
  • Loading branch information
wlad031 committed Dec 8, 2021
1 parent aa8e63e commit b62fe6b
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 5 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,23 @@ Outputs:

#### Calling
```
(greeing "John")
(greeting "John")
```

#### Conditions
```
(if (> 1 0) (println true) (println false))
```

#### Lambda (anonymous functions)
```
(def (foo f a b) (f a b))
(foo (lambda (x y) (+ x y)) 10 20)
(foo (lambda (x y) (* x y)) 10 20)
(foo (lambda (x y) (/ y x)) 10 20)
```

### Features

- [x] optimization for tail-recursive functions (for very simple ones, as, for example, `iter` from the example above)
Expand Down
5 changes: 5 additions & 0 deletions examples/lambda.lz
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
(def (foo f a b) (f a b))

(foo (lambda (x y) (+ x y)) 10 20)
(foo (lambda (x y) (* x y)) 10 20)
(foo (lambda (x y) (/ y x)) 10 20)
1 change: 1 addition & 0 deletions src/main/scala/dev/vgerasimov/lizp/ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ case class NativeFunc(name: Sym, func: List[Expr] => List[Expr]) extends Expr
case class Func(name: Sym, params: List[FuncParam], body: List[Expr]) extends Expr
case class Const(name: Sym, expression: Expr) extends Expr
case class Redef(ref: Sym, expression: Expr) extends Expr
case class Lambda(params: List[FuncParam], body: List[Expr]) extends Expr

case class If(condition: Expr, thenExpression: Expr, elseExpression: Expr) extends Expr

Expand Down
7 changes: 6 additions & 1 deletion src/main/scala/dev/vgerasimov/lizp/interpreter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def eval(scopes: Scopes, expressions: List[Expr]): Either[LizpError, List[Expr]]
expressions
.map({
case literal: Literal => literal.asRight
case lambda: Lambda => lambda.asRight
case LList(expressions) => eval(localScope :: scopes, expressions).map(LList(_))
case definition: Definition =>
definition match
Expand Down Expand Up @@ -119,7 +120,11 @@ def eval(scopes: Scopes, expressions: List[Expr]): Either[LizpError, List[Expr]]
.flatMap(evaluatedArgs => {
val paramScope: mutable.Map[Sym, Definition] = mutable.Map()
(params zip evaluatedArgs)
.foreach({ case (param, arg) => paramScope.put(param.name, Const(param.name, arg)) })
.foreach({
case (param, Lambda(lambdaParams, lambdaBody)) =>
paramScope.put(param.name, Func(param.name, lambdaParams, lambdaBody))
case (param, arg) => paramScope.put(param.name, Const(param.name, arg))
})
eval(paramScope :: newScopes, body).map(_.last)
})
})
Expand Down
22 changes: 19 additions & 3 deletions src/main/scala/dev/vgerasimov/lizp/native.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ private[lizp] object native:
import ExecutionError.*

lazy val all: List[Definition] = List(
nth,
nil,
list,
head,
tail,
greaterOrEqual,
lessOrEqual,
greater,
Expand All @@ -23,6 +26,14 @@ private[lizp] object native:
printlnFunc
)

private def in1out1(name: String, func: PartialFunction[Expr, Expr]) = NativeFunc(
name,
ls => {
val arg = ls(0)
if (func.isDefinedAt(arg)) List(func(arg)) else throw new WrongArgumentTypes(Nil, Nil) // FIXME: error args
}
)

private def in2out1(name: String, func: PartialFunction[(Expr, Expr), Expr]) = NativeFunc(
name,
ls => {
Expand All @@ -31,8 +42,13 @@ private[lizp] object native:
}
)

val nil = Const("nil", LList(Nil))

// format: off
val nth = in2out1("nth", { case (LNum(n), LList(ls)) => ls(n.toInt) })
val head = in1out1("head", { case LList(ls) => ls.head })
val tail = in1out1("tail", { case LList(ls) => LList(ls.tail) })
val list = NativeFunc("list", ls => List(LList(ls)))

val greaterOrEqual = in2out1(">=", { case (LNum(a), LNum(b)) => LBool(a >= b) })
val lessOrEqual = in2out1("<=", { case (LNum(a), LNum(b)) => LBool(a <= b) })
val greater = in2out1(">", { case (LNum(a), LNum(b)) => LBool(a > b) })
Expand All @@ -50,7 +66,7 @@ private[lizp] object native:
ls =>
List({
def f(a: Any): LUnit.type =
print(a)
println(a)
LUnit
ls(0) match
case LNull => f("null")
Expand Down
7 changes: 7 additions & 0 deletions src/main/scala/dev/vgerasimov/lizp/parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import dev.vgerasimov.slowparse.Parsers.*
import dev.vgerasimov.slowparse.Parsers.given

import dev.vgerasimov.lizp.syntax.*
import scala.util.Random

def parse(string: String): Either[ParsingError, List[Expr]] = Parser.apply(string)

Expand All @@ -24,6 +25,12 @@ private def expand(expression: Expr): Either[LizpError, Expr] =
.mapLeft(LizpError.Multi(_))
case LList(Sym("val") :: (name: Sym) :: body :: Nil) =>
expand(body).map(Const(name, _))
case LList(Sym("lambda") :: LList(params) :: body) =>
body
.map(expand)
.partitionToEither
.map(Lambda(params.map(_.asInstanceOf[Sym]).map(FuncParam(_)), _))
.mapLeft(LizpError.Multi(_))
case LList(Sym("if") :: condition :: thenExpression :: elseExpression :: Nil) =>
for {
cond <- expand(condition)
Expand Down
13 changes: 13 additions & 0 deletions std/std.lz
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(def (nth ls n)
(def (iter i x xs)
(println i)
(if (= i n) x (iter (+ i 1) (head xs) (tail xs))))
(iter 0 (head ls) (tail ls)))

(nth (list 1 2 3 4 5 6) 0)
(nth (list 1 2 3 4 5 6) 1)
(nth (list 1 2 3 4 5 6) 2)
(nth (list 1 2 3 4 5 6) 3)
(nth (list 1 2 3 4 5 6) 4)
(nth (list 1 2 3 4 5 6) 5)
(nth (list 1 2 3 4 5 6) 6)

0 comments on commit b62fe6b

Please sign in to comment.