Skip to content

Instantly share code, notes, and snippets.

@yuri4n
Created May 25, 2022 16:46
Show Gist options
  • Save yuri4n/bf2d908371d4f1d7106d06659312480b to your computer and use it in GitHub Desktop.
Save yuri4n/bf2d908371d4f1d7106d06659312480b to your computer and use it in GitHub Desktop.
/** This is basically The Lambda Calculus itself. This also forms our AST.
*/
enum Expr:
case Application(lhs: Expr, rhs: Expr)
case Function(param: Token.Identifier, body: Expr)
case Atom(identifier: Token.Identifier)
/** Characters that make our syntax, e.g. (λx.x λx.x) λy.y
*/
enum Token:
case Lambda
case Dot
case LParenthesis, RParenthesis
case Identifier(value: String)
case WhiteSpace
// 1: Added after syntax sugar was explained.
case Keyword(value: Token.Kwd)
case Equal
// end 1.
object Token:
type Kwd = "def"
def create(token: Char | String): Either[Throwable, Token] = token match
case '\\' | `lambdaSymbol` => Right(Lambda)
case '.' => Right(Dot)
case '(' => Right(LParenthesis)
case ')' => Right(RParenthesis)
case ' ' => Right(Token.WhiteSpace)
// 1: Added after syntax sugar was explained.
case '=' => Right(Token.Equal)
case keyword: Kwd => Right(Token.Keyword(keyword))
// end 1.
case name: String if "[a-z]\\w*".r.matches(name) =>
Right(Token.Identifier(name))
case ut => Left(new Throwable(s"[Unexpected Token] $ut"))
extension (s: Char | String) def toToken: Either[Throwable, Token] = Token.create(s)
// From here we would like to extend our tokens to include definitions as part of our language.
def lexer(expr: String): Either[Throwable, Seq[Token]] =
@tailrec def recursiveLexer(
exprRes: String,
res: Either[Throwable, Seq[Token]]
): Either[Throwable, Seq[Token]] = if exprRes.isBlank then res
else
val head = exprRes.head
val seq: Char | String =
if head.isLower && head != lambdaSymbol then exprRes.takeWhile(c => c.isLetterOrDigit || c == '_')
else head
val dropN = seq match
case _: Char => 1
case s: String => s.length
seq.toToken match
case Right(token) =>
recursiveLexer(exprRes.drop(dropN), res.map(r => r :+ token))
case _ => recursiveLexer(exprRes.drop(dropN), res)
recursiveLexer(expr, Right(Seq.empty))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment