Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
b62e1ec
initial commit
Sibiri4ok Oct 1, 2025
3168f60
add names to pairing
Sibiri4ok Oct 1, 2025
7fa7459
update name directory
Sibiri4ok Oct 1, 2025
f164327
Add: ast, parser & inferencer
Sibiri4ok Oct 6, 2025
39319da
Upd: add vicitory as maintainer
Sibiri4ok Oct 6, 2025
5624cdc
Fix: some fix
Sibiri4ok Oct 6, 2025
6994f28
add Anf
Sibiri4ok Oct 12, 2025
080534e
fix ocamlformat
Sibiri4ok Nov 17, 2025
2d89e3a
fix ocamlformat
Sibiri4ok Nov 17, 2025
5e8d638
Add anf_pretty_printer
Sibiri4ok Nov 19, 2025
b63ce60
Merge branch 'feature/Sibiri4ok' into master
Sibiri4ok Feb 8, 2026
fde4502
add new constructions in ast
Sibiri4ok Feb 9, 2026
fd7d1a8
Merge pull request #4 from Sibiri4ok/feature/Danil
Sibiri4ok Feb 15, 2026
c3a6f28
update anf
Sibiri4ok Feb 15, 2026
16b3647
fmt in ast, inferencer, parser
vicitori Feb 24, 2026
341eb79
change utils folder name to util
vicitori Feb 24, 2026
6cdfbe4
replace ANFMonad at util
vicitori Feb 24, 2026
1ebc7a4
add arity type and anf_fun_bind
vicitori Feb 24, 2026
afd9c7e
use arity in conversion to ANF
vicitori Feb 24, 2026
62ac16a
add architecture (ISA, regs, instr)
vicitori Feb 24, 2026
6a81f7f
add config with runtime primitives
vicitori Feb 24, 2026
714b619
add generator state monad
vicitori Feb 24, 2026
fb2d679
add function_layout, analysis before generation
vicitori Feb 24, 2026
e721796
add auxillary
vicitori Feb 24, 2026
d298d24
add code generator
vicitori Feb 24, 2026
1d7452a
code generator entry point
vicitori Feb 24, 2026
69b3042
add ppx_deriving.eq
vicitori Feb 25, 2026
ba2391a
update tests for arity and anf_fun_bind
vicitori Feb 25, 2026
ab59721
add riscv backend tests
vicitori Feb 25, 2026
d83a985
rewrite gen_via_apply_nargs and fix bug with inf recursion
vicitori Feb 25, 2026
e41cd59
Добавил runtime
Sibiri4ok Feb 28, 2026
3c23700
update riscv
vicitori Mar 7, 2026
edf24c4
feat entry point
vicitori Mar 7, 2026
e2e5cb3
add ll/cc
vicitori Mar 7, 2026
5be629b
add runner for midleend
vicitori Mar 7, 2026
f72520c
add gc & some tests
Sibiri4ok Mar 7, 2026
42ee384
fix fails
Sibiri4ok Mar 7, 2026
46e7405
add tuples
Sibiri4ok Mar 7, 2026
d08b2e7
fix tests + dune fmt
vicitori Mar 8, 2026
220ce5d
add llvm
vicitori Mar 8, 2026
a972fc1
delete dead code
vicitori Mar 8, 2026
83d6d9d
refactor riscv, cc, ll
vicitori Mar 8, 2026
8db8aaf
add llvm runtime
vicitori Mar 8, 2026
d45a788
rename llvm to llvm_ir
vicitori Mar 8, 2026
9dbe84a
add backend choosing at entry point
vicitori Mar 8, 2026
01c60bd
fix errors
vicitori Mar 8, 2026
e76974b
update test expectes
vicitori Mar 8, 2026
cfc10b8
add tests
vicitori Mar 8, 2026
bcd8c17
upd
Sibiri4ok Mar 8, 2026
9d2ff29
add more tests & some refactor
Sibiri4ok Mar 8, 2026
c9f3c53
add typecheck with levels
Sibiri4ok Mar 8, 2026
c630d05
fix 011test
Sibiri4ok Mar 8, 2026
4875fdf
refactor
Sibiri4ok Mar 8, 2026
34c6625
add tests ll & cc
Sibiri4ok Mar 8, 2026
5ceb247
add some tests
Sibiri4ok Mar 8, 2026
b3fdcc8
add some infer tests
Sibiri4ok Mar 8, 2026
fd3b9e6
add infer tests 2
Sibiri4ok Mar 9, 2026
f15711c
ref
Sibiri4ok Mar 9, 2026
c7e9978
fix zanuda
Sibiri4ok Mar 9, 2026
2283c64
fmt project
Sibiri4ok Mar 9, 2026
b661f76
Merge branch 'Kakadu:master' into master
vicitori Mar 9, 2026
4e08f7e
fix manytests
vicitori Mar 9, 2026
4ee3591
add more llvm tests
vicitori Mar 9, 2026
dbfc18b
replce inferencer to midleend
vicitori Mar 9, 2026
ec2e2ac
merge two runtimes
vicitori Mar 9, 2026
8b305c3
ref
vicitori Mar 9, 2026
2f48f9a
add name mangling
vicitori Mar 9, 2026
3ad2185
run llvm tests
vicitori Mar 9, 2026
55a8833
add clang installing
vicitori Mar 9, 2026
8082250
fix
vicitori Mar 9, 2026
058965d
fix llvm call
vicitori Mar 10, 2026
d72b5e9
fix llvm test
vicitori Mar 10, 2026
3e8f7c5
install clang at EML.opam
vicitori Mar 10, 2026
91fd1d9
add rva23
vicitori Mar 11, 2026
31cca41
add all extensions
vicitori Mar 11, 2026
28f4c3d
fix bug at resolver
vicitori Mar 11, 2026
5c00aed
add another solution
vicitori Mar 11, 2026
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
3 changes: 3 additions & 0 deletions EML/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/_build
/_coverage

3 changes: 3 additions & 0 deletions EML/.ocamlformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
version=0.27.0
profile=janestreet

36 changes: 36 additions & 0 deletions EML/EML.opam
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
opam-version: "2.0"
synopsis: "A short LLVM demo"
maintainer: ["Victoria Ostrovskaya & Danil Usoltsev"]
authors: ["Victoria Ostrovskaya & Danil Usoltsev"]
license: "LGPL-3.0-or-later WITH OCaml-LGPL-linking-exception"
homepage: "https://github.com/Kakadu/comp24"
bug-reports: "https://github.com/Kakadu/comp24/issues"
depends: [
"ocaml"
"dune" {>= "3.8" & = "3.19.1"}
"angstrom" {= "0.16.0"}
"qcheck"
"bisect_ppx"
"ppx_expect"
"llvm" {= "18-shared"}
"qcheck" {with-tests}
"odoc" {with-doc}
]
build: [
["dune" "subst"] {dev}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/Kakadu/comp24.git"
depexts: [
[ "llvm-18-dev" "clang" "gcc-riscv64-linux-gnu" "qemu-user" ] {os-distribution = "ubuntu"}
]
7 changes: 7 additions & 0 deletions EML/EML.opam.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
depexts: [
[ "llvm-18-dev" "clang-18" "gcc-riscv64-linux-gnu" "g++-riscv64-linux-gnu" "qemu-user"] {os-distribution = "ubuntu"}
]
pin-depends: [
["ppx_deriving_qcheck.0.6" "git+https://github.com/c-cube/qcheck.git#42429bf06ba12373cad02b1404f50d0ad6238af5"]
]
# Don't edit '*.opam' file manually. Use 'dune b @install'
20 changes: 20 additions & 0 deletions EML/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.PHONY: all test
all:
dune build

test:
dune test

TEST_COV_D = /tmp/cov
COVERAGE_OPTS = --coverage-path $(TEST_COV_D) --expect bin/

.PHONY: test_coverage coverage
test_coverage: coverage
coverage:
$(RM) -r $(TEST_COV_D)
mkdir -p $(TEST_COV_D)
BISECT_FILE=$(TEST_COV_D)/language dune runtest --no-print-directory \
--instrument-with bisect_ppx --force
bisect-ppx-report html $(COVERAGE_OPTS)
bisect-ppx-report summary $(COVERAGE_OPTS)
@echo "Use 'xdg-open _coverage/index.html' to see coverage report"
159 changes: 159 additions & 0 deletions EML/bin/EML.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
(** Copyright 2025-2026, Victoria Ostrovskaya & Danil Usoltsev *)

(** SPDX-License-Identifier: LGPL-3.0-or-later *)

open Stdio
open EML_lib
open Middleend

type backend =
| Ricsv
| Llvm

type opts =
{ input_file : string option
; output_file : string option
; enable_gc : bool
; backend : backend
; infer_only : bool
}

let default_opts =
{ input_file = None
; output_file = None
; enable_gc = false
; backend = Ricsv
; infer_only = false
}
;;

type env = Inferencer.TypeEnv.t

let report_parse_error oc s =
Out_channel.output_string oc (Format.asprintf "Parsing error: %s\n" s)
;;

let report_infer_error oc e =
Out_channel.output_string
oc
(Format.asprintf "Inferencer error: %a\n" Inferencer.pp_error e)
;;

let with_frontend text oc f_success : (env, unit) Result.t =
match Frontend.Runner.run text with
| Error (Frontend.Runner.Parse s) ->
report_parse_error oc s;
Error ()
| Ok ast -> f_success ast
;;

let with_middleend ast env f : (env, unit) Result.t =
match Middleend.Runner.run ast env with
| Error e_mid ->
Format.eprintf "Middleend error: %a\n%!" Middleend.Runner.pp_error e_mid;
Error ()
| Ok (anf_ast, env') -> f anf_ast env'
;;

let run_compile text env oc ~backend ~enable_gc : (env, unit) Result.t =
with_frontend text oc (fun ast ->
with_middleend ast env (fun anf_ast env' ->
let ppf = Format.formatter_of_out_channel oc in
let res =
match backend with
| Ricsv -> Backend.Ricsv.Runner.gen_program ~enable_gc ppf anf_ast
| Llvm -> Backend.Llvm_ir.Runner.gen_program ~enable_gc ppf anf_ast
in
match res with
| Ok () -> Ok env'
| Error msg ->
Format.eprintf "Codegen error: %s\n%!" msg;
Error ()))
;;

let run_infer_only text env oc : (env, unit) Result.t =
match Frontend.Parser.parse text with
| Error s ->
report_parse_error oc s;
Error ()
| Ok ast ->
(match Inferencer.ResultMonad.run (Inferencer.infer_structure env ast) with
| Error e ->
report_infer_error oc e;
Error ()
| Ok (_subst, env') ->
let filtered_env =
Base.Map.filter_keys env' ~f:(fun key -> not (Base.Map.mem env key))
in
Base.Map.iteri filtered_env ~f:(fun ~key ~data ->
match data with
| Inferencer.Scheme.Scheme (_, ty) ->
Out_channel.output_string
oc
(Format.asprintf "val %s: %a\n" key Frontend.Ast.pp_ty ty));
Ok env')
;;

let compiler opts : (unit, unit) Result.t =
let run text env oc =
if opts.infer_only
then run_infer_only text env oc
else run_compile text env oc ~backend:opts.backend ~enable_gc:opts.enable_gc
in
let env0 =
if opts.enable_gc
then Middleend.Inferencer.TypeEnv.env_with_gc
else Middleend.Inferencer.TypeEnv.initial_env
in
let with_output f =
match opts.output_file with
| Some path -> Out_channel.with_file path ~f
| None -> f Out_channel.stdout
in
let input =
match opts.input_file with
| Some path -> In_channel.read_all path |> String.trim
| None -> In_channel.input_all stdin |> String.trim
in
match with_output (fun oc -> run input env0 oc) with
| Ok _env -> Ok ()
| Error () -> Error ()
;;

let parse_args () : (opts, unit) Result.t =
let parse_backend = function
| "llvm" -> Ok Llvm
| "ricsv" -> Ok Ricsv
| _ -> Error ()
in
let rec loop current_opts = function
| [] -> Ok current_opts
| "-gc" :: rest -> loop { current_opts with enable_gc = true } rest
| "-infer" :: rest -> loop { current_opts with infer_only = true } rest
| "-fromfile" :: path :: rest ->
loop { current_opts with input_file = Some path } rest
| "-o" :: path :: rest -> loop { current_opts with output_file = Some path } rest
| "-backend" :: backend_name :: rest ->
(match parse_backend backend_name with
| Ok backend -> loop { current_opts with backend } rest
| Error () -> Error ())
| argument :: _ when String.length argument > 0 && Char.equal argument.[0] '-' ->
Error ()
| _positional_argument :: _ -> Error ()
in
let argv = Array.to_list Sys.argv in
match argv with
| [] -> Ok default_opts
| _program_name :: arguments -> loop default_opts arguments
;;

let () =
match parse_args () with
| Error () ->
Format.eprintf "Positional arguments are not supported\n";
exit 1
| Ok opts ->
(match compiler opts with
| Error () -> exit 1
| Ok () -> ())
;;
4 changes: 4 additions & 0 deletions EML/bin/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(executable
(name EML)
(modes byte exe)
(libraries stdio base EML.lib))
18 changes: 18 additions & 0 deletions EML/dune-project
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
(lang dune 3.8)

(name EML)

(generate_opam_files false)

(source
(github Kakadu/comp24))

(authors "Victoria Ostrovskaya & Danil Usoltsev")

(maintainers "Victoria Ostrovskaya & Danil Usoltsev")

(license "LGPL-3.0-or-later WITH OCaml-LGPL-linking-exception")



; See the complete stanza docs at https://dune.readthedocs.io/en/stable/dune-files.html#dune-project
112 changes: 112 additions & 0 deletions EML/lib/backend/llvm_ir/analysis.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
(** Copyright 2025-2026, Victoria Ostrovskaya & Danil Usoltsev *)

(** SPDX-License-Identifier: LGPL-3.0-or-later *)

open Frontend.Ast
open Middleend.Anf
open Runtime.Primitives

type function_layout =
{ func_name : string
; asm_name : string
; params : immediate list
; body : anf_expr
; is_rec : bool
}

type analysis_result =
{ functions : function_layout list
; resolve : int -> string -> (string * int) option
}

let rec params_of_anf = function
| AnfExpr (ComplexLambda (pats, body)) ->
let imms =
List.filter_map
(function
| PatVariable id -> Some (ImmediateVar id)
| _ -> None)
pats
in
let rest, inner = params_of_anf body in
imms @ rest, inner
| other -> [], other
;;

let analyze (program : anf_program) =
let raw =
List.filter_map
(function
| AnfValue (rec_flag, (func_name, arity, body), _) ->
let params, body = params_of_anf body in
Some (func_name, arity, params, body, rec_flag = Rec)
| AnfEval _ -> None)
program
in
let mangle_reserved name =
if is_reserved name
then "eml_" ^ name
else if String.equal name "_start"
then "eml_start"
else name
in
let functions, _ =
List.fold_left
(fun (reversed_functions, counts) (func_name, _arity, params, body, is_rec) ->
let base_asm_name = mangle_reserved func_name in
let duplicate_index =
Base.Map.find counts func_name |> Option.value ~default:0
in
let updated_counts =
Base.Map.set counts ~key:func_name ~data:(duplicate_index + 1)
in
let asm_name =
if duplicate_index = 0
then base_asm_name
else base_asm_name ^ "_" ^ Int.to_string duplicate_index
in
( { func_name; asm_name; params; body; is_rec } :: reversed_functions
, updated_counts ))
([], Base.Map.empty (module Base.String))
raw
in
let functions = List.rev functions in
let has_main =
List.exists (fun func_layout -> String.equal func_layout.func_name "main") functions
in
let functions =
if has_main
then functions
else (
let synthetic_main =
{ func_name = "main"
; asm_name = "main"
; params = []
; body = AnfExpr (ComplexImmediate (ImmediateConst (ConstInt 0)))
; is_rec = false
}
in
functions @ [ synthetic_main ])
in
let resolver func_index var_name =
let rec find i =
if i < 0
then None
else (
match Base.List.nth functions i with
| None -> None
| Some func_layout when String.equal func_layout.func_name var_name ->
Some (func_layout.asm_name, List.length func_layout.params)
| Some _ -> find (i - 1))
in
let start_index =
match Base.List.nth functions func_index with
| Some func_layout
when func_layout.is_rec && String.equal func_layout.func_name var_name ->
func_index
| _ -> func_index - 1
in
find start_index
in
{ functions; resolve = resolver }
;;
20 changes: 20 additions & 0 deletions EML/lib/backend/llvm_ir/analysis.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(** Copyright 2025-2026, Victoria Ostrovskaya & Danil Usoltsev *)

(** SPDX-License-Identifier: LGPL-3.0-or-later *)

open Middleend.Anf

type function_layout =
{ func_name : string
; asm_name : string
; params : immediate list
; body : anf_expr
; is_rec : bool
}

type analysis_result =
{ functions : function_layout list
; resolve : int -> string -> (string * int) option
}

val analyze : anf_program -> analysis_result
Loading
Loading