Packages

The Phi Programming Language

Current section

Files

Jump to
phi test phi_parser_test.exs
Raw

test/phi_parser_test.exs

defmodule PhiParserTest do
use ExUnit.Case
test "Parser constructs an AST from layouted tokens" do
source = """
module Main where
foo = 1
bar = 2
"""
{:ok, tokens} = Phi.Lexer.lex(source)
resolved_tokens = Phi.Layout.resolve(tokens)
# Run Parser
{:ok, ast} = Phi.Parser.parse(resolved_tokens)
assert ast.name == "Main"
assert length(ast.declarations) == 2
# Verify order and content
[foo_decl, bar_decl] = ast.declarations
assert foo_decl.name == "foo"
assert foo_decl.expr == %Phi.AST.ExprVar{name: "num_1"}
assert bar_decl.name == "bar"
assert bar_decl.expr == %Phi.AST.ExprVar{name: "num_2"}
end
test "Parser constructs AST for Data Declarations" do
source = """
module Test where
data Maybe a = Nothing | Just a
data Result = Ok | Err
"""
{:ok, tokens} = Phi.Lexer.lex(source)
resolved = Phi.Layout.resolve(tokens)
{:ok, ast} = Phi.Parser.parse(resolved)
assert length(ast.declarations) == 2
[maybe_decl, result_decl] = ast.declarations
assert maybe_decl.name == "Maybe"
assert length(maybe_decl.args) == 1
assert ["a"] = maybe_decl.args
assert length(maybe_decl.constructors) == 2
assert {"Nothing", []} = Enum.at(maybe_decl.constructors, 0)
assert {"Just", [%Phi.AST.TypeVar{name: "a"}]} = Enum.at(maybe_decl.constructors, 1)
assert result_decl.name == "Result"
assert length(result_decl.args) == 0
assert length(result_decl.constructors) == 2
end
test "Parser constructs AST for Classes and Instances" do
source = """
module Main where
class Eq a where
eq :: a -> a -> Bool
instance Eq Int where
eq = false
"""
{:ok, tokens} = Phi.Lexer.lex(source)
resolved = Phi.Layout.resolve(tokens)
{:ok, ast} = Phi.Parser.parse(resolved)
assert length(ast.declarations) >= 2
class_decl = Enum.find(ast.declarations, &match?(%Phi.AST.DeclClass{}, &1))
inst_decl = Enum.find(ast.declarations, &match?(%Phi.AST.DeclInstance{}, &1))
assert %Phi.AST.DeclClass{name: "Eq"} = class_decl
assert length(class_decl.args) == 1
assert [%Phi.AST.TypeVar{name: "a"}] = class_decl.args
assert length(class_decl.members) == 1
[member_sig] = class_decl.members
assert %Phi.AST.DeclTypeSignature{name: "eq"} = member_sig
assert %Phi.AST.TypeArrow{} = member_sig.type
assert %Phi.AST.DeclInstance{class: "Eq"} = inst_decl
assert length(inst_decl.types) == 1
assert [%Phi.AST.TypeConstructor{name: "Int"}] = inst_decl.types
assert length(inst_decl.members) == 1
end
end