Skip to content

Commit

Permalink
Add support to parse function declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
melvic-ybanez committed Sep 17, 2022
1 parent 7d6e735 commit a675db7
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 17 deletions.
4 changes: 4 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ align.tokens = [
{
code = "<-"
owners = [{ regex = "Enumerator.Generator" }]
},
{
code = "->",
owners = [{ regex = "Term.Apply" }]
}
]

Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/com/melvic/dry/ast/Decl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ object Decl {

final case class StmtDecl(stmt: Stmt) extends Decl

final case class Def(name: Token, params: List[Token], body: List[Decl]) extends Decl

object StmtDecl {
def fromExpr(expr: Expr): StmtDecl =
StmtDecl(ExprStmt(expr))
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/com/melvic/dry/interpreter/Interpreter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ object Interpreter {
})(env)
}

recurse(declarations, LocalEnv(env.table, globals), Value.Unit)
recurse(declarations, LocalEnv(env.table, natives), Value.Unit)
}

def globals: Env = Env.empty
def natives: Env = Env.empty
.define("print", Callable(1, { case arg :: _ => print(Value.show(arg)).unit }))
// we don't support user-defined functions yet, so we are building a dedicated function for println for now.
// Once, user-defined functions are supported, we can just replace this with a call to `print`, applied
Expand Down
39 changes: 31 additions & 8 deletions src/main/scala/com/melvic/dry/parsers/DeclParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ package com.melvic.dry.parsers
import com.melvic.dry.Token
import com.melvic.dry.Token.TokenType
import com.melvic.dry.ast.Decl
import com.melvic.dry.ast.Decl.{Let, LetDecl, LetInit, StmtDecl}
import com.melvic.dry.ast.Decl._
import com.melvic.dry.parsers.Step._

import scala.util.chaining.scalaUtilChainingOps

private[parsers] trait DeclParser extends StmtParser { _: Parser =>
def declaration: ParseResult[Decl] =
(matchAny(TokenType.Let) match {
case None => statement.mapValue(StmtDecl(_))
case Some(parser) => parser.letDecl
}).pipe {
case result @ ParseResult(Left(_), _) => result.mapParser(_.synchronize)
case result => result
}
matchAny(TokenType.Def)
.map(_.defDecl)
.orElse(matchAny(TokenType.Let).map(_.letDecl))
.getOrElse(statement.mapValue(StmtDecl(_)))
.pipe {
case result @ ParseResult(Left(_), _) => result.mapParser(_.synchronize)
case result => result
}

def letDecl: ParseResult[Let] = {
def consumeSemicolon(parser: Parser): ParseResult[Token] =
Expand All @@ -31,4 +33,25 @@ private[parsers] trait DeclParser extends StmtParser { _: Parser =>
}
}
}

def defDecl: ParseResult[Def] =
for {
name <- consume(TokenType.Identifier, "identifier", "def keyword")
leftParen <- name.consume(TokenType.LeftParen, "(", "function name")
params <-
if (!leftParen.check(TokenType.RightParen)) {
def recurse(params: List[Token], parser: Parser): ParseResult[List[Token]] =
parser
.matchAny(TokenType.Comma)
.fold(ParseResult.succeed(params.reverse, parser))(
_.consume(TokenType.Identifier, "parameter name", ",").mapValue(_ :: params)
)

leftParen.consume(TokenType.Identifier, "parameter name", "(").flatMap { case Step(param, parser) =>
recurse(param :: Nil, parser).flatMapParser(_.consume(TokenType.RightParen, ")", "parameters"))
}
} else leftParen.consume(TokenType.RightParen, ")", "(").mapValue(_ :: Nil)
leftBrace <- params.consume(TokenType.LeftBrace, "{", "function signature")
body <- leftBrace.block
} yield Step(Def(name.value, params.value, body.value.declarations), body.next)
}
14 changes: 7 additions & 7 deletions src/main/scala/com/melvic/dry/parsers/StmtParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ private[parsers] trait StmtParser { _: Parser with DeclParser =>
select(
expressionStatement,
TokenType.LeftBrace -> { _.block },
TokenType.If -> { _.ifStatement },
TokenType.While -> { _.whileStatement },
TokenType.For -> { _.forStatement }
TokenType.If -> { _.ifStatement },
TokenType.While -> { _.whileStatement },
TokenType.For -> { _.forStatement }
)

def expressionStatement: ParseResult[Stmt] =
Expand All @@ -41,10 +41,10 @@ private[parsers] trait StmtParser { _: Parser with DeclParser =>

def ifStatement: ParseResult[Stmt] =
for {
step <- consume(TokenType.LeftParen, "(", "if")
cond <- step.expression
body <- cond.consume(TokenType.RightParen, ")", "if condition")
thenBranch <- body.statement
leftParen <- consume(TokenType.LeftParen, "(", "if")
cond <- leftParen.expression
rightParen <- cond.consume(TokenType.RightParen, ")", "if condition")
thenBranch <- rightParen.statement
ifStmt <- thenBranch
.matchAny(TokenType.Else)
.fold[ParseResult[Stmt]](
Expand Down

0 comments on commit a675db7

Please sign in to comment.