Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: CI

on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

jobs:
test:
name: Test (Elixir ${{matrix.elixir}} / OTP ${{matrix.otp}})
runs-on: ubuntu-latest
strategy:
matrix:
# elixir: ['1.16', '1.17', '1.18', '1.19']
# otp: ['26', '27', '28', '29']
elixir: ['1.16']
otp: ['26']
steps:
- uses: actions/checkout@v4

- name: Setup Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: ${{matrix.elixir}}
otp-version: ${{matrix.otp}}

- name: Cache deps
uses: actions/cache@v4
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-mix-

- name: Cache build
uses: actions/cache@v4
with:
path: _build
key: ${{ runner.os }}-build-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-build-

- name: Install dependencies
run: mix deps.get

- name: Compile
run: mix compile

- name: Run mix test
run: mix test

- name: Run compile_stdlib
run: mix compile_stdlib

- name: Run compile_all.exs
run: mix run compile_all.exs

# - name: Run phi.test
# run: mix phi.test
4 changes: 3 additions & 1 deletion compile_all.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
defmodule CompileAll do
def run do
all_files = Path.wildcard("lib/**/*.hm")
lib_files = Path.wildcard("stdlib/**/*.phi")
test_files = Path.wildcard("tests/**/*.phi")
all_files = lib_files ++ test_files
IO.puts "Found #{length(all_files)} files."

File.mkdir_p!("ebin")
Expand Down
6 changes: 3 additions & 3 deletions lib/mix/tasks/compile_stdlib.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ defmodule Mix.Tasks.CompileStdlib do
"""
use Mix.Task

@shortdoc "Compile all Hamler stdlib .hm files in dependency order"
@shortdoc "Compile all Phi stdlib .phi files in dependency order"

def run(_args) do
Mix.Task.run("compile", [])

files = Path.wildcard("lib/**/*.hm") |> Enum.sort()
files = Path.wildcard("stdlib/**/*.phi") |> Enum.sort()
total = length(files)

IO.puts("\n#{IO.ANSI.bright()}=== Phi Stdlib Compilation Report ===#{IO.ANSI.reset()}")
IO.puts("Found #{total} .hm files\n")
IO.puts("Found #{total} .phi files\n")

# Build dependency graph and sort topologically
module_infos = Enum.map(files, &extract_module_info/1)
Expand Down
9 changes: 1 addition & 8 deletions lib/mix/tasks/phi.compile.ex
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,6 @@ defmodule Mix.Tasks.Phi.Compile do
if stdlib_only do
IO.puts("Stdlib written to #{out_dir}/. Done.")
else
keys = Phi.Typechecker.Env.all_keys(stdlib_env)
IO.puts("\nDEBUG: Before multi_pass, stdlib_env has #{length(keys)} keys")
IO.puts("Compiling #{length(files)} user file(s)...")
{_user_env, compiled_mods} = multi_pass(files, stdlib_env, out_dir, 1)
summarise(compiled_mods, out_dir)
Expand All @@ -102,10 +100,7 @@ defmodule Mix.Tasks.Phi.Compile do
# ---------------------------------------------------------------------------

defp load_stdlib(stdlib_files, out_dir) do
env = do_passes(stdlib_files, Phi.Typechecker.Env.new(), out_dir, 1)
keys = Phi.Typechecker.Env.all_keys(env)
IO.puts("DEBUG: load_stdlib returning env with #{length(keys)} keys")
env
do_passes(stdlib_files, Phi.Typechecker.Env.new(), out_dir, 1)
end

defp do_passes(files, env, out_dir, pass, successful_files \\ %{}) do
Expand Down Expand Up @@ -142,8 +137,6 @@ defmodule Mix.Tasks.Phi.Compile do
new_env

successes == 0 ->
IO.puts("Pass #{pass}: stuck with #{length(failures)} failing files")
IO.puts("DEBUG: returning env with #{map_size(new_env.bindings)} keys after being stuck")
new_env

true ->
Expand Down
14 changes: 7 additions & 7 deletions lib/mix/tasks/phi.test.ex
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
defmodule Mix.Tasks.Phi.Test do
@moduledoc """
Compiles the Hamler stdlib (lib/**/*.hm) and then the Hamler test suite
(tests/**/*.hm) using the same multi-pass environment accumulation strategy,
Compiles the Phi stdlib (lib/**/*.phi) and then the Phi test suite
(tests/**/*.phi) using the same multi-pass environment accumulation strategy,
then executes the test main function.

Usage: mix phi.test
"""
use Mix.Task

@shortdoc "Run Hamler native QuickCheck tests"
@shortdoc "Run Phi native QuickCheck tests"

def run(_args) do
Mix.Task.run("compile", [])
Expand All @@ -18,14 +18,14 @@ defmodule Mix.Tasks.Phi.Test do
IO.puts("\n=== Phi Native Test Runner ===\n")

# Step 1: compile stdlib
IO.puts("--- Compiling stdlib (lib/**/*.hm) ---")
lib_files = Path.wildcard("lib/**/*.hm")
IO.puts("--- Compiling stdlib (lib/**/*.phi) ---")
lib_files = Path.wildcard("lib/**/*.phi")
IO.puts("Found #{length(lib_files)} stdlib files.")
stdlib_env = multi_pass_compile(lib_files, Phi.Typechecker.Env.new(), 1, "lib")

# Step 2: compile test suite
IO.puts("\n--- Compiling test suite (tests/**/*.hm) ---")
test_files = Path.wildcard("tests/**/*.hm")
IO.puts("\n--- Compiling test suite (tests/**/*.phi) ---")
test_files = Path.wildcard("tests/**/*.phi")
IO.puts("Found #{length(test_files)} test files.")
_test_env = multi_pass_compile(test_files, stdlib_env, 1, "tests")

Expand Down
20 changes: 20 additions & 0 deletions lib/phi/ast.ex
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ defmodule Phi.AST do
defstruct [:name]
end

defmodule BinderAs do
defstruct [:name, :binder]
end

defmodule BinderAtom do
defstruct [:value]
end

defmodule BinderBinary do
defstruct [:binder]
end

defmodule BinderConstructor do
defstruct [:name, :args]
end
Expand All @@ -146,4 +158,12 @@ defmodule Phi.AST do
defmodule ExprRecordUpdate do
defstruct [:base, :fields] # base is an expression, fields is [{name_string, expr}, ...]
end

defmodule ExprBinary do
defstruct [:value] # for binary values like <<111, 122>> or <<"binary">>
end

defmodule ExprReceive do
defstruct [:clauses, :after_clause]
end
end
Loading